Vue成神之路之全局API

前言

记录平时学到的知识,标题写的大气一点,也算是给自己一点鼓励,希望在技术这条路可以远走越远,路越走越宽~

文中代码地址

PS:如果对你有一点帮助,请顺手给个小星星哦,鼓励我继续写下去~

引入的文件文件说明

vue.js——开发版本:包含完整的警告和调试模式
vue.min.js——生产版本:删除了警告,进行了压缩

1、全局api

全局API并不在构造器里,而是先声明全局变量或者直接在Vue上定义一些新功能,Vue内置了一些全局API。说的简单些就是,在构造器外部用Vue提供给我们的API函数来定义新的功能。

1.1 Vue.directive

除了Vue提供的内部指令,还可以根据Vue提供的全局api来定义一些属于自己的指令。比如定义一个change指令,作用就是让文字颜色变成红色。

demo:




    
    Vue.directive 自定义指令
    


    

Vue.directive 自定义指令


{{num}}

接下来定义一个全局指令change让文字变色,这里使用Vue.directive();来定义全局指令:

//如果在 bind 和 update 时触发相同行为,而不关心其它的钩子,可以简写成这种形式
Vue.directive('change',function(el,binding,vnode, oldVnode){
        el.style='color:'+binding.value;
});

使用声明周期钩子:

Vue.directive("change", {
    bind:function(el, binding) {//被绑定
        console.log('1 - bind')

        el.style="color:"+binding.value
    },
    inserted: function() {//绑定到节点
        console.log('2 - inserted')
    },
    update:function(){//组件更新
        console.log('3 - update');
    },
    componentUpdated:function(){//组件更新完成
        console.log('4 - componentUpdated');
    },
    unbind:function(){//解绑
        console.log('5 - unbind');
    }
})

写完之后可以看到数字已经变成了绿色,说明自定义指令起到了作用。

自定义指令中传递的四个个参数:

  • el: 指令所绑定的元素,可以用来直接操作DOM。

  • binding: 一个对象,包含指令的很多信息。

  • vnode:Vue 编译生成的虚拟节点。

  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

自定义指令的生命周期:

自定义指令有五个生命周期(也叫钩子函数),分别是 bind,inserted,update,componentUpdated,unbind

  1. bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个绑定时执行一次的初始化动作。
  2. inserted:被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于document中)。
  3. update:被绑定于元素所在的模板更新时调用,而无论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新。
  4. componentUpdated:被绑定元素所在模板完成一次更新周期时调用。
  5. unbind:只调用一次,指令与元素解绑时调用。
bind:function(){//被绑定
     console.log('1 - bind');
},
inserted:function(){//绑定到节点
      console.log('2 - inserted');
},
update:function(){//组件更新
      console.log('3 - update');
},
componentUpdated:function(){//组件更新完成
      console.log('4 - componentUpdated');
},
unbind:function(){//解绑
      console.log('5 - unbind');
}
1.2 Vue.extend

Vue.extend 返回的是一个“扩展实例构造器”,也就是预设了部分选项的Vue实例构造器。经常服务于Vue.component用来生成组件,可以简单理解为当在模板中遇到该组件名称作为标签的自定义元素时,会自动调用“扩展实例构造器”来生产组件实例,并挂载到自定义元素上。

Vue 的构造函数可接收的大部分选项都能在 Vue.extend() 中使用,不过也有两个特例:data 和 el。由于每个 Vue 的实例都应该有自己的 $data$el,我们显然不希望传递给 Vue.extend() 的值被所有通过这个构造函数创建的实例所共享。因此如果要定义组件初始化默认数据和元素的方式,应该传入一个函数:

搭配Vue.component使用:

// 扩展 Vue 得到一个可复用的构造函数
var MyComponent = Vue.extend({
  template: '

{{title}} a custom component!

', data: function () { return { title: 'Hello!' } } })

接下来,就可以用 Vue.component() 来注册这个构造函数:

// 注册组件,传入扩展构造器
Vue.component('my-component', MyComponent)

扩展实例demo:

//Vue.extend 返回的是一个“扩展实例构造器”,也就是一个预设了部分选项的 Vue 实例构造器
var authorExtend = Vue.extend({
    template: "

{{authorName}}

", data: function() { return { authorName: 'zaishuiyixia', authorUrl: 'https://www.jianshu.com/u/6d5f3f6492f8' } } });

想要展示在页面上,还需要把扩展实例挂载到元素上。

new authorExtend().$mount('#author');

还可以通过HTML标签或者标签的class来生成扩展实例构造器,Vue.extend里的代码是一样的,只是在挂载的时候,我们用类似jquery的选择器的方法,来进行挂载就可以了。

new authorExtend().$mount('.extend');

完整代码:




    
    Vue.extend 扩展实例构造器
    


    

Vue.extend 扩展实例构造器


1.3 Vue.set

当一个 Vue 实例被创建时,它向 Vue 的响应式系统中加入了其 data 对象中能找到的所有的属性。当这些属性的值发生改变时,视图将会产生“响应”,即匹配更新为新的值。

// 我们的数据对象
var data = { a: 1 }

// 该对象被加入到一个 Vue 实例中
var vm = new Vue({
  data: data
})

// 获得这个实例上的属性
// 返回源数据中对应的字段
vm.a == data.a // => true

// 设置属性也会影响到原始数据
vm.a = 2
data.a // => 2

// ……反之亦然
data.a = 3
vm.a // => 3

当这些数据改变时,视图会进行重渲染。值得注意的是只有当实例被创建时 data 中存在的属性才是响应式的。也就是说如果你添加一个新的属性,比如:

vm.b = 'hi'

那么对 b 的改动将不会触发任何视图的更新。

如果我就是希望新添加的属性也是响应式的,应该怎么办呢?

Vue.set就是来解决这个问题的。

Vue.set 的作用就是向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且触发视图更新。它主要用于向响应式对象上添加新属性,因为 Vue 无法探测普通的新增属性 。也可以通过Vue.set在构造器外部操作构造器内部的数据、属性或者方法。

什么是外部数据,就是不在Vue构造器里里的data处声明,而是在构造器外部声明,然后在data处引用就可以了。外部数据的加入让程序更加灵活,我们可以在外部获取任何想要的数据形式,然后让data引用:

//在构造器外部声明数据
 var outData={
    count:1,
    goodName:'zaishuiyixia'
};
var app=new Vue({
    el:'#app',
    //引用外部数据
    data:outData
})

在外部改变数据的三种方法:

1、用Vue.set改变

function add(){
       Vue.set(outData,'count',4);
 }

2、用Vue对象的方法添加

app.count++;

3、直接操作外部数据

outData.count++;

Vue.set存在的意义:

由于Javascript的限制,Vue不能自动检测以下变动的数组。

  1. 当你利用索引直接设置一个项时,vue不会为我们自动更新。
  2. 当你修改数组的长度时,vue不会为我们自动更新。

example:




    
    
    Vue.set 全局api


    

Vue.set 全局api


  • {{aa}}

这时我们的界面是不会自动跟新数组的,我们需要用Vue.set(app.arr,1,’ddd’)来设置改变,vue才会给我们自动更新,这就是Vue.set存在的意义。

另一个代码例子:




    
    
    Vue.set 全局api


    

Vue.set 全局api


  • {{aa}}

{{item.message}}


点击之后试图更新,列表新增了一条数据,通过数组的变异方法( Vue数组变异方法:push()、pop()、shift()、unshift()、splice()、sort()、reverse() )我们可以动态控制数据的增减,但是却无法做到对某一条数据的修改。这时候就也会用到Vue的内置方法Vue.set。

Vue.set( target, key, value ) 响应式新增与修改数据:

  1. target:{Object | Array} 要更改的数据源(可以是对象或者数组)
  2. key:{Object | Array} 要更改的具体数据
  3. value :重新赋的值



    
    
    Vue.set 全局api


    

Vue.set 全局api


  • {{aa}}


{{item.message}}







点击第一个按钮后新增了一条数据,此时点击第二个按钮将Test one更改为Change Test。

可以看到列表中第一列的Test one已经变成了Change Test。

当写惯了JS之后,有可能想改数组中某个下标的中的数据我直接this.items[XX]就改了,如:

btn4Click:function(){
    this.items[0]={message:"Change Test",id:'10'}
}

点击btn4Click按钮时,通过打印出的数据可以看到,虽然数据已经改变了,但是视图没有更新。这是因为由于 JavaScript 的限制,当通过数组下标直接修改数据时,Vue 不能检测出数据的改变,所以当我们需要动态改变数据的时候,可以使用Vue.set()。

btn3Click:function(){
    var itemLen=this.items.length;
    Vue.set(this.items,itemLen,{message:"Test add attr",id:itemLen});
    console.log('btn3Click', this.items)
}

点击btn3Click按钮可以看到视图更新并且新增了一条数据。

Vue.set()不光能修改数据,还能添加数据,弥补了Vue数组变异方法的不足。

Vue.set()在methods中也可以写成this.$set()

1.4 Vue的生命周期

Vue实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、销毁等一系列过程,我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,就是生命周期。

每一个组件或者实例都会经历一个完整的生命周期,可以大致分为三个阶段:初始化、运行中、销毁。

Vue一共有10个生命周期函数,我们可以利用这些函数在vue的每个阶段执行一些操作,例如操作数据或者改变内容。

  1. beforeCreate:实例、组件通过new Vue() 创建出来之后会初始化生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作。

  2. created:接下来初始化数据data,绑定事件(methods里面定义的方法),然后执行created函数,这个时候已经可以使用到数据,也可以更改数据,在这里更改数据不会触发updated函数,在这里可以在渲染前倒数第二次更改数据的机会,不会触发其他的钩子函数,一般可以在这里做(请求数据)初始数据的获取。

  3. beforeMount: 接下来开始找实例或者组件对应的模板,编译模板为虚拟dom放入到render函数中准备渲染,然后执行beforeMount钩子函数,在这个函数中虚拟dom已经创建完成,马上就要渲染,在这里也可以更改数据,不会触发updated,在这里可以在渲染前最后一次更改数据的机会,不会触发其他的钩子函数,在这里做初始数据的更改,也可以做初始数据的获取。

  4. mounted:接下来开始render,渲染出真实dom,然后执行mounted钩子函数,此时,组件已经出现在页面中,数据、真实dom都已经处理好了,事件都已经挂载好了,可以在这里操作真实dom等事情...

  5. beforeUpdate:当组件或实例的数据更改之后,会立即执行beforeUpdate,然后vue的虚拟dom机制会重新构建虚拟dom与上一次的虚拟dom树利用diff算法进行对比之后重新渲染,一般不做什么事儿。

  6. updated:当数据更新完成,重新渲染完成后,执行updated,这是数据已经更改完成,dom也重新render完成,可以操作更新后的真实dom。

  7. activated:搭配keep-alive使用。keep-alive是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止切换回组件后重复渲染DOM。一般搭配路由或者组件使用,作用是路由或组件的内容被加载过一次之后,放到内存之中,下一此再进这个路由或者切换回这个组件的时候就不用重新渲染这个组件了,继而也就不会重新执行钩子函数,也不会有像发送请求再次获取数据这样的操作了,只有当数据变化时,才使用VirtualDOM进行diff更新。它会把以前的内容(数据)从内存里拿出来显示,继而不用从新发请求渲染数据了。包裹动态组件时,会缓组件实例,而不是销毁它们。


    相似, 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。当第一次进入keep-alive 页面的时候,钩子函数的触发顺序是:beforeCreate>created-> mounted-> activated,退出时触发deactivated。当再次进入时,只触发activated。

  8. deactivated:与activated生命周期函数相对应的就是deactivated生命周期函数。它会在组件被替换、页面被隐藏(如跳到其他页面)的时候执行。

  9. beforeDestroy:当经过某种途径调用$destroy方法后,立即执行beforeDestroy,在组件或实例销毁前执行。一般在这里做一些善后工作,例如清除计时器、清除非指令绑定的事件等等...

  10. destroyed:在组件或实例销毁后执行,这时已经解除了组件的数据绑定、指令绑定的事件监听...去掉后只剩下dom空壳,在这里做善后工作也可以。




    
    vue的生命周期
    


    

vue的声明周期


{{ message }}


打开控制台,可以看到刚进入页面的时候会执行beforeCreate、created、beforeMount、mounted这四个生命周期函数:


Vue成神之路之全局API_第1张图片
1.png

可以看到在beforeMount阶段打印出的实例的挂载点是虚拟dom,数据还没有挂载上去;在mounted阶段数据才被挂载上去,这时才可以操作真实的dom。

点击增加内容按钮后可以看到执行了beforeUpdate、和updated这两个声明周期函数:


Vue成神之路之全局API_第2张图片
2.png

最后点击销毁按钮可以看到执行了beforeDestroy和destroyed这两个生命周期函数:


Vue成神之路之全局API_第3张图片
3.png

PS:activated和deactivated生命周期函数将会在之后做专门的讲解。

1.5 template模板标签

一个字符串模板作为 Vue 实例的标识使用。模板将会替换 挂载的元素。挂载元素的内容都将被忽略,除非模板的内容有分发插槽。

这是官网给出的template模板标签的作用描述,感觉不是很详细,写几个例子看看它都能做什么。

把template写在挂载元素外面:




    
    
    Vue模板标签templete


    

Vue模板标签templete


当把template写在挂载点外面的时候,打开浏览器可以看到在浏览器上并没有渲染出任何信息,这是因为template标签内容天生不可见,设置了display:none;属性:


Vue成神之路之全局API_第4张图片
image.png



    
    
    Vue模板标签templete


    

Vue模板标签templete


当把template写在挂载点里面的时候,打开浏览器可以看到在浏览器上渲染出了模板,并且最终的渲染结果并没有包含