全局 API 是什么 举个比较好理解的例子,Vue 就好比一块蛋糕,生命周期钩子函数以及内部指令可以理解为做蛋糕用的面粉、糖、鸡蛋等。而全局 API 就是裹在蛋糕外面的奶油,让整个蛋糕(Vue)看起来更加美味。全局 API 的作用就是给 Vue 以更多的自由,大家可以根据自己项目的需求,通过全局 API 来制作出各种各样的方法工具。
Vue.extend Vue.extend 是什么? 作为全局 API 中的一员,在实际开发中很少会被用到,因为相比我们经常使用的 Vue.component
,Vue.extend
在写法上就会显得比较繁琐。但在一些比较特殊的场景下,Vue.extend
+ $mount
是我们需要去了解的。
自定义纯标签 假设我现在有个需求,在很多地方需要用到我的官网名称,并且这个官网名称还带上 url 地址,可点击跳转到我的官网,在模板中,只需要写一个 <official/>
就能展示。
让我们来看看用 Vue.extend
怎么去实现,新建 demo.html 代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <title > Vue.extend-扩展实例构造器</title > </head > <body > <h1 > Vue.extend-扩展实例构造器</h1 > <official > </official > <script src ="https://cdn.bootcss.com/vue/2.6.10/vue.min.js" > </script > <script type ="text/javascript" > var official = Vue.extend({ template: "<p > <a target ='_blank' :href ='url' > {{name }} </a > </p > ", data: function ( ) { return { name: 'Jungle\'Blog' , url: 'https://blog.csdn.net/weixin_43825727?spm=1011.2124.3001.5343' } } }); new official().$mount('official' ); </script > </body > </html >
全局定义之后,可以在任何地方进行使用,非常便捷
Vue.directive 自定义指令 Vue.directive 是什么 之前也学了 v-model
、v-show
等官方定义的指令,在项目的开发过程中,我们会有一些特殊的需求,要自定义指令,Vue.directive
就是为什么做这件事情的 API。
自定义组件 假如又来了一个需求,需要让加上 v-color 指令的标签的字体颜色通过传入的变量值进行改变,比如 v-color="red"
标签就会变为红色。
代码演示如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > Vue.directive 自定义标签</title > <style > </style > </head > <body > <div id ='app' > <p v-color ="color" > 啦啦啦啦啦</p > </div > </body > <script src ="https://cdn.bootcss.com/vue/2.6.10/vue.min.js" > </script > <script > window .onload = function ( ) { Vue.directive('color' , function (el, binding, vnode ) { console .log('el' , el) console .log('binding' , binding) console .log('vnode' , vnode) el.style = "color:" + binding.value }); new Vue({ el: '#app' , data: { color: 'red' } }) } </script > </html >
回调函数参数 自定义组件的回调函数有三个参数。
el:被绑定的 node 节点。
binding: 包含指令信息的对象参数。
vnode:Vue 编译生成的虚拟节点。
自定义组件的生命周期 自定义组件包含几个生命周期,也就是在调用自定义组件时,几个钩子函数会被触发,分别是如下。
bind:只会调用一次,在第一次绑定到元素上时被调用,初始化操作可以使用它。
inserted:被绑定的元素插入了父节点。
update:被绑定的元素模板更新时调用。
componentUpdated:被绑定的元素模板完成一次生命周期。
unbind:指令和被绑定元素解绑时调用。
Vue.set 全局操作 在解释 Vue.set
之前先了解一下 Vue 的响应式原理:
当你把一个 JS 对象传给 Vue 实例的 data 属性时,Vue 将遍历此对象的所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。Object.defineProperty 是 ES5 中一个无法 shim 的特性,这也就是为什么 Vue 不支持 IE8 以及更低版本的浏览器。
为什么要使用 Vue.set 受限于现代浏览器,Vue 检测不到对象的添加和删除;因为 Vue 在初始化实例时对 data
属性执行 getter/setter
转化操作,所以对象必须在 data
中才能让其响应式。
Vue 不允许在已经创建的实例上动态添加新的根级响应式属性,不过可以使用 Vue.set
方法将响应式属性添加到嵌套的对象上。代码演示如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > Vue.set 全局操作</title > <style > </style > </head > <body > <div id ='app' > <p v-for ="item in fruit" > {{ item }}</p > <button v-on:click ="change" > 变</button > {{ fruit }} </div > <button onclick ="add()" > 外部添加</button > </body > <script src ="https://cdn.bootcss.com/vue/2.6.10/vue.min.js" > </script > <script > function add ( ) { Vue.set(app.fruit, 1 , 'melon' ); console .log(app.fruit) } var app = new Vue({ el: '#app' , data: { fruit: ['apple' , 'banana' , 'pear' , 'grape' ] }, methods: { change: function ( ) { this .fruit[1 ] = 'melon' } } }) </script > </html >
当点击按钮“变”的时候,渲染没有变化,当点击按钮“外部添加”的时候,渲染数据发生了变化。
Vue.filter 全局过滤器是一个在项目中时常会用到的 API,使用场景也非常丰富,比如说数据的统计,保留小数点参数等等,在后续的商场实战中也会被运用到实战中。
实例 下面我们演示一个简单的过滤器,需求是使用过滤器将需要过滤的目标值加上 4,代码演示如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > Vue.filter 过滤器</title > <style > </style > </head > <body > <div id ='app' > <p > {{ count | add5 }}</p > </div > </body > <script src ="https://cdn.bootcss.com/vue/2.6.10/vue.min.js" > </script > <script > Vue.filter("add5" , function (value ) { return value + 5 ; }) var app = new Vue({ el: '#app' , data: { count: 20 }, }) </script > </html >
屏幕上会出现 25 这个数字,注意的是,声明 add5过滤器,必须要放在声明实例 app 之前,否则不会被注入到实例中。
Vue.nextTick nextTick 是一个比较重要的高级特性,应用场景在很多地方会出现。Vue 是异步渲染的框架,一开始就是如此,当你改变 data 属性内部的变量,视图不会立即更新,在此时你若是进行 DOM 操作,是拿不到最新的渲染结果,这个时候你就要借助 Vue.nextTick 高级特性,在该特性的回调函数内获取最新的渲染结果。
实例 1 2 3 this.$nextTick(function () { const html = document.getElementById("aaa").innerHTML })
Mixin 混入
混入(mixin)提供了一个非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包括任意组件选项。当组件使用混入对象时,所有混入对象的选项将被「混合」进入该组件本身的选项。
上面这段摘录自 Vue 的官方文档,文字有点难理解,通过举实例来解释 mixin 的具体用法。 其实我们可以用 Object 的思想去理解 mixin,假设有一个变量 A,它的值为 { a: 1, b: 2 }
,有另一个变量 B,它的值为 { a: 3, c: 4 }
,B 作为混入的对象混入 A,那么 A 中已有的属性 a 不会被覆盖,A 会新增一个 c 属性,最终 A 为 { a: 1, b: 2, c: 4 }
。
实例 通过 Vue 的代码进行分析如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 export default { data () { return { username: '张三' , age: 30 , hasWife: true } }, mounted ( ) { console .log('mixin' ) }, methods: { speak ( ) { console .log('这是mixin' ) }, cry ( ) { console .log('这是cry' ) } } } import mixin from './minix' ;export default { data ( ) { return { username: '李四' , age: 31 , hasHusband: true } }, mounted ( ) { console .log('app' ); }, mixins: [mixin], methods: { speak ( ) { console .log('这是app' ) }, eat ( ) { console .log('吃饭' ) } } } export default { data ( ) { return { name: '李四' , age: 31 , hasHusband: true , hasWife: true , } }, mounted ( ) { console .log('mixin' ) console .log('app' ) }, methods: { speak () { [ function ( ) { console .log('这是mixin' ) }, function ( ) { console .log('这是app' ) } ].forEach(cb => { cb() }) console .log('这是app' ) }, eat ( ) { console .log('吃饭' ) }, cry ( ) { console .log('这是cry' ) } } }
上述为组件中使用 mixins 方法进行「混入」,下面我们来介绍「全局混入」,「混入」可以在入口页进行全局注册,但是使用它时要格外小心,一旦使用全局混入,它将会影响每一个之后创建的 Vue 实例。 官方示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 Vue.mixin({ created: function ( ) { var myOption = this .$options.myOption if (myOption) { console .log(myOption) } } }) new Vue({ myOption: 'hello!' })
Vue 生命周期函数 单页面开发模式,每个页面都可以理解为一个 Vue 组件,每个页面都是一个鲜活的生命,在它的一生中,从出生到消亡都会有对应的钩子函数,下面就让我们认识一下它们。
beforeCreate:在组件创建之前。
created:在组件创建之后,一般用于初始化一些固定的数据。
beforeMount:DOM 节点渲染之前。
mounted:在 DOM 节点渲染完之后被触发,通常笔者都会在这个生命周期中通过 ajax 去获取服务端的数据,如果在 created 生命周期里获取数据并渲染视图,DOM 节点可能还未被渲染,有可能页面会报错,安全起见,数据统一放在 mounted 钩子函数内获取。
beforeUpdate:数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。
updated:当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用 计算属性 或 watcher 取而代之。
activated:被 keep-alive 缓存的组件激活时调用。
deactivated:被 keep-alive 缓存的组件停用时调用。
beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。一般用于销毁页面内创建的 setTimeout
等变量,防止内存泄漏。
实例 Vue 生命周期代码演示如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="UTF-8" > <meta name ="viewport" content ="width=device-width, initial-scale=1.0" > <meta http-equiv ="X-UA-Compatible" content ="ie=edge" > <title > Vue 生命周期</title > <style > [v-cloak] { display : none; } </style > </head > <body > <div id ='app' > <p v-cloak > {{count}}</p > <button @click ="add" > 加+</button > <button onclick ="app.$destroy()" > 销毁</button > </div > </body > <script src ="https://cdn.bootcss.com/vue/2.6.10/vue.min.js" > </script > <script > var app=new Vue({ el:'#app' , data:{ count: 1 }, methods:{ add: function ( ) { this .count ++; } }, beforeCreate:function ( ) { console .log('beforeCreate' ); }, created:function ( ) { console .log('created' ); }, beforeMount:function ( ) { console .log('beforeMount' ); }, mounted:function ( ) { console .log('mounted' ); }, beforeUpdate:function ( ) { console .log('beforeUpdate' ); }, updated:function ( ) { console .log('updated' ); }, activated:function ( ) { console .log('activated' ); }, deactivated:function ( ) { console .log('deactivated' ); }, beforeDestroy:function ( ) { console .log('beforeDestroy' ); }, destroyed:function ( ) { console .log('destroyed' ) } }) </script > </html >
每个生命周期都值得被深入研究
总结 Vue 全局 API 属于 Vue 的高级特性,随着项目复杂度的提升,这些高级特性出现的频率也会随之增高,学习它们也是必不可少的,在学习过程中还需用心体会它们解决问题的场景。