一、Vue 基础之 mixin 混入、自定义指令、teleport、render 函数、插件和数据校验插件
mixin 混入,组件 data、methods 优先级高于 mixin data 优先级、methods 优先级,组件中有则执行组件中的,组件中没有的则执行 mixin 中的。生命周期函数,先执行 mixin 里面的,再执行组件里面的,如下所示:
const myMixin = {
data() {
return {
number: 2,
count: 2
}
},
created() {
console.log('mixin created')
},
methods: {
handleClick() {
console.log('mixin handleClick')
}
}
}
const app = Vue.createApp({
data() {
return { number: 1 }
},
created() {
console.log('created');
},
mixins: ['myMixin'],
methods: {
handleClick() {
console.log('handleClick');
},
},
template: `
<div>
<div>{{number}}</div>
<div>{{count}}</div>
<button @click="handleClick">增加</button>
</div>
`
});
const vm = app.mount('#root');
mixin 中,自定义的属性,组件中的属性优先级高于 mixin 属性的优先级。如果修改 mixin 优先级高于组件的优先级,可以使用策略配置 optionMergeStrategies 进行修改,如下所示:
const myMixin = {
number: 1
}
const app = Vue.createApp({
mixins: [myMixin],
number: 2,
template: `
<div>
<div>{{this.$options.number}}</div>
</div>
`
});
app.config.optionMergeStrategies.number = (mixinVal, appValue) => {
return mixinVal || appValue;
}
const vm = app.mount('#root');
- 自定义指令
directive,如下所示:
const directives = {
focus: {
mounted(el) {
el.focus();
}
}
}
const app = Vue.createApp({
data() {
return { hello: true }
}
template: `
<div>
<div v-if="hello">
<input v-focus />
</div>
</div>
`
});
app.directive('focus', {
beforeMount(el) {
console.log('beforeMount')
},
mounted(el) {
console.log('mounted');
el.focus();
},
beforeUpdate() {
console.log('beforeUpdate');
},
updated() {
console.log('updated');
},
beforeUnmount() {
console.log('beforeUnmount');
},
unmounted() {
console.log('unmounted');
}
});
const vm = app.mount('#root');
- 自定义指令后面可以接上一些参数,通过
binding.arg 获取参数,通过 binding.value 获取值,如下所示:
const app = Vue.createApp({
data() {
return {
distance: 110
}
},
template: `
<div>
<div v-pos:right="distance" class="header">
<input />
</div>
</div>
`
});
app.directive('pos', (el, binding) => {
el.style[binding.arg] = (binding.value + 'px');
});
const vm = app.mount('#root');
teleport 传送门,如下所示:
const app = Vue.createApp({
data() {
return {
show: false,
message: 'hello'
}
},
methods: {
handleBtnClick() {
this.show = !this.show;
}
},
template: `
<div class="area">
<button @click="handleBtnClick">按钮</button>
<teleport to="#hello">
<div class="mask" v-show="show">{{message}}</div>
</teleport>
</div>
`
});
const vm = app.mount('#root');
Vue 把 template 变成 render 函数,render 函数再返回一个虚拟 DOM,意义是让 Vue 的性能更快,让 Vue 具备跨平台的能力。render function,template -> render -> h -> 虚拟 DOM,JS 对象 -> 真实 DOM -> 展示到页面上,如下所示:
const app = Vue.createApp({
template: `
<my-title :level="2">
hello Tom
</my-title>
`
});
app.component('my-title', {
props: ['level'],
render() {
const { h } = Vue;
return h('h', this.level, {}, [
this.$slots.default(),
h('h4', {}, 'Tom')
])
}
});
const vm = app.mount('#root');
plugin 插件,也就是把通用性的功能封装起来,如下所示:
const myPlugin = {
install(app, options) {
app.provide('name', 'Tom');
app.directive('focus', {
mounted(el) {
el.focus();
}
});
app.mixin({
mounted() {
console.log('mixin');
}
});
app.config.globalProperties.$sayHello = 'hello world';
}
}
const app = Vue.createApp({
template: `
<my-title />
`
});
app.component('my-title', {
inject: ['name'],
mounted() {
console.log(this.$sayHello);
},
template: `<div>{{name}}<input v-focus /></div>`
});
app.use(myPlugin, { name: 'Tom'});
const vm = app.mount('#root');
- 对数据做校验的插件,如下所示:
const app = Vue.createApp({
data() {
return { name: 'Jack', age: 22}
},
rules: {
age: {
validate: age => age > 25,
message: 'too young, to simple'
},
name: {
validate: name => name.length >= 4,
message: 'name too short'
}
},
template: `
<div>name: {{name}}, age: {{age}}</div>
`
});
const validatorPlugin = (app, options) => {
app.mixin({
created() {
for(let key in this.$options.rules) {
const item = this.$options.rules[key];
this.$watch(key, (value) => {
const result = item.validate(value);
if (!result) console.log(item.message);
})
}
}
})
}
app.use(validatorPlugin);
const vm = app.mount('#root');