Vue高级用法
1.自定义指令
-
在Vue的模版语法中我们学习过各种指令,比如v-show,v-for这些,但是除了这些指令之外其实Vue也提供了自定义的指令
- 在通常情况下如果需要对DOM元素进行底层操作,就可以使用自定义指令
-
自定义指令分为两种:
- 自定义局部指令: 组件中通过directives选项,只能在当前组件中使用
- 自定义全局指令: app中directive方法,可以在任意组件中被使用
-
下面👇案例展示
<template>
<input text="text" v-focus />
</template>
<script>
export default {
//局部自定义指令
directives: {
focus: {
mounted(el,bindings,vnode,preVnode) {
el.focus()
}
}
}
}
</script>
//全局自定义指令
app.directive("focus",{
mounted(el,bindings,vnode,preVnode) {
el.focus()
}
})
2.指令的生命周期
-
一个指令定义的对象,Vue提供了一些钩子函数:
- created:在绑定元素的attribute或时事件监听器被应用之前调用;
- beforeMount:当指令第一次绑定到元素并且在挂载父组件之前调用;
- mounted:在绑定元素的父组件被挂载后调用;
- beforeUpdate:在更新包含组件的 VNode 之前调用;
- updated:在包含组件的 VNode 及其子组件的 VNode 更新后调用;
- beforeUnmount:在卸载绑定元素的父组件之前调用;
- unmounted:当指令与元素解除绑定且父组件已卸载时,只调用一次;
<template>
<!-- 自定义指令是可以有修饰符 -->
<button v-if="counter < 2" @click="increment" v-lifeCircle.abc="'TimYang'">
当前计数:{{counter}}
</button>
</template>
<script>
import {ref} from "vue"
export default {
directives: {
lifeCircle: {
created(el,bindings,vnode,preVnode) {
console.log("lifeCircle created",el,bindings,vnode,preVnode)
console.log(bindings.value) //TimYang
console.log(bindings.modifiers);//修饰符对象
},
beforeMount() {
console.log("lifeCircle beforeMount")
},
mounted() {
console.log("lifeCircle mounted")
},
beforeUpdate() {
console.log("lifeCircle beforeUpdate")
},
updated() {
console.log("lifeCircle updated")
},
beforeUnmount() {
console.log("lifeCircle beforeUnmount")
},
unmounted() {
console.log("lifeCircle unmounted")
},
}
}
setup() {
const counter = ref(0)
const increment = () => {
counter.value++
}
return {
counter
increment
}
}
}
</script>
3.自定义指令案例
<template>
<h2 v-format-time="'YYYY/MM/DD'">
{{timestamp}}
</h2>
</template>
<script>
export default {
setup() {
const timestamp = 1624452193
return {
timestamp
}
}
}
</script>
- 把自定义指令抽离出来放入在directive文件夹中
//format-time.js
//记得下载一个dayjs库
import dayjs from "dayjs"
export default function(app) {
let formatString = "YYYY-MM-DD HH:mm:ss"
app.directive("format-time",{
created(el,bindings) {
if(bindings.value) {
formatString = bindings.value
}
}
mounted(el,bindings) {
const textContent = el.textContent
const timestamp = parseInt(textContent)
if(textContent.length === 10) {
timestamp = timestamp * 1000
}
el.textContent = dayjs(timestamp).format(formatString)
}
})
}
//index.js
import registerFormatTime from "./format-time"
export default function registerDirectives(app) {
registerFormatTime(app)
}
//main.js
const app = createAPP(App)
//在入口文件把app传过去这样就可以有全局指令
registerDirectives(app)
4.Teleport
-
在组件化开发中,我们封装一个组件A,在另外一个组件B中使用:
- 那么组件A中template的元素,会被挂载到组件B中template的某个位置
- 最终我们应用会形成一颗DOM树结构
-
但是在某些情况下,是希望组件不是挂载在这个组件树上的,可能是移动到Vue app之外的其他位置
- 比如移动到body元素上,或者有其他的div#app之外的元素上
- 这个时候我们可以通过teleport来完成
-
Teleport是什么呢?
-
它是Vue提供的内置组件,类似react的Portals;
-
带有两个属性:
- to:指定将其中的内容移动到目标元素,可以使用选择器
- disabled:是否禁用teleport功能
-
App.vue
-
<template>
<div class="app">
<teleport to="#tele">
<h2>当前计数</h2>
<button>+1</button>
<HelloWorld></HelloWorld>
</teleport>
<!-- 如果👇这个tele和上面的id都相同,也不会影响,因为到时候代码其实是会进行合并的 -->
<!--<teleport to="#tele">
<h2>当前计数</h2>
<button>+1</button>
<HelloWorld></HelloWorld>
</teleport>-->
</div>
</template>
<script>
import HelloWorld from "./HelloWorld.vue"
export default {
components: {
HelloWorld
}
}
</script>
<style scoped>
</style>
- HelloWorld.vue
<template>
<div>
<h2>Hello World</h2>
</div>
</template>
<script>
export default {
}
</script>
<style scoped>
</style>
然后这个#tele放在哪里呢,就放在对应的index里面
5.Vue插件
-
通常我们向Vue全局添加一些功能时,会采用插件的模式,它有两种编写方式:
- 对象类型:一个对象,但是必须包含一个 install 的函数,该函数会在安装插件时执行;
- 函数类型:一个function,这个函数会在安装插件时自动执行;
-
插件可以完成的功能没有限制,比如下面的几种都是可以的:
- 添加全局方法或者 property,通过把它们添加config.globalProperties 上实现;
- 添加全局资源:指令,过滤器,过渡等;
- 通过全局 mixin 来添加一些组件选项;
- 一个库,提供自己的 API,同时提供上面提到的一个或多个功能;
创建一个plugins里面存放plugins_object.js
//plugins_object.js
export default {
install(app) {
console.log(app)
app.config.globalProperties.$name = "Tim"
}
}
在入口文件使用插件
import { createApp } from 'vue'
import registerDirectives from './directives'
import pluginObject from './plugins/plugins_object'
import pluginFunction from './plugins/plugins_function'
const app = createApp(App);
registerDirectives(app);
//对象的使用:其实就是内部执行了install
app.use(pluginObject);
//函数的使用
app.use(pluginFunction);
app.mount('#app');
在👆的插件中写入全局的name那么在组件内部就可以获取到
//App.vue
<template>
</template>
<script>
import {getCurrentInstance} from "vue"
export default {
mounted() {
console.log(this.$name) //Tim
}
//也可以在setup中获取,比较麻烦
setup() {
const instance = getCurrentInstance();
console.log(instance.appContext.config.globalProperties.$name
}
}
</script>
<style>
</style>
plugins_object.js里面写的也可以是一个函数不仅仅是对象
export default function(app) {
console.log(app)
app.component("")
app.mixin();
app.config.globalProperties.$name = "Tim"
}