1.Vue.extend(options)
构造器,创建一个 子类 。参数是一个包含组件选项的对象
data 选项是特例,需要注意 在 Vue.extend() 中它必须是一个函数,
<div id="test"></div>
// 创建构造器
let MyTest = Vue.extend({
template: '<p>{{name}} {{age}}</p>',
data(){
return {
name: 'zhangning',
age: '24'
}
}
})
创建 MyTest 实例,并挂载到一个元素上
new MyTest().$mount('#test')
最终结果如下
<p>zhangning 24</p>
上面 extend 创建的是 Vue 构造器,而不是一个具体的组件实例,所以不能够通过 new Vue({components: testExtend}) 来直接使用,需要通过 new MyTest().$mount('#test') 来挂载到指定的元素上
*调用 Vue.extend() 创建的是一个组件构造器
*通常在创建组件构造器时,传入 template 代表我们自定义组件的模板
*该模板就是在使用到组件的地方,要显示的 HTML 代码
*但是,这种写法在vue2之后几乎就不再使用了,都是直接使用语法糖,不过我们还是要学习的,为后面的学习打下基础
现在我们通常不使用 Vue.extend() 来注册组件了,使用语法糖的写法,直接把对象放在 Vue.component() 来注册组件,可以看第 7 个API进行学习
调用Vue.component() 是将刚才的组件构造器注册为一个组件,并且给它起一个组件的标签名字
所以需要传递两个参数:1.注册组件的标签名 2.组件构造器
组件必须挂在在某个Vue实例下,否则不会生效
示例:封装一个全局提示组件
首先创建一个 message.vue 组件
<template>
<transition>
<div v-show='show'>{{message}}</div>
</transition>
</template> <script>
export default{
data(){
return {
show: false,
message: ''
}
}
}
</script> <style scoped>
div {
padding: 10px;
color: #ddd;
background: red;
text-align: center;
position: fixed;
top: 30%;
left: 50%;
}
</style>
然后在 main.js 中配置
import Message from './components/Message.vue' const MessageM = {
install: function(Vue) {
// 创建一个 vue 的子类组件
const MessageConstructor = Vue.extend(Message)
// 创建子类实例,并挂载到动态创建的元素上,并将元素添加到全局结构中
const inst = new MessageConstructor().$mount(document.createElement('div'))
document.body.appendChild(inst.$el)
// 在 vue 原型链上注册方法,控制组件
Vue.prototype.$message = (msg, time = 1000) => {
inst.message = msg
inst.show = true
setTimeout((
inst.show = false
), time)
}
}
}
Vue.use(MessageM)
在组件内使用
this.$message('消息提示')
以上就是一个简单的全局消息提示
2.Vue.nextTick
在写词DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM
<template>
<div>
<div ref='valRef'>{{ val }}</div>
<div>{{ val1 }}</div>
<div>{{ val2 }}</div>
<div>{{ val3 }}</div>
<el-button type="primary" @click.once='handleClick'>改变val</el-button>
</div>
</template> <script>
export default {
name: 'index',
data() {
return {
val: 'zhangning',
val1: '',
val2: '',
val3: ''
}
},
methods: {
// 点击按钮时,val1和val3获取的是初次加载时候的val的值,因为vue的DOM是异步加载,
// 而使用了nextTick的val2的值在msg改变之后,就立刻获取到了val更新之后的值
handleClick() {
this.val = '我已改变';
// DOM 未更新,获取不到最新的dom
this.val1 = this.$refs.valRef.innerHTML;
this.$nextTick(() => {
// DOM 已更新,获取最新的dom
this.val2 = this.$refs.valRef.innerHTML;
})
// DOM 未更新,获取不到最新的dom
this.val3 = this.refs.valRef.innerHTML;
}
}
}
</script>
官方给出的解释和例子(异步更新队列)
Vue 在更新 DOM 时是异步执行的。只要监听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更,如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然而在下一个的事件循环 tick 中,Vue 刷新队列并执行实际(已去重)工作。Vue 在内部对异步队列尝试使用原生的Promise.then、MutationObserver 和 setImmediate,如果执行环境不支持,则会采用 setTimeout(fn, 0) 代替。
例如,当设置 vm.someData = 'newVlaue',该组件不会立即重新渲染,当刷新队列时,组件会在下一个事件循环 tick 中更新。多数情况我们不需要关心这个过程,但是如果想基于更新后的 DOM 状态做点什么,这就有点棘手。虽然Vue鼓励我们使用数据驱动的方式思考,避免直接接触 DOM ,但是有时我们必须要这么做。为了在数据变化之后等待 Vue 完成更新 DOM,可以在数据变化之后立即使用 Vue.nextTick(callback)。这样回调函数将在 DOM 更新完成之后被调用。例如
<div id="example">{{message}}</div>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
在组件内使用 vm.$nextTick() 实例方法特别方便,因为它不需要全局 Vue ,并且回调函数中的 this 将自动绑定到当前的 Vue 实例上
Vue.component('example', {
template: '<span>{{ message }}</span>',
data: function () {
return {
message: '未更新'
}
},
methods: {
updateMessage: function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
this.$nextTick(function () {
console.log(this.$el.textContent) // => '已更新'
})
}
}
})
因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的语法 async/await 完成相同的事情
methods: {
updateMessage: async function () {
this.message = '已更新'
console.log(this.$el.textContent) // => '未更新'
await this.$nextTick()
console.log(this.$el.textContent) // => '已更新'
}
}
3.Vue.set
Vue.set(target, key, value)
target:要更改的数据源(可以是对象或者数组)
key:要更改的具体数据
value:重新赋的值
由于 js 的限制,Vue 不能检测出数据的改变,但是通过这种方法修改数组中的数据,就会检测到数组的改变,是响应式的
用法:向响应式对象中添加一个 property, 并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 arr[1] = 110)
export default {
name: 'index',
data() {
return {
arr: [1,2,3]
}
},
methods: {
// 修改 arr[1] 变为 200
handleChange(){
this.$set(this.arr, 1, 200);// arr: [1, 200, 3]
},
// arr 数组添加元素 600
handleAddArr(){
this.$set(this.arr, this.arr.length, 600);
}
}
}
4.Vue.delete()
Vue.delete(target, key, value)
target:要删除的数据源(可以是对象或者数组)
key:要删除的具体数据
用法:删除对象的 property。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开 Vue 不能检测到 property 被删除的限制,虽然很少使用,但直到要会用
export default {
name: 'index',
data() {
return {
zhangning: {
height: 187,
name: 'zhangning',
sex: '男'
}
}
},
methods: {
// 删除 name
handleDeleteName() {
this.$set(this.zhangning, 'name');
}
}
}
5.Vue.directive()
Vue.directive(string, Function | Object)
注册或获取全局指令
声明周期:
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定被插入文档中)
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生改变,也可能没有,但是你可以通过比较更新前后的值来忽略不必要的模板更新(详细的钩子函数参数见下)
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用
unbind:只调用一次,指令与元素解绑时调用
钩子函数参数
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 钩子中可用
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
Vue.directive('demo', {
bind: function (el, binding, vnode) {
var s = JSON.stringify
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ')
}
}) new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})
页面展示效果如下
name: 'demo'
value: 'hello!'
expression: 'message'
argument: 'foo'
modifiers: {a: true, b: true}
vnode keys: tag,data,children,text,elm,ns,context...
动态指令参数,指令的参数可以是动态的,例如,在 v-mydirective:[argument]='value'中,argument 参数可以根据组件数据进行更新,这可以让我们的自定义指令灵活使用。
创建一个自定义指令,把元素固定在距离顶部 200px 的位置
<div id="test">
<p>Scroll down the page</p>
<p v-pin="200">距离顶部200px</p>
</div>
Vue.directive('pin', {
bind: function(el, binding, vnode){
el.style.position = 'fixed'
el.style.top = binding.value + 'px'
}
}) new Vue({
el: '#test'
})
当我们需要固定在左侧而不是顶部的时候,这时候我们就需要用到动态指令
<div id="test">
<p>Scroll down the page</p>
<p v-pin:[direction]="200">距离顶部200px</p>
</div>
Vue.directive('pin', {
bind: function(el, binding, vnode){
el.style.position = 'fixed'
let s = binding.arg == 'left' ? 'left' : 'top'
el.style[s] = binding.value + 'px'
}
}) new Vue({
el: '#test' ,
data(){
return {
direction: 'left'
}
}
})
以上这个自定义指令现在的灵活性就足以支持一些不同的用例了
函数简写
很多时候,我们想在 bind 和 update 时触发相同行为,而不关心其他的钩子。
Vue.directive('pin', function(el, binding){
el.style.top = binding.value + 'px'
})
如果指令需要多个值,可以传入 js 对象,指令函数能够接收所有合法的 js 表达式
<div v-demo="{ color: 'red', text: 'hello'}"></div>
Vue.directive('demo', function(el, binding){
console.log(binding.value.color) // red
console.log(binding.value.text) // hello
})
在项目中使用的案例
通过权限控制每个页面的按钮,
先定义一个 directive.js,写上全局指令
import Vue from 'vue';
import store from './store'; Vue.directive('permission', {
inserted: (el, binding) => {
if (store.getters.userButtons.length) {
const buttons = store.getters.userButtons;
if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el);
} else {
store.dispatch('getInfo').then(data => {
const { buttons } = data.buttons;
if (buttons.indexOf(binding.value) < 0) el.parentNode.removeChild(el);
});
}
}
});
在 main.js 中全局引入
import './directive.js'
在 vue 组件中使用,判断有没有下载按钮权限
<el-button
round
icon="el-icon-document"
type="primary"
v-permission="'SJML_SQXZ'"
@click="applyForDownload"
>下载文档</el-button>
6.Vue.filter()
定义过滤器,可被用于常见的文本格式化。过滤器可以用在两个地方:双花括号插值和 v-bind 表达式,过滤器应该被添加在 js 表达式的尾部,由管道符号指示:'|'
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
在一个组件的选项中定义本地过滤器
filters: {
capitalize: function (value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
}
}
在创建 Vue 实例之前全局定义过滤器
Vue.filter('capitalize', function() {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
new Vue({
// ...
})
注意:当全局过滤器和局部过滤器重名时,会采用局部过滤器
过滤器函数总接收表达式的值作为第一个参数
过滤器可以串联:
{{ message | filterA | filterB }}
这个例子中,filterA 被定义为接收单个参数的过滤器函数,表达式 message 的值将作为参数传入到函数中。然后继续调用同样被定义为接收单个参数的过滤器函数 filterB,将 filterA 的结果传递给 filterB 中。
过滤器时 js 函数,因此可以接收参数
{{ message | filterA('arg1', arg2) }}
这个例子,filterA 被定义为接收三个参数的过滤器函数,其中 message 的值作为第一个参数,普通字符串 'arg1' 作为第二个参数, arg2 作为第三个参数
在项目中使用的案例
先定义一个 filters.js
export { formatBoolean, formatDate, formatNum, formatStatus }; // 布尔值
function formatBoolean(value) {
return value ? "是" : "否";
} // 状态
function formatStatus(value) {
return value ? "成功" : "失败";
}
// 时间戳转换
function formatDate(value) {
let date = new Date(parseInt(value));
let Y = date.getFullYear();
let M =
date.getMonth() + 1 < 10
? "0" + (date.getMonth() + 1)
: date.getMonth() + 1;
// let D = date.getDate();
let D = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
let h = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
let m = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let s = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return Y + "." + M + "." + D + " " + h + ":" + m + ":" + s;
} // 数值加逗号
function formatNum(num) {
num = (num || 0).toString();
let result = "";
while (num.length > 3) {
result = "," + num.slice(-3) + result;
num = num.slice(0, num.length - 3);
}
if (num) {
result = num + result;
}
return result;
}
然后在 main.js 中进行全局引入
import * as filters from './filters.js'
Object.keys(filters).forEach(item => {
Vue.filter(item, filters[item])
})
// 这里讲一下 Object.keys() 方法,表示给定对象的所有可枚举属性的字符串数组
let zn = {name: 'zhangning', age: '24', height: '187'}
Object.keys(zn);// ['name', 'age', 'height'] 返回可枚举属性组成的数组
// 处理数组,返回索引值数组
let arr = [100, 200, 300, 400, 500]
Object.keys(arr);// ['0', '1', '2', '3', '4'] 返回索引值字符串组成的数组
// 处理字符串,返回索引值数组
let str = 'zhang';
Object.keys(str);// ['0', '1', '2', '3', '4']
// 常用技巧
let zn = {name: 'zhangning', age: '25', address: '合肥', getName: function()}
Object.keys(person).map(item => {
person[item] // 获取到属性对应的值,做一些处理
})
7.Vue.component()
// 定义一个名为 button-counter 的新组件
Vue.component('button-counter', {
data: function () {
return {
count: 0
}
},
template: '<button v-on:click="count++">You clicked me {{ count }} times.</button>'
})
data 必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝,如果不是一个函数,就会影响到组件所有实例
在项目中自定义全局组件案例
首先创建一个组件 download.vue
然后创建一个 download.js,在 js 中引入组件
// 引入组件
import DLFLoading from './index.vue';
// 自定义组件对象
const DownloadDialog = {
// install 是默认的方法。当外界在 use 这个组件的时候,就会调用本身的 install 方法,同时传一个 Vue 这个类的参数
install: function(Vue) {
// Vue.component() 与正常的全局注册组件用法相同,可以理解为通过 install 和 Vue.use()函数注册了全局组件
Vue.component('DownloadDialog', DLFLoading);
}
}
// 导出
export default DownloadDialog;
接着在 main.js 中全局引入组件
// 全局引入自定义下载 loading
import DownloadDialog from '@/components/DownloadDialog/download.js';
Vue.use(DownloadDialog);
最后在项目中直接就可以使用
<DownloadDialog
@cancelDownload="cancelDownload"
:downloadOver="downloadOver"
:downloadLoading="downloadLoading"
></DownloadDialog>
8.Vue.use()
安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为参数传入。
该方法需要在 new Vue() 之前被调用
当 install 方法被同一个插件多次调用,插件将只会被安装一次。
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制 一般有以下几种
1.添加全局方法或者property
2.添加全局资源:指令/过滤器/过渡等
3.通过全局混入来添加一些组件选项
4.添加 Vue 实例方法,通过把他们添加到 Vue.prototype 上实现
5.一个库,提供自己的 api,同时提供上面提到的一个或多个功能
使用插件
通过全局方法 Vue.use() 使用插件。它需要在你调用 new Vue() 启动应用之前完成
// 调用 MyPlugin.install(Vue)
Vue.use(MyPlugin)
new Vue({ // ...组件选项
})
也可以传入一个可选的选项对象
Vue.use(MyPlugin, {someOption: true})
Vue.use 会自动阻止多次注册相同插件,即使多次调用也只会注册一次该插件
9.Vue.mixin()
全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。插件作者可以使用混入,向组件注入自定义的行为(官方不推荐使用)
官网全局混入案例。混入也可以进行全局注册,使用时格外小心,一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,它可以用来自定义选项注入处理逻辑。
// 为自定义的选项 myOption 注入一个处理器
Vue.mixin({
created: function(){
var myOption = this.$options.myOption
if(myOption) {
console.log(myOption)
}
}
}) new Vue({
myOption: 'zhangning'
})
// => 'zhangning'
注意:要谨慎使用全局混入,因为它影响每个单独创建的 Vue 实例(包括第三方组件)。大多数情况下,之应当应用于自定义选项,就像上面实例一样,推荐将其作为插件发布,以避免重复应用混入
使用案例
定义一个 mixin.js
let MiXin = {
data(){
return {
name: 'zhangning'
}
},
created(){
console.log('这是mixin中的name', this.name)
},
mounted(){},
methods: {}
}
export default MiXin
// 全局引入 import mixin from './mixin'
Vue.mixin(mixin) // 在 vue 组件中局部引入
import '@/mixin'
export default {
mixins: [mixin]
}
混入和组件的合并注意事项
1.数据对象 data 在内部进行递归合并,在和组件的数据发生冲突时以组件数据优先
2.同名钩子函数(created,mounted)将混合为一个数组,都将被调用。另外混入对象的钩子将在组件自身钩子之前调用
3.值为对象的选项(methods,components,directives)将被混合为同一个对象,两个对象键名冲突时,去组件对象的键值对
10.Vue.compile() -- 模板渲染
将一个模板字符串编译成 render 函数。旨在完整版时可用
let res = Vue.compile('<div><span>{{ massage }}</span></div>')
new Vue({
data: {
message: 'hello'
},
render: res.render,
staticRenderFns: res.staticRenderFns
})
以上是官网给的一个小实例。
以后深入理解之后,再回来更新
11.Vue.observable() -- 可用于组件间共享数据
让一个对象可响应,Vue 内部会用它来处理 data 函数返回的对象。
返回的对象可以直接用于渲染函数和计算属性内,并且会在发生变更时出发相应的更新。
处理简单的跨组件共享数据状态的问题,可以说是个精简的 vuex
示例
创建store.js
import Vue from 'vue'
export const store = Vue.observable({num: 0})
export const mutations = {
setNum (num) {
store.num = num
}
}
在组件中使用(所有的说明都没有举例子来的实在,理解的更快)
<template>
<div>
<span>选择数量</span>
<button @click="setNum(num + 1)"> + </button>
<span>count</span>
<button @click="setNum(num - 1)"> - </button>
</div>
</template> <script>
import { store, mutations } from '@/store/store'
export default {
name: 'numIndex',
computed: {
count() {
return store.num
}
},
methods: {
setNum: mutations.setNum
}
}
</script>
12.Vue.version()
提供字符串形式的 Vue 安装版本号。这对社区的插件和组件来说非常有用,你可以根据不同的版本号采取不同的策略
let version = Number(Vue.version.split('.')[0])
if (version == 2) {
} else if (version == 1) {
} else {}
就是获取当前使用的 vue 版本号,原理就是读取 package.json 中的 version 字段
以上就是 vue API 全局 API 的所有内容,
宝剑锋从磨砺出,梅花香自苦寒来。