动态组件
`:is 用于绑定动态组件`
被传给 :is 的值可以是以下几种:
被注册的组件名
导入的组件对象
<component :is="name"></component>
// 点击按钮切换组件
<button @click="names='ChildA'">按钮</button>
data() {
return {
//name: "ChildA",
name: "ChildB",
}
//给组件设置了一个名字,通过更改名字中的组件名,实现动态组件
//name 中是ChildA 则上面就是ChildA 反之是ChildB
KeepAlive组件
1.一般组件在动态改变时,会被销毁
使用<KeepAlive> 包裹动态组件时,这个组件在改变后不会销毁,会被放在缓存中,再次切换回来的时候数据仍然存在
`任何时候都只能有一个活跃组件实例作为 <KeepAlive> 的直接子节点`
2.KeepAlive 起作用的前提,动态载入的子组件必须有name,否则不会缓存
3.<KeepAlive> 中只能写入<component>
4.activated 进入时激活 deactivated 离开时失活
//当进入该组件时就会执行activated
//当离开该组件时就会执行deactivated 执行下一个进入的组件的activated
5.当一个组件在 <KeepAlive> 中被切换时,它的 activated 和 deactivated 生命周期钩子将被调用,用来替代 mounted 和 unmounted
<div>
<KeepAlive>
<component :is="names">{{ content }}</component>
</KeepAlive>
</div>
6.使用include/exclude(不包含)可以设置哪些组件被缓存,使用 max可以设定最多缓存多少个
1)include 可以使用字符串,正则表达式,数组
2)如果是字符串 include 如果是正则或者数组 :include
//设置只有ChildA和ChildC可以被缓存
<KeepAlive :include="['ChildA', 'ChildC']">
<component :is="names">{{ content }}</component>
</KeepAlive>
7.`<component>用于渲染动态组件或元素的“元组件”`
//这样会在页面中放入一个 div标签
<component :is="'div'"></component>
8.可以使用vue的组件替换当前原生的html标签
//把div 渲染成立 ChildA组件
<div is="vue:ChildA"></div>
切换案例
//父组件
<template>
<div>
<!-- <ul class="clear"> -->
//<!-- 通过 v-for 遍历list 把 name做为内容 -->
//<!-- 通过点击动态设置组件名 跳转到不同的组件 -->
<li v-for="item in list" :key="item.id" :class="item.name === content ? 'select-tab' : ''" @click="names = item.tab, content = item.name">{{ item.name }}</li>
</ul>
<div>
<KeepAlive :include="['ChildA', 'ChildC']">
<component :is="names">{{ content }}</component>
</KeepAlive>
<!-- </div> -->
</div>
</template>
<script>
import ChildA from "@/components/dynamicComponent/ChildA.vue"
import ChildB from "@/components/dynamicComponent/ChildB.vue"
import ChildC from "@/components/dynamicComponent/ChildC.vue"
export default {
name: 'DynamicComponent',
components: {
ChildA,
ChildB,
ChildC
},
data() {
return {
names: "ChildA",
content: "水果",
list: [
{ id: 1001, name: "水果", tab: "ChildA" },
{ id: 1002, name: "蔬菜", tab: "ChildB" },
{ id: 1003, name: "粮油", tab: "ChildC" },
]
}
}
}
</script>
<style>
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
float: left;
padding: 5px 20px;
border: 1px solid #000;
border-left: none;
}
li:first-child {
border-left: 1px solid #000;
}
.clear::after {
content: "";
display: block;
height: 0;
visibility: hidden;
clear: both;
}
.select-tab {
background-color: orange;
}
</style>
// 三个子组件
<template>
<div>
A 上次停留的时间:{{this.time }}
<hr />
<slot name="default"></slot>
<hr />
{{ count }}
<button @click="count++">按钮</button>
</div>
</template>
<script>
export default {
name: "ChildA",
data() {
return {
count: 1,
time: 0,
date: 0
}
},
activated() {
console.log("A进入时,激活")
this.date = Date.now();
},
deactivated() {
console.log("A离开时,失活")
this.time = Date.now() - this.date + this.time;
this.date = null
}
}
</script>
<template>
<div>
B
<hr />
<slot name="default"></slot>
<hr />
{{ count }}
<button @click="count++">按钮</button>
</div>
</template>
<script>
export default {
name: "ChildB",
data() {
return {
count: 1
}
},
activated() {
console.log("B进入时,激活")
},
deactivated() {
console.log("B离开时,失活")
}
}
</script>
<template>
<div>
C
<hr />
<slot name="default"></slot>
<hr />
{{ count }}
<button @click="count++">按钮</button>
</div>
</template>
<script>
export default {
name: "ChildC",
data() {
return {
count: 1
}
},
activated() {
console.log("C进入时,激活")
},
deactivated() {
console.log("C离开时,失活")
}
}
</script>
异步组件
异步组件-->用到时再加载,尤其针对首页和部分主页面
// 组件名:() => import() 加载函数 异步要搭配这个使用
// 其中import 是一个promise类型
`标准写法`
<template>
<div>
<ChildA/>
</div>
</template>
<script>
//异步组件的引入
import { defineAsyncComponent } from "vue";
export default {
name: "AsyncComponent",
//异步组件的注册
components: {
ChildA: defineAsyncComponent({
loader: () => import("@/components/asyncComponent/ChildA.vue")
})
}
}
</script>
`<Suspense>组件`
是一个内置组件,让我们可以在组件树上层等待下层的多个嵌套异步依赖项解析完成,并可以在等待时渲染一个加载状态
// 使用
<Suspense>
<ChildA />
// 如果当前异步组件没有加载完成,就会显示下面template中的内容
// #fallback 是固定的
<template #fallback>
加载中...
</template>
</Suspense>
自定义指令
1.自定义的指令要放在directives中使用
2.在directives当中设置的指令属性名,在标签中必须使用v-指令名
3.自定义指令中mounted中的参数
1)第一个参数 el就是真实的DOM,是被设置当前指令的元素
2)第二个参数的 $.instance 当前组件的实例化,可以调用data中的属性
3)第三个参数 vNode 就是虚拟DOM
<template>
<div>
//<!-- 给div设置一个自定义指令叫做 color -->
<div v-color="'green'">阿边</div>
</div>
</template>
<script>
import ChildA from "@/components/commandView/ChildA.vue"
export default {
name: "CommandView",
components: {
ChildA
},
data() {
return {
count: 1
}
},
`directives`: {
color: {
mounted(el, $, vNode) {
// 第一个参数el就是真实的DOM,是被设置当前指令的元素
console.log(el)
// $.instance 当前组件的实例化,可以调用data中的属性
console.log($.instance)
console.log($.instance.count)//1
// vNode 就是虚拟DOM
// 第二个参数的value就是这个指令给的值
// 这样可以在上面任意写入值
el.style.color=$.value
}
}
}
}
</script>
案例 验证号码
<template>
<div>
// <!-- 设置一个自定义指令叫做 tel -->
// <!-- v-tel.cn 设置不同的地区 -->
// v-tel 是自定义的指令
<input type="text" v-model="tel" v-tel.cn>
</div>
</template>
<script>
import ChildA from "@/components/commandView/ChildA.vue"
export default {
name: "CommandView",
components: {
ChildA
},
data() {
return {
count: 1,
tel: ""
}
},
directives: {
tel: {
updated(el, $) {
console.log($.modifiers)//指令后面的 .的内容
var header = "";
// 当$.modifiers.cn为真 且不是+086开头时 进入
if ($.modifiers.cn && !/^\+086/.test($.instance.tel)) {
// 设置中国地区正确的电话号码
$.instance.tel = "+086" + $.instance.tel;
header = "^\\+086";
} else if ($.modifiers.hk && !/^\+00852/.test($.instance.tel)) {
// 设置香港地区正确的电话号码
$.instance.tel = "+00852" + $.instance.tel;
header = "^\\+00852";
}
// 判断电话号码是否正确 通过颜色进行提示
if (new RegExp(header + "1[3-9]\\d{9}$").test($.instance.tel)) {
el.style.color = "green"
} else {
el.style.color = "red"
}}}}}
</script>
全局注册指令
指令中的内容放在单独放在一个文件夹下 引入到main.js中进行使用
vue3过渡效果和传送门
<Transition> 它可以将进入和离开动画应用到通过默认插槽传递给它的元素或组
<Transition> 仅支持单个元素或组件作为其插槽内容。如果内容是一个组件,这个组件必须仅有一个根元素
//进入或离开可以由以下的条件之一触发
● 由 v-if 所触发的切换
● 由 v-show 所触发的切换
● 由特殊元素 <component> 切换的动态组件
` CSS 过渡`
1. v-enter-from:进入动画的起始状态。在元素插入之前添加,在元素插入完成后的下一帧移除。
2. v-enter-active:进入动画的生效状态。应用于整个进入动画阶段。在元素被插入之前添加,在过渡或动画完成之后移除。这个 class 可以被用来定义进入动画的持续时间、延迟与速度曲线类型。
3. v-enter-to:进入动画的结束状态。在元素插入完成后的下一帧被添加 (也就是 v-enter-from 被移除的同时),在过渡或动画完成之后移除。
4. v-leave-from:离开动画的起始状态。在离开过渡效果被触发时立即添加,在一帧后被移除。
5. v-leave-active:离开动画的生效状态。应用于整个离开动画阶段。在离开过渡效果被触发时立即添加,在过渡或动画完成之后移除。这个 class 可以被用来定义离开动画的持续时间、延迟与速度曲线类型。
6. v-leave-to:离开动画的结束状态。在一个离开动画被触发后的下一帧被添加 (也就是 v-leave-from 被移除的同时),在过渡或动画完成之后移除
`为过渡效果命名`
<Transition name="fade">
<!-- <p v-if="show">这个文本需要动画</p> -->
<div v-if="show" class="div1">显示的容器</div>
</Transition>
//下面的更改为 把其中的 v 换成起的名字
.fade-enter-from,
.fade-leave-to {
opacity: 0;
transform: translate(-50%, -300px);
transition: all 0.5s cubic-bezier(0,.41,1,-0.36);
}
.fade-enter-to,.fade-leave-from {
opacity: 1;
transform: translate(-50%, 0);
transition: all 0.5s cubic-bezier(0,.41,1,-0.36);
}
案例 div动画显示
<template>
<div>
<button @click="show = !show">按钮</button>
<Transition>
<!-- <p v-if="show">这个文本需要动画</p> -->
<div v-if="show" class="div1">显示的容器</div>
</Transition>
</div>
</template>
<script>
import ModelView from "@/components/transitionView/ModalView.vue"
export default {
name: "TransitionView",
data() {
return {
show: false,
}
}
}
</script>
<style>
.div1 {
width: 500px;
height: 300px;
border: 1px solid #000;
background-color: tomato;
position: fixed;
left: 50%;
transform: translate(-50%, 0);
}
.v-enter-from,
.v-enter-active,
.v-leave-active,
.v-leave-to {
opacity: 0;
transform: translate(-50%, -300px);
transition: all 1s;
}
.v-enter-to,
.v-leave-from {
opacity: 1;
transform: translate(-50%, 0);
transition: all 1s;
}
</style>
Teleport传送门
是一个内置组件,它可以将一个组件内部的一部分模板“传送”到该组件的 DOM 结构外层的位置去
常用于全屏的模态窗
// <Teleport> 接收一个 to prop 来指定传送的目标。to 的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。
// 这段代码的作用就是告诉 Vue“把以下模板片段传送到 body 标签下”。
<button @click="open = true">Open Modal</button>
<Teleport to="body">
<div v-if="open" class="modal">
<p>Hello from the modal!</p>
<button @click="open = false">Close</button>
</div>
</Teleport>
`案例`
// 父组件
<template>
<div>
<Teleport to="body">
<div class="mask" v-if="show" @click="show = false"></div>
<Transition>
<ModelView v-if="show" title="添加新用户" @close="show = false">
<template #content>
<label>用户名:</label> <input type="text"><br>
<label>密码:</label> <input type="password" autocomplete>
</template>
<template #footer>
<button type="submit">登录</button>
<button type="reset">重置</button>
</template>
</ModelView>
</Transition>
</Teleport>
</div>
<button @click="show = true">按钮</button>
</template>
<script>
import ModelView from "@/components/transitionView/ModelView.vue"
export default {
name: "TransitionView",
components: {
ModelView
},
data() {
return {
show: false,
}
}
}
</script>
<style>
.div1 {
width: 500px;
height: 300px;
border: 1px solid #000;
background-color: tomato;
position: fixed;
left: 50%;
transform: translate(-50%, 0);
}
.v-enter-from,
/* .v-enter-active,
.v-leave-active,
这两个中间效果可以不写
*/
.v-leave-to {
opacity: 0;
transform: translate(-50%, -300px);
transition: all 0.2s cubic-bezier(0, .41, 1, -0.36);
}
.v-enter-to,
.v-leave-from {
opacity: 1;
transform: translate(-50%, 0);
transition: all 0.2s cubic-bezier(0, .41, 1, -0.36);
}
.mask {
position: absolute;
width: 100%;
height: 100%;
background-image: url('/public/img/鬼灭1.webp');
left: 0;
top: 0;
}
</style>
// 子组件
<template>
<div class="modal">
<div>
<h3>{{ title }}</h3>
<button class="close" @click="clickhandler">×</button>
</div>
<form>
<div class="content">
<slot name="content"></slot>
</div>
<hr />
<div class="footer">
<slot name="footer"></slot>
</div>
</form>
</div>
</template>
<script>
export default {
name: "ModelView",
props: ["title"],
emits: ["close"],
methods: {
clickhandler() {
this.$emit("close");
}
}
}
</script>
<style scoped>
.modal {
width: 500px;
position: absolute;
border: 1px solid #000;
background-color: #fff;
left: 50%;
transform: translate(-50%, 0);
}
.modal h3 {
text-align: center;
}
.modal .close {
position: absolute;
right: 10px;
top: 10px;
}
.modal .content {
text-align: center;
}
.modal .footer {
text-align: right;
}
</style>
其他函数
1.$forceUpdate()
在vue2中 对象以及数组的操作,在数据改变时,视图没有更新,使用$forceUpdate()进行强制更新视图
2.$nextTick()
用于在DOM更新之后执行延迟回调函数
它的主要作用是在当前数据变化后等待DOM更新完成,然后执行特定的操作
比如获取更新后的DOM元素或执行一些需要在DOM渲染完成后进行的操作
3.渲染函数 h() 创建虚拟DOM节点
// h(标签名,标签的标签属性,标签里的内容)
// h(标签名,标签的标签属性,[标签内子节点])
<template>
<div>
<ChildA />
</div>
</template>
<script>
import { h } from "vue";
// 动态创建一个p标签
var ChildA = h("p", {}, "内容")
export default {
name: "OtherView",
components: {
ChildA
}
}
</script>
4.渲染函数mergeProps()
// 合并多个 props 对象,用于处理含有特定的 props 参数的情况
// 可以合并class、style、onXxx 事件监听器——多个同名的事件监听器将被合并到一个数组
// 当有相同的属性时,会覆盖;不同的就合并
<template>
<div>
<ChildA />
{{ d }}
// 打印出来是
`{ "class": "div0 div1 div2", "onClick": [ null, null ] }`
// 把 A与B的class合并在了一起
</div>
</template>
<script>
import { h, mergeProps } from "vue";
const A = {
class: "div0",
onClick: () => {
console.log("1");
}
}
const B = {
class: ["div1", "div2"],
onClick: () => {
console.log("2");
}
}
export default {
name: "OtherView",
components: {
ChildA
},
data(){
return{
// 合并对象
d:mergeProps(A,B)
}
},
,
mounted() {
console.log(this.d);
//Proxy(Object) {class: 'div0 div1 div2', onClick: Array(2)}
}
}
</script>
5.渲染函数cloneVNode()
// 克隆一个 vnode,返回一个克隆的 vnode,可在原有基础上添加一些额外的 prop
// Vnode 被认为是一旦创建就不能修改的,你不应该修改已创建的 vnode 的 prop,而应该附带不同的或额外的 prop 来克隆它
var ChildA = h("div", {}, "内容")
var ChildB = cloneVNode(ChildA, { class: "div3" })
console.log(ChildA)
console.log(ChildB)
6.mixins 混入
允许我们在`多个组件之间共享重复的逻辑`,将公用的功能以对象的方式传入 mixins 选项中,当组件使用 mixins 对象,所有 mixins 对象的选项都将被扩展到该组件本身的选项中来,这样就可以`提高代码的重用性,并易于后期的代码维护`
<template>
<div>
<ChildA />
<ChildB />
</div>
</template>
<script>
import { cloneVNode, h, mergeProps } from "vue";
var ChildA = h("div", {}, "内容")
var ChildB = cloneVNode(ChildA, { class: "div3" })
const A1 = {
components: {
ChildA,
},
data() {
return {
count: 1
}
},
created() {
console.log("aa")
}
}
const B1 = {
components: {
ChildB,
},
data() {
return {
sum: 2
}
},
methods: {
click() {
console.log("NIHAO")
}
},
mounted() {
console.log("bb")
}
}
export default {
name: "OtherView",
mixins: [A1, B1],
components: {
},
mounted() {
console.log(this)
// 混入之后 可以调用A1或B1中的值或方法
console.log(this.sum);//2
console.log(this.count);//1
this.click()//NIHAO
}
}
</script>