vue3
混入
Mixin 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。
一个 mixin 对象可以包含任意组件选项。
当组件使用 mixin 对象时,所有 mixin 对象的选项将被“混合”进入该组件本身的选项。
var obj = {
data:function(){
return {
name:'zhangsan'
}
}
}
export default {
mixins:[obj]
}
<template>
{{ username }}
<button @click="getname">获取</button>
</template>
<script>
var obj = {
data() {
return {
username: "zhangsan",
};
},
methods: {
getname() {
console.log(this.username);
},
},
};
export default {
mixins: [obj]; // 使用mixin对象,使obj对象选项被混合进入该组件
};
</script>
选项和并
当组件和 mixin 对象含有同名选项时,这些选项将以恰当的方式进行“合并”。
每个 mixin 可以拥有自己的 data 函数。每个 data 函数都会被调用,并将返回结果合并。
在数据的 property 发生冲突时,会以组件自身的数据为优先
。
混合后对象和组件的有同名属性或方法时,组件中属性和方法会覆盖对象中的同名属性和方法;
而同名的钩子函数,为对象中的钩子函数先执行,组件中的钩子函数后执行,互不冲突
<template>
{{ username }}
<button @click="getname">获取</button>
</template>
<script>
var obj = {
data() {
return {
username: "zhangsan",
};
},
methods: {
getname() {
console.log(this.username);
},
},
created(){
console.log(1);
}
};
export default {
mixins: [obj],
data() {
return {
username: "lisi", //属性和方法,实例优先
};
},
methods: {
},
created(){
console.log(2); //混入的钩子先执行,实例的钩子后执行
}
};
</script>
同名钩子函数将合并为一个数组,因此都将被调用。
mixin 对象的钩子将在组件自身钩子之前调用。
值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。
全局mixin
Vue 应用程序全局应用 mixin, vue全局都可以使用全局的数据
main.js
//全局混入
var obj={
data(){
return{
msg:'hello'
}
}
}
createApp(App).mixin(obj).use(store).use(router).mount('#app')
Home.vue
<template>
{{msg}} // 在vue全局中都可以使用全局mixin中的值
</template>
<script>
export default {
};
</script>
自定义指令
在实例的directive属性中,自定义指令,这些指令可以被该实例使用(私有自定义指令)。
如果是全局注册(在main.js中进行注册)的话,那么所有的组件都可以使用(全局自定义指令)。
私有自定义指令
directives节点与data,created和mothods同级
<!-- 给自定义指令传变量 -->
<h1 v-color="color"></h1>
<!-- 给自定义指令传一个固定值,需要加单引号 -->
<h1 v-color="'red'"></h1>
data() {
return {
color: 'blue'
}
},
directives: {
// 定义一个名为color的指令
color: {
// 当指令第一次被绑定到元素上时,会立即触发bind函数
// el 表示当前指令被绑定到的DOM对象
bind(el, binding) {
// binding为用户通过=传递的值
console.log(binding)
el.style.color = binding.value
}
}
}
bind函数只会被调用一次,只在指令第一次被绑定到元素上时才触发。
update函数在DOM被更新时被触发。
<!-- 给自定义指令传变量 -->
<h1 v-color="color"></h1>
<!-- 点击按钮时bind函数不会被触发,颜色值不会被改变-->
<button @click="color='green'">改变color值</button>
directives: {
// 定义一个名为color的指令
color: {
// 当指令第一次被绑定到元素上时,会立即触发bind函数
// el 表示当前指令被绑定到的DOM对象
bind(el, binding) {
// binding为用户通过=传递的值
console.log(binding)
el.style.color = binding.value
},
// 在每次DOM被更新时会触发
updated(el, binding) {
console.log(binding)
el.style.color = binding.value
}
}
}
函数简写:
如果在bind和update函数中书写一样的代码,可以将函数进行简写。
directives: {
// 定义一个名为color的指令
// 当bind和update函数内容一样时,将bind和update函数进行简写
color(el, binding){
console.log(binding)
el.style.color = binding.value
}
}
全局自定义指令
main.js
// Vue.directive('color', {
// bind(el, binding) {
// el.style.color = binding.value
// },
// updated(el, binding) {
// el.style.color = binding.value
// }
// })
// 进行函数简写
Vue.directive('color', function(el, binding){
el.style.color = binding.value
}
)
mounted函数只在元素第一次插入Dom时被调用,当DOM更新时mounted函数不会被触发。
updated函数会在每次DOM更新完成后被调用。
app.directive(
'focus',{
mounted(el){
el.focus()
},
undated(el){ //每次DOM更新都会调用
el.focus()
}
})
如果mounted和updated函数中逻辑完全相同,则可以简写:
app.directive('focus', (el) => {
el.focus() //mounted和updated函数被触发时都是执行该操作
},
})
指令创建
<template>
<input type="text" v-focus>
</template>
<script>
export default {
directives:{
focus:{
//当被绑定的元素插入到DOM中时,会自动触发mounted函数
mounted(el){ //el 当前元素
el.focus(); //获取焦点
el.style.border="1px solid red";
el.style.outline="none"
},
},
}
</script>
指令钩子函数参数
-
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 钩子中可用。
<template> <p v-color>哈哈哈</p> <p v-color="'yellow'">今天天气很好</p> //绑定值 <p v-color:fontSize="'30px'">小没哭了</p> //设置指令值 <p v-color:color.weight="'white'">啦啦啦</p> //修饰符 </template> <script> export default { color:{ created(el,binding){ el.style.backgroundColor="pink"; el.style.color=binding.value; //对象的绑定值 el.style[binding.arg]=binding.value; //对象的参数的值 if(binding.modifiers.weight){ //含修饰符的对象 el.style.fontWeight="700"; } }, } } } </script>
指令参数
v-focus:color
el.style[binding.arg] = 'red'; //给指令传递的参数赋值
动态指令参数
v-focus:[direction]
direction: 'color' //可以动态改变指令的参数
指令值
v-focus:color=" 'blue' "
el.style[binding.arg] = binding.value;
渲染函数
渲染函数比模板更接近编译器。
在组件标签中传递一个属性值1-6,然后在子组件中分别使用h1-h6去包裹插槽的内容:
<template>
<my-h :level="2">hello world </my-h>
</template>
<script>
import MyH from '../components/MyH.vue'
export default {
components:{
MyH
}
}
</script>
render 函数 跟 template 一样都是创建 html 模板的,但是有些场景中用 template 实现起来代码冗长繁琐而且有大量重复,这时候就可以用 render 函数。
<script>
import { h,ref } from "vue";
export default {
props: ["level"],
setup(props, { slots, attrs, emit }) {
return () => [
h('h'+props.level,{},[slots.default()]), //h函数 (标签名,{},[插槽] )
];
},
};
</script>
h元素中还可以再创建子元素
<script>
import { h } from "vue";
export default {
props: ["level"],
setup(props, { slots, attrs, emit }) {
return () => [
h('h'+props.level,{},[slots.default()]), //h函数
h(
"h" + props.level,
{
class: "title",
style: [{ backgroundColor: "yellow" }],
}, //h函数的第二个子元素
[
h("span", {}, slots.default()),
h("span", {}, slots.default())
], //可以在h元素中创建多个子元素
),
];
// return()=><h1>{slots.default()}</h1>
},
};
</script>
setup() 函数
● setup函数是v3提供新的组件选项。
● 之前的data、声明周期、自定义函数都可以放置在内
● 在创建组件之前执行,初始化props,紧接着就调用setup函数,从生命周期钩子的视角来看,它会在beforeCreate钩子之前被调用
● 是mixins的强化版,比mixins更加灵活
● 因为setup()是在解析其它组件选项之前被调用的,所以避免使用this
ref() 函数
<template>
<h1>{{count}}</h1>
<button @click="change_count">点我</button>
</template>
<script>
import {ref} from 'vue'
export default {
setup(){
let count=ref(0); //ref函数监听count的变化
function change_count(){
count.value+=1;
}
return {count,change_count}
}
}
</script>
注:
● 在setup中定义的变量或方法,都必须通过return {xxx,xxx}暴露出去,外界才能使用
● ref函数仅能监听基本类型的变化
,不能监听复杂类型的变化(比如对象、数组)
reactive函数
reactive函数用来检测复杂数据类型的变化
<template>
<h1>{{obj.name}}</h1>
<button @click="change_obj">点我</button>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
setup(){
let obj= reactive({name:'zhangsan'}); //reactive函数封装引用数据类型
function change_obj(){
obj.name='lisi'
}
return {obj,change_obj}
}
}
</script>
JSX
render函数虽然可以解决问题,但是代码写起来比较麻烦。
在 Vue 中使用 JSX 语法,它可以让我们回到更接近于模板的语法上。
自定义插件
插件通常用来为 Vue 添加全局功能。插件的功能范围没有严格的限制——一般有下面几种:
添加全局方法或者 property。如:vue-custom-element
添加全局资源:指令/过滤器/过渡等。如 vue-touch
通过全局混入来添加一些组件选项。如 vue-router
添加 Vue 实例方法,通过把它们添加到 Vue.prototype 上实现。
一个库,提供自己的 API,同时提供上面提到的一个或多个功能。如 vue-router
Vue.js 的插件应该暴露一个 install 方法。这个方法的第一个参数是 Vue 构造器,第二个参数是一个可选的选项对象:
在src文件夹中创建utils文件夹
myplugin.js
//自定义插件
export default{
install:(Vue,options)=>{
//1.在插件中封装一个方法$getname
Vue.config.globalProperties.$getname=()=>{
console.log('xiaoming');
}
//2.在插件中封装一个指令 v-color
Vue.directive('color', {
created(el, binding, vnode, oldVnode) {
el.style.color="red";
}
})
//3.为插件创建一个mixin admin
Vue.mixin({
data(){
return {
admin:'zhangsan'
}
}
})
}
}
插件的使用
main.js
import myplugin from './utils/myplugin'
createApp(App).use(myplugin).use(store).use(router).mount('#app')
Home.vue
<template>
<!-- <button @click="$getname" v-color>{{admin}}点击</button> -->
<button @click="getname" v-color>{{admin}}点击</button>
</template>
<script>
export default {
methods:{
getname(){
this.$getname();
}
},
}
</script>