vue 开发的技巧
1.require.context()
reqire.context() 其实是 webpack 的方法,vue-cli 是基于 webpack 的,而且基本上 vue 项目都是基于 webpack 进行工程化了的,所以是可以用这个 API 方法的;
require.context(directory, useSubdirectories, regExp);
参数:directory: 说明需要检索的目录;
useSubdirectories:是否检索子目录;
regExp:匹配文件的正则表达式;
使用场景:在我们引入同一个文件夹下的大量文件的时候,可以使用;例如:
import titleCom from '@/components/home/titleCom' import bannerCom from '@/components/home/bannerCom' import cellCom from '@/components/home/cellCom' components:{titleCom,bannerCom,cellCom} 这样文件多的话,是很繁琐的,可以使用: const path = require('path') const files = require.context('@/components/home', false, /\.vue$/) const modules = {} files.keys().forEach(key => { const name = path.basename(key, '.vue') modules[name] = files(key).default || files(key) }) components:modules
2.watch
watch 我们可以进行数据的监听,来实现数据改变之后我们就直接出发监听的方法,其实有一个类似的方式也是可以实现的,比如我们绑定了 v-model 之后,这时候再添加 on-change 事件,这个场景我们一般用在表单元素上,但是并不是只有点击了表单元素才会触发 on-chang 事件,只要 v-model 的值改变了,就会触发 on-change
watch 的一般使用场景,例如:表格初始进来需要调查询接口 getList(),然后input 改变会重新查询
created(){ this.getList() }, watch: { inpVal(){ this.getList() } } 这里我们其实也可以利用 watch 的immediate和handler属性简写: watch: { inpVal:{ handler: 'getList', immediate: true } } inpVal 的值只要改变,就触发 handler 行为,对应的行为名字是 getList;这里 watch 不仅存在 immediate 属性,其实还存在 deep 深度监听的属性
3.组件之间的通信
1)、props
props 其实说白了就是父组件向子组件进行传值,传值的时候可以设置默认值,而且一般不允许我们在子组件中去修改传递的值;但是我们在开发的时候其实发现如果我们传递对象或者数组的时候修改了是没事的,这是什么原因呢? 其实,vue 之所以不允许我们修改传递的 props 值是因为我们在渲染完组件之后,vue 的 diff 算法再计算再次渲染时候的差异的时候会根据一个唯一表示去对比,如果我们修改了这个表示就会出现错乱,那么我们 props 传递的如果是个对象或者数组的话,对象的值是通过指针指向的地址就行存值得,我们修改了值,只是修改了地址中的值,但是我们的指针并没有发生改变,因此 diff 算法所依赖的标识并没有发生改变,也就不会有警告了;
此外需要注意的是如果默认值设置的是 数组或者对象的话,需要用函数进行返回值的形式进行设置
2)、$emit
$emit 是子组件向父组件传值的一个方式,一般通过 $emit('event', argument) 的形式上传;
3)、vuex
状态管理器,适合数据共享比较多的项目中使用,就是多个组件都共享一些相同的数据;
4)、attrs && listeners
attrs 的使用场景:如果是父组件传递给子组件值得时候,传递的比较多,但是我们又比较懒,不想在 props 中进行设置接收,这时候我们就可以通过 $attrs 获取到父组件上定义了,但是在子组件没有接收的值;
listeners 的使用场景:一般情况下,我们在父组件上通过 v-on 绑定了一个事件,然后我们想要触发这个事件,就只能通过 $emit('事件的名字') 进行调用,但是自从有了 $listeners 这个 api 方法之后,我们在子组件中也可以通过 $listeners 来捕捉到父组件中通过 v-on 绑定的事件了;
attrs 和 listeners 都是 vue2.4.0 版本新增的 API 方法,相应的还有 inheriAttrs 属性,inheritAttrs 的默认值为 true,意思是将父组件中除了 props 之外的属性添加到子组件的根节点上,但是即使设置为了 true,仍然可以通过 $attrs 获取到 props 之外的属性,将 inheritArrts 设置为 false,属性就不会显示在根节点上了;
5)、provide && inject
provide && inject 是 vue2.2.0 提供的方法,在开发中不建议使用,因为 provide 的注入主要是类似在祖先组件中,定义一个变量,然后在后代组件中注入,然后去使用,这个其实并不是很方便,而且值一般情况是不响应的,如果传入的是引用类型的话,还是可以达到响应的效果,但是只能在祖先组件中使用,所以一般这样的情况基本都使用 vuex 或者浏览器的缓存来处理;
6)、parent && children
$parent 在子组件中可以拿到一级父组件的属性和方法;
$children 在父组件中可以拿到一级子组件的属性和方法;
7)、$refs
$refs 在组件内,可以访问到当前dom;结合组件的传值,这个方法可以拿到子组件的实例,响应的也就是可以直接操作子组件的 data 和 methods;
8)、$root
$root 可以获取根实例,也就是 我们定义的 id='app' 的组件实例;通过 $root.$children[o] 获取到根实例的一级子组件;通过 $root.$children[0].$children[0] 获取到根实例的二级子组件;
9)、.sync
10)、v-slot
插槽在最初的版本中就是存在的,在 2.6.0 的版本中又做了更新,像 slot、slot-cope,scope 还并未被遗弃,slot 的作用就是将父组件的 template 传入到子组件,简单的说就是组件的封装调用
插槽分为:匿名插槽,含有名字的插槽,作用域插槽;
作用域插槽是可以进行传值的,通过 :key 进行传值,然后通过 v-slot:todo='slotProps' 获取;
11)、EventBus
EventBud 的作用类似于 vuex,可以实现平级、嵌套组件之间的传值,但是对应的时间名字必须一致,而且是全局唯一的,原理就是通过 on 和 emit 实例化了一个全局的 vue,进而实现了数据的共享;
// 在 main.js Vue.prototype.$eventBus=new Vue() // 传值组件 this.$eventBus.$emit('eventTarget','这是eventTarget传过来的值') // 接收组件 this.$eventBus.$on("eventTarget",v=>{ console.log('eventTarget',v);//这是eventTarget传过来的值 })
12)、broadcast && dispatch
这两个方法是,事件的广播和派发,是 vue1.x 的方法,但是在 vue2.x 的时候已经删除了
13)、Vue.observable
这个方法是 2.6.0 版本中新增的,相当于 VueX 的作用,也可以说是一个简化版的 vuex ;在 react 有新推出 hooks 来避免函数组件中无法获取 react 的 state 等问题,vue.observable 的作用可以说跟其基本上是一样的,例如:
import Vue from 'vue' export const store = Vue.observable({ count: 0 }) export const mutations = { setCount (count) { store.count = count } } //使用 <template> <div> <label for="bookNum">数 量</label> <button @click="setCount(count+1)">+</button> <span>{{count}}</span> <button @click="setCount(count-1)">-</button> </div> </template> <script> import { store, mutations } from '../store/store' // Vue2.6新增API Observable export default { name: 'Add', computed: { count () { return store.count } }, methods: { setCount: mutations.setCount } } </script>
4、异步组件
在一些比较大的项目中,项目过大的话,导致加载过慢的现象,所以异步组建的实现按需加载就是很必要的了;
1、异步注册组件的 3 种方法:
// 工厂函数执行 resolve 回调 Vue.component('async-webpack-example', function (resolve) { // 这个特殊的 `require` 语法将会告诉 webpack // 自动将你的构建代码切割成多个包, 这些包 // 会通过 Ajax 请求加载 require(['./my-async-component'], resolve) }) // 工厂函数返回 Promise Vue.component( 'async-webpack-example', // 这个 `import` 函数会返回一个 `Promise` 对象。 () => import('./my-async-component') ) // 工厂函数返回一个配置化组件对象 const AsyncComponent = () => ({ // 需要加载的组件 (应该是一个 `Promise` 对象) component: import('./MyComponent.vue'), // 异步组件加载时使用的组件 loading: LoadingComponent, // 加载失败时使用的组件 error: ErrorComponent, // 展示加载时组件的延时时间。默认值是 200 (毫秒) delay: 200, // 如果提供了超时时间且组件加载也超时了, // 则使用加载失败时使用的组件。默认值是:`Infinity` timeout: 3000 })
异步组件的渲染,其实说白了就是要渲染很多次,至少是两次的渲染,渲染的过程就是先把当前组件渲染成一个注释节点,当组件加载成功后,通过 forceRender 执行重新渲染;或者是渲染为注释节点,然后在渲染为 loading 节点,在渲染为请求完成的节点;;如果感觉注释节点理解起来比较抽象的话,可以理解成,开始的时候这些节点其实在加载的时候类似我们的 html 文件,开始只是加载当前需要的 css 和 js,不需要让人看得那部分给了个display: none;
2、路由的按需加载
import() 方法的提出是在 es6 中提出的,import() 方法是动态加载,返回一个 Promise 对象,then 方法的参数是加载到的模块。类似于 Node.js 的 require 方法,主要 import() 方法是异步加载的;
在 webpack 低于2.4 的版本中,是这样用的:
{ path:'/', name:'home', components:resolve=>require(['@/components/home'],resolve) }
在 webpack 大于2.4 的版本中,是这样用的:
{ path:'/', name:'home', components:()=>import('@/components/home') }
6、动态组件
7、递归组件
8、函数式组件
函数组件其实说白了就是没有用到数据的实例化,没有用到生命周期的一个组件;
在一个函数式组件中,如果想要使用 props 的话,可以在 template 上声明 functional 这时候所需要的参数就会通过 context 来传递;context 包括:props、children、slots、slcopedSlots、data、parent、listeners、injections 等属性;例如:
<template functional> <div v-for="(item,index) in props.arr">{{item}}</div> </template>
9、components 和 vue.component
components 是局部注册组件;vue.component 是全局的注册组件
10、vue.extend
11、mixins
mixins 的值是一个数组,主要是将一些重复的 js 逻辑进行混入;例如:
const mixin={ created(){ this.dealTime() }, methods:{ dealTime(){ console.log('这是mixin的dealTime里面的方法'); } } } export default{ mixins:[mixin] }
12、extends
13、Vue.use()
14、install
15、Vue.nextTick
16、Vue.directive