Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!
2013年7月28日,尤雨溪第一次在 GItHub 上为 Vue.js 提交代码;2015年10月26日,Vue.js 1.0.0版本发布;2016年10月1日,Vue.js 2.0发布。
最早的 Vue.js 只做视图层,没有路由, 没有状态管理,也没有官方的构建工具,只有一个库,放到网页里就可以直接用了。
后来,Vue.js 慢慢开始加入了一些官方的辅助工具,比如路由(Router)、状态管理方案(Vuex)和构建工具(Vue-cli)等。此时,Vue.js 的定位是:The Progressive Framework。翻译成中文,就是渐进式框架。
Vue.js2.0 引入了很多特性,比如虚拟 DOM,支持 JSX 和 TypeScript,支持流式服务端渲染,提供了跨平台的能力等。Vue.js 在国内的用户有阿里巴巴、百度、腾讯、新浪、网易、滴滴出行、360、美团等等。
Vue 已是一名前端工程师必备的技能,现在就让我们开始深入学习 Vue.js 内部的核心技术原理吧!
自定义指令
类似于 v-if、v-for 一样,Vue.js 向用户提供了实现自定义指令的功能。你可以通过指令对普通 DOM 元素进行底层操作,比如修改元素的样式、元素的默认效果等。我们先举一个简单的例子,让大家对自定义指令有一个更直观的认识。
<p v-color>Hfun Fly</p>
directives:{
color: {
inserted(el) {
el.style.color = '#f00'
}
}
}
效果如下:
可以看到,我们的指令生效了,“Hfun Fly” 变成了红色。代码中的 insert 是指令执行过程中的一个钩子函数,将在当前指令所绑定的元素插入到父节点时被调用,参数 el 是绑定的元素的 DOM 对象。下面我们进一步看一下自定义指令所经历的各个生命周期钩子。
钩子函数
bind :只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted
:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。update
:所在组件的 VNode 更新时调用,但是可能发生在其子VNode更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。componentUpdated
:指令所在组件的 VNode 及其子 VNode 全部更新后调用。unbind
:只调用一次,指令与元素解绑时调用。
钩子函数参数
每个钩子函数都接受4个参数,分别是 el、binding、vnode 和 oldVnode,下面是官方文档给出的解释。
el
:指令所绑定的元素,可以用来直接操作 DOM。binding
:一个对象,包含以下 property:name
:指令名,不包括v-
前缀。value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为2
。oldValue
:指令绑定的前一个值,仅在update
和componentUpdated
钩子中可用。无论值是否改变都可用。expression
:字符串形式的指令表达式。例如v-my-directive="1 + 1"
中,表达式为"1 + 1"
。arg
:传给指令的参数,可选。例如v-my-directive:foo
中,参数为"foo"
。modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为{ foo: true, bar: true }
。
vnode
:Vue 编译生成的虚拟节点。oldVnode
:上一个虚拟节点,仅在update
和componentUpdated
钩子中可用
可能 binding 钩子函数里面的参数看起来不是很清楚,下面我们用一个例子来加深一下对上面参数的理解。
<p v-color:foo.a.b="test">Hfun Fly</p>
directives:{
color: {
update(el,binding,vnode,oldVnode) {
console.log(binding)
}
}
},
-------------------------------输出-------------------------------
{
"name": "color", // 指令名
"value": "hahaha", // update之后,绑定的变量真实值
"oldValue": "hahaha", // update之前,绑定的变量真实值
"expression": "test", // 绑定的变量名
"arg": "foo", // 绑定的指令的参数
"modifiers": {
"a": true,
"b": true
}, // 绑定的修饰符对象
}
根据传入参数的不同,我们可以将上方里例子改进一下,根据用户传入的参数的不同,动态改变字体样式。改造后代码如下:
<p v-color="'#00ff00'">Hfun Fly</p>
<p v-color="'#0000ff'">Hfun Fly</p>
<p v-color="'#ff0000'">Hfun Fly</p>
directives:{
color: {
inserted(el) {
el.style.color = binding.value
}
}
}
效果如下:
注意:上方代码中 v-color="'#00ff00'" 中绑定的是一个字符串,如果内部没有带引号,默认绑定的是变量,变量我们只需要在 data 中声明即可。
比如我们可以动态绑定指令的参数,举个简单的小例子:
<p v-color[foo]>Hfun Fly</p>
directives:{
color: {
inserted(el,binding) {
console.log(binding.arg) // a
}
}
},
data(){
return{
foo:'a'
}
}
我们可以通过改变 foo 的值,达到动态绑定自定义指令参数的效果。在钩子函数中,通过指令参数可以动态的修改绑定元素的 DOM 元素。
函数简写
在很多时候,你可能想在 bind 和 update 时触发相同行为,而不关心其它的钩子。那么就可以省略钩子函数的步骤了。
<p v-color>Hfun Fly</p>
directives:{
color(el) {
el.style.color = 'red'
}
},
对象字面量
如果指令需要多个值,可以传入一个 JavaScript 对象字面量。
<p v-color="{ color: 'red', text: 'hello' }">Hfun Fly</p>
directives:{
color(el,binding) {
console.log(binding.value.color) // "red"
console.log(binding.value.text) // "hello"
}
},
全局注册和局部注册
对于自定义指令,我们既可以全局注册,也可以局部注册。对于全局注册我们只需要在 main.js 里定义,就可以在所有页面中使用了。全局注册语法如下:
Vue.directive('color', {
inserted: function(el) {
el.style.color = 'red'
}
});
局部注册就像上方例子中的一样,在每一个文件中通过定义,只能在当前文件中使用。局部注册语法如下:
<p v-color>Hfun Fly</p>
directives:{
color(el) {
el.style.color = 'red'
}
},
Vue 进阶系列教程将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!
叶阳辉
HFun 前端攻城狮
往期精彩: