大家好,我是code_shu,以后争取都是原创有价值,尽量不水。下面开始我们的正题。我会聊下我最近在搭建项目时做了哪些点的优化?与原来的模式相比,又能带来哪些方面的效率提升?看完本篇文章,你将能收获以下几点:
- 熟练使用
import
和export
进行前端工程自动化 - 熟练使用
webpack
的require.context
api 进行前端工程自动化 - 前端工程自动化方面有了更好的认识
我们先从普通项目基本操作开始,然后对比优化方案,下面开始我们的正题。
普通项目结构
.
├── src
├── assets --------------------------------------------静态文件
├── api --------------------------------------------接口文件
├── components --------------------------------------------组件文件
├── router --------------------------------------------vue-router 项目路由
├── store --------------------------------------------vuex 项目状态管理
├── directives --------------------------------------------全局指令文件
├── minxins --------------------------------------------混入文件
├── utils --------------------------------------------工具函数文件
├── views --------------------------------------------页面文件
├── App.vue --------------------------------------------vue项目根组件
└── main.js --------------------------------------------项目入口
复制代码
我们在创建一些文件用来演示
.
├── src
├── api
│ ├──user.js --------------------------------------------用户相关接口
│ └──cart.js --------------------------------------------购物车相关接口
├── components
│ ├──Cart.vue -----------------------------------------购物车组件
│ └──Banner.vue ----------------------------------------轮播图组件
├── directives
│ └──index.js ---------------------------------------- 全局指令
├── views
│ └──home.vue ---------------------------------------- 主页
└── utils
├──dom.js --------------------------------------------DOM相关的工具函数
└──array.js ----------------------------------------数组相关的工具函数
复制代码
api/user.js
里写两个演示接口
// 获取用户信息
const getUserInfo = ()=>({})
// 获取用户使用权限是否过期
const getUserExpired = ()=>({})
export {
getUserInfo, // 获取用户信息
getUserExpired // 获取用户使用权限是否过期
}
复制代码
api/cart.js
里写两个演示接口
// 获取购物车商品分类
const getCartProductCategory = ()=>({})
// 获取购物车商品数量
const getCartProductCount = ()=>({})
export {
getCartProductCategory, // 获取购物车商品分类
getCartProductCount // 获取购物车商品数量
}
复制代码
components/Cart.vue
<template>
<div>
<h1>Cart 组件</h1>
</div>
</template>
<script>
export default {
name: 'Cart',
data () {
return {}
}
}
</script>
复制代码
components/Banner.vue
<template>
<div>
<h1>Banner 组件</h1>
</div>
</template>
<script>
export default {
name: 'Banner',
data () {
return {}
}
}
</script>
复制代码
directives/index.js
import Vue from "vue"
const draggable = {
inserted(el, binding,vnode,oldVnode){
//...
},
bind(el, binding,vnode,oldVnode){
//...
},
update(el, binding,vnode,oldVnode){
//...
},
unbind(el, binding,vnode,oldVnode){
//...
},
componentUpdated(el, binding,vnode,oldVnode){
//...
}
}
const fcous = {
inserted(el, binding,vnode,oldVnode){
//...
},
bind(el, binding,vnode,oldVnode){
//...
},
update(el, binding,vnode,oldVnode){
//...
},
unbind(el, binding,vnode,oldVnode){
//...
},
componentUpdated(el, binding,vnode,oldVnode){
//...
}
}
Vue.directive('draggable', draggable)
Vue.directive('fcous', fcous)
</script>
复制代码
然后 在
main.js
里面 直接import '@/directives'
views/home.vue
<template>
<div class="wrapper">
</div>
</template>
<script>
export default {
data() {
return {
}
},
watch: {},
computed: {},
methods: {},
created() {},
mounted() {}
}
</script>
<style lang="scss" scoped></style>
复制代码
utils/dom.js
里写两个演示函数
// 获取DOM元素的样式
const getStyle = ()=>({})
// 获取DOM元素的属性
const getAttr= ()=>({})
export {
getStyle, // 获取DOM元素的样式
getAttr // 获取DOM元素的属性
}
复制代码
API 使用优化
一般用法
Ps:我们默认你项目配置 别名 alias
@
为src
api 的使用
views/home.vue
<template>
<div class="wrapper">
</div>
</template>
<script>
// api 按需使用
import { getUserInfo, getUserExpired } from "@/api/user"
import { getCartProductCategory, getCartProductCount } from "@/api/cart"
export default {
data() {
return {
}
},
watch: {},
computed: {},
methods: {},
created() {},
mounted() {}
}
</script>
<style lang="scss" scoped></style>
复制代码
我们知道如果项目的体量越来越大,团队人员各自创建的 功能api名称 如
user.js
、cart.js
不一定很语义化,可能会 取一个看似语义化而看不懂的 api文件名字 如ResourceLibraryProjectManagement.js
资源库项目管理 的相关 api, 或许有人说,我不怕麻烦,我cv大法很厉害的,就怕复制粘贴错。
我们对api的使用方式 开始进行优化,首先说明优化方向:
- 第一种方案,同样 通过
import
按需导入,达到如下效果
// 只要一个 import 进行按需导入
import {
getUserInfo,
getUserExpired,
getCartProductCategory,
getCartProductCount
} from "@/api"
复制代码
此种优化目的:我们不需要关心 你
api模块名字是什么
,因为每个人取名字风格不一样,唯一关心的写了什么 api接口
仅此而已
我们开始对 api 文件进行优化改造,改造后的api目录结构
如下:
├── api
├── modules --------------------------------------------api模块
│ ├──user.js --------------------------------------------用户相关接口
│ └──cart.js --------------------------------------------购物车相关接口
└──index.js ----------------------------------------------api入口文件
复制代码
api/mudules/user.js
// 获取用户信息
export const getUserInfo = ()=>({})
// 获取用户使用权限是否过期
export const getUserExpired = ()=>({})
// 拒绝重复劳动
//export {
// getUserInfo, // 获取用户信息
// getUserExpired // 获取用户使用权限是否过期
//}
复制代码
api/mudules/cart.js
// 获取购物车商品分类
export const getCartProductCategory = ()=>({})
// 获取购物车商品数量
export const getCartProductCount = ()=>({})
// 拒绝重复劳动
//export {
// getCartProductCategory, // 获取购物车商品分类
// getCartProductCount // 获取购物车商品数量
//}
复制代码
api/index.js
api入口文件
export * from "./modules/user.js"
export * from "./modules/cart.js"
复制代码
- 小伙伴说,第一种方案对我们1000+路由项目来说,维护很难,至少有几百个
import
按需导入接口,代码量多了上去和维护难度也增加了,第二种改造方案继续:
改造后的目录结构依然不变,核心思想是模块化管理和入口文件
├── api
├── modules --------------------------------------------api模块
│ ├──user.js --------------------------------------------用户相关接口
│ └──cart.js --------------------------------------------购物车相关接口
└──index.js ----------------------------------------------api入口文件
复制代码
api/mudules/user.js
// 获取用户信息
export const getUserInfo = ()=>({})
// 获取用户使用权限是否过期
export const getUserExpired = ()=>({})
复制代码
api/mudules/cart.js
// 获取购物车商品分类
export const getCartProductCategory = ()=>({})
// 获取购物车商品数量
export const getCartProductCount = ()=>({})
复制代码
第二种方案与第一种方案唯一不同的就是api入口文件改造
api/index.js
第二种改造方案 的api入口文件
import Vue from 'vue'
// 通过 webpack 的 require.context 获取指定路径下面的js文件,为了可以进一步深度遍历,
// 第二个参数传为true
const files = require.context('./modules', true, /\.js$/)
// 所有api集合对象
const api = files.keys().reduce((modules, path) => {
const apis = Object.keys(files(path)).reduce((r, key) => {
r[key] = files(path)[key]
return r
}, {})
return Object.assign({}, modules, apis)
}, {})
Vue.prototype.$api = api
复制代码
关于 require.context
是什么?
一个webpack
的api
,通过执行require.context
函数获取一个特定的上下文,主要用来实现自动化导入模块,在前端工程中,如果遇到从一个文件夹引入很多模块的情况,可以使用这个api
,它会遍历文件夹中的指定文件,然后自动导入,使得不需要每次显式的调用import
导入模块
具体请看官网:webpack.docschina.org/guides/depe…
然后 在
main.js
里 直接import "@/api"
, 使用方式则是简单了很多,没有了import
,缺点是 没有了按需,因为api集合对象是直接挂载在Vue的原型上了
使用示例:
views/home.vue
<template>
<div class="wrapper"></div>
</template>
<script>
export default {
data() {
return {}
},
mounted() {
console.log(this.$api)
console.log(this.$api.getUserInfo)
console.log(this.$api.getUserExpired)
console.log(this.$api.getCartProductCategory)
console.log(this.$api.getCartProductCount)
}
}
</script>
<style lang="scss" scoped></style>
复制代码
说完 api在项目中的优化后,我们接着来优化我们组件的使用
组件使用优化
请看优化最终效果
views/home.vue
<template>
<div class="wrapper"></div>
</template>
<script>
// 我想这样
import {
Cart,
Banner
} from "@/components"
// 我不想这样
//import Cart from "@/components/Cart.vue"
//import Banner from "@/components/Banner.vue"
export default {
data() {
return {}
},
components:{
Cart,
Banner
}
}
</script>
<style lang="scss" scoped></style>
复制代码
开始我们的改造,组件目录结构如下:
├── api
├── modules --------------------------------------------组件模块
│ ├──Banner ---------------------------------------------轮播图组件
│ │ └──index.vue
│ └──Cart ---------------------------------------------购物车组件
│ └──index.vue
└──index.js ----------------------------------------------组件入口文件
复制代码
之所以这样设计目录结构,是因为考虑到你的组件 可能依赖很多为你这个组件服务的其他组件,增强独立维护性
我们来写我们的组件入口文件
components/index.js
export { default as Banner } from "./modules/Banner"
export { default as Cart } from "./modules/Cart"
复制代码
以上就完成了组件方面的优化了,下面接着优化我们的全局指令
全局指令优化
全局指令优化,核心思想依然是
模块化+ 入口化
思想,即 一个入口文件管理众多模块文件,由 入口文件对外分发,因此更多的精力关注自己模块的编写即可
指令文件目录结构:
├── directives
├── modules -------------------------------------------- 组件模块
│ ├──focus.js ------------------------------------------- 获取焦点指令
│ └──draggable.js ------------------------------------- 拖拽指令
└──index.js ---------------------------------------------- 指令入口文件
复制代码
directives/modules/focus.js
export default {
inserted(el, binding,vnode,oldVnode){
//...
},
bind(el, binding,vnode,oldVnode){
//...
},
update(el, binding,vnode,oldVnode){
//...
},
unbind(el, binding,vnode,oldVnode){
//...
},
componentUpdated(el, binding,vnode,oldVnode){
//...
}
}
复制代码
directives/modules/draggable.js
export default {
inserted(el, binding,vnode,oldVnode){
//...
},
bind(el, binding,vnode,oldVnode){
//...
},
update(el, binding,vnode,oldVnode){
//...
},
unbind(el, binding,vnode,oldVnode){
//...
},
componentUpdated(el, binding,vnode,oldVnode){
//...
}
}
复制代码
directives/index.js
import Vue from 'vue'
const files = require.context('./module', false, /\.js$/)
files.keys().forEach(key => {
const fileName = key.replace(/(\.\/|\.js)/g, '')
Vue.directive(fileName, files(key).default)
})
复制代码
最后 在
main.js
导入 该文件import "@/directives"
views/home.vue
<template>
<div class="wrapper">
<input type="text" v-focus />
</div>
</template>
<script>
export default {
data() {
return {}
}
}
</script>
<style lang="scss" scoped></style>
复制代码
相信有了以上优化思路,你也可以优化你的项目,由于文字不一定描述的很清楚,所以我把相关优化放在这个项目了,项目地址,如果觉得对你有所帮助,请不要吝啬的 你的 star
,其他utils
等都是类似的优化,就不一一道出了。
结语
以上就是我最近在项目搭建和前端工程自动化方面做的一些事,目的是降低相关使用门槛,提升团队效率。
文章若有不准确或错误的地方,欢迎指出,如果你有更好的点子,欢迎留言。