混入
mixin
Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个 mixin 对象可以包含任意组件选项。当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。
var obj = {
data:function(){
return {
name:'zhangsan'
}
}
}
export default {
mixins:[obj]
}
选项合并
当组件和 mixin 对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
比如,每个 mixin 可以拥有自己的 data 函数。每个 data 函数都会被调用,并将返回结果合并。在数据的 property 发生冲突时,会以组件自身的数据为优先。
var obj = {
data:function(){
return {
name:'zhangsan'
}
}
}
export default {
mixins:[obj],
data:function(){
return {
name:'lisi'//优先
}
}
}
同名钩子函数将合并为一个数组,因此都将被调用。另外,mixin 对象的钩子将在组件自身钩子之前调用。
var obj={
created(){
console.log(1)
}
}
created(){
console.log(2)//1,2都打印
}
//钩子函数
值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
全局mixin
你还可以为 Vue 应用程序全局应用 mixin:
//main.js
var obj={
data(){
return{
msg:'hello',
}
createApp(App).mixin(obj).use(store).use(router).mount('#app')
Mixin 也可以进行全局注册。使用时格外小心!一旦使用全局 mixin,它将影响每一个之后创建的组件 (例如,每个子组件)。
钩子函数: 1、是个函数,在系统消息触发时被系统调用 2、不是用户自己触发的
钩子函数的名称是确定的,当系统消息触发,自动会调用。
常见的钩子函数:vue的生命周期函数,vue的自定义指令等
自定义指令
在VUE中,我们可以在实例的directive属性中,自定义指令,这些指令可以被该实例使用;
如果是全局注册话,那么所有的子组件都可以使用!
在 Vue 3 中,我们为自 定义指令创建了一个更具凝聚力的 API。正如你所看到的,它们与我们的组件生命周期方法有很大的不同,即使我们正与类似的事件钩子,我们现在把它们统一起来了:
const MyDirective = {
created(el, binding, vnode, prevVnode) {}, // 新增
beforeMount() {},
mounted() {},
beforeUpdate() {}, // 新增
updated() {},
beforeUnmount() {}, // 新增
unmounted() {}
}
指令创建
directives:{
focus:{
mounted(el, binding, vnode) {
el.focus()
}
}
}
指令钩子函数参数
el:指令所绑定的元素,可以用来直接操作 DOM。
binding:一个对象,包含以下 property:
value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论 值是否改变都可用。
arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
instance:指向vue实例。
vnode:Vue 编译生成的虚拟节点。
prevVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。
指令参数
v-focus:color
el.style[binding.arg] = 'red';
动态指令参数
v-focus:[direction]
direction: 'color'
指令值
v-focus:color="'blue'"
el.style[binding.arg] = binding.value;
渲染函数
Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中,你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数,它比模板更接近编译器。
例如我们的需求是,在组件标签中传递一个属性值1-6,然后在子组件中分别使用h1-h6去包裹插槽的内容:
<anchored-heading :level="1">Hello world!</anchored-heading>
如果利用传统的模式,我们的逻辑可能会比较复杂,需要判断传值,且放置多个插槽。
<template>
<h1 v-if="level === 1">
<slot></slot>
</h1>
<h2 v-else-if="level === 2">
<slot></slot>
</h2>
<h3 v-else-if="level === 3">
<slot></slot>
</h3>
<h4 v-else-if="level === 4">
<slot></slot>
</h4>
<h5 v-else-if="level === 5">
<slot></slot>
</h5>
<h6 v-else-if="level === 6">
<slot></slot>
</h6>
</template>
<script>
export default {
props:['level']
}
</script>
这里用模板并不是最好的选择:不但代码冗长,而且在每一个级别的标题中重复书写了 <slot></slot>。
虽然模板在大多数组件中都非常好用,但是显然在这里它就不合适了。那么,我们来尝试使用 render 函数重写上面的例子:
<script>
import { h,ref } from 'vue'
export default {
props:['level'],
setup(props, { slots, attrs, emit }) {
return () => [
h('h' + props.level, { class: 'title' }, slots.default())
]
}
}
</script>
如果我们想要写的更加复杂,可以在h1元素中再创建子元素:
<script>
import { h,ref } from 'vue'
export default {
props:['level'],
setup(props, { slots, attrs, emit }) {
return () => [
h('h' + props.level, { class: 'title' }, [
h('span',{class:'s'},slots.default())
])
]
}
}
</script>
h函数的第二个参数:
// 3.x 语法
{
class: ['button', { 'is-outlined': isOutlined }],
style: [{ color: '#34495E' }, { backgroundColor: buttonColor }],
id: 'submit',
innerHTML: '',
onClick: submitForm,
key: 'submit-button'
}
V3 setup() 函数
-
setup函数是v3提供新的组件选项。
-
之前的data、声明周期、自定义函数都可以放置在内
-
在创建组件之前执行,初始化props,紧接着就调用setup函数,从生命周期钩子的视角来看,它会在beforeCreate钩子之前被调用
-
是mixins的强化版,比mixins更加灵活
-
因为setup()是在解析其它组件选项之前被调用的,所以避免使用this
V3 ref() 函数
在setup函数中,可以使用ref函数,用于创建一个响应式数据,当数据发生改变时,Vue会自动更新UI
例如:使用ref函数定义一个变量count:
<template>
<h1>{{ count }}</h1>
<button @click="change_count">点我</button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
let count = ref(0);
function change_count() {
count.value += 1;
}
return { count, change_count }
}
}
</script>
注意:
-
在setup中定义的变量或方法,都必须通过return {xxx,xxx}暴露出去,外界才能使用
-
ref函数仅能监听基本类型的变化,不能监听复杂类型的变化(比如对象、数组)
V3 reactive 函数
用来检测复杂数据类型的变化
<template>
<h1>{{ obj }}</h1>
<button @click="change_age">点我</button>
</template>
<script>
import { reactive } from 'vue'
export default {
setup() {
let obj = reactive({ name: "Alice", age: 12 });
function change_age() {
++obj.age
}
return { obj, change_age }
}
}
</script>
JSX
如果你写了很多 render 函数,可能会觉得上面这样的代码写起来麻烦,我们需要对元素进行很多配置。
用于在 Vue 中使用 JSX 语法,它可以让我们回到更接近于模板的语法上:
<script>
export default {
props:['level'],
setup(props, { slots, attrs, emit }) {
return () => <h1>{slots.default()}</h1>
}
}
</script>
注意:在HTML文件中,JSX是无法编译的,在脚手架中可以。
自定义插件
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
添加全局方法或者 property。如:vue-custom-element
添加全局资源:指令/过滤器/过渡等。如 vue-touch
通过全局混入来添加一些组件选项。如 vue-router
添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
myplugin.js vue3
export default{
install:(Vue,options)=>{
console.log(options)
//1.在插件中封装一个方法
Vue.config.globalProperties.$getname=()=>{
console.log('xiaoming');
},
//2.在插件中封装一个指令
Vue.directive('color', {
created(el, binding, vnode, oldVnode) {
el.style.color='red';
}
})
//3.为插件插件一个mixin
Vue.mixin({
data(){
return{
admin:'zhangsan'
}
}
})
}
}
插件的使用:
main.js
import myplugin from './utils/myplugin'
createApp(App).use(myplugin,{}).mount('#app')