目录
八. Provide 和 Inject(非父子组件间的通信 祖先组件之间)
一. 计算属性
1. 特点
-
名称自定义
-
任何包含响应式数据的复杂逻辑,都应该使用计算属性
-
计算属性是有缓存的
-
计算属性和methods 的区别:
-
计算属性会基于它的依赖关系进行缓存,是有缓存的
-
在数据不发生变化时,计算属性是不需要重新计算的
-
依赖的数据发生变化,计算属性会自动重新进行计算
-
在多次调用时,methods 会多次执行,计算属性只执行一次
2. 写法
1. 函数式写法
computed: {
fullname() {
return this.firstName + " " + this.lastName;
}
}
2. 对象式写法
computed: {
fullName: {
get: function() {
return this.firstName + " " + this.lastName;
},
set: function(value) {
const names = value.split(" ");
this.firstName = names[0];
this.lastName = names[1];
}
}
}
二. 侦听器
1. 特点
名称的定义是所依赖的数据的名称
2. 写法
1. 函数式写法
watch: {
message(newValue, oldValue) {
console.log(newValue, oldValue)
// 如果侦听的是一个对象时,这个对象是通过proxy代理侦听,侦听后拿到的是一个proxy对象
// 可以通过下面的方法拿到原始对象
console.log(Vue.toRaw(newValue))
// console.log({ ...newValue })
}
}
2. 对象式写法
watch: {
info: {
handler(newValue, oldValue) {
console.log(newValue, oldValue)
},
deep: true,
immediate: true
}
}
3. 对属性的侦听
watch: {
'info.name': function(newValue, oldValue) {
console.log(newValue, oldValue)
}
}
4. this.$watch
created() {
this.$watch( "message",
(newValue, oldValue) => {
console.log(newValue, oldValue)
}, {deep: true, immediate: true})
}
三. 虚拟DOM
1. 作用
多个VNode 节点 -> 虚拟DOM -> 真实DOM
作用一: 跨平台
作用二: diff 算法
四. 组件
1. 全局组件
import Vue from 'vue';
import comCpns from '@/components/comCpns';
Vue.component('com-cpns', comCpns);
Vue.component(comCpns.name, comCpns);
<com-cpns></com-cpns>
<product-item></product-item>
<ProductItem></ProductItem>
app.component("ProductItem",{})
2. 局部组件
<ProductItem></ProductItem>
<product-item></product-item>
components: {
ProductItem
}
五. 组件间的通信
1. 父传子(自定义属性)
// 父组件
<show-info name="why" :age="18"></show-info>
import ShowInfo from './show-info.vue';
components: {
ShowInfo
}
// 子组件
// 1. 数组语法
props: ["name", "age"];
// 2. 对象语法 (推荐)
props: {
name: {
type: String,
required: true
},
age: {
type: Number,
default: 0
},
// 对象类型的写法
friend: {
type: Object,
default: () => {{ name:"kobe" }}
//default() {
// return { name: "kobe"}
//}
},
// 数组类型的写法
hobbies: {
type: Array,
default: () => ["a", "b", "c"]
}
}
2. 子传父(自定义事件)
// 父组件
<add-counter @addClick="addBtnClick"></add-counter>
addBtnClick(count) {
this.counter += count
}
// 子组件
<button @click="btnClick(1)"></button>
// 注册自定义事件
emits: ["addClick"]
btnClick(count) {
// 发送自定义事件
// (自定义事件的名称, 传递的参数)
this.$emit("addClick", count)
}
六. 动态绑定类名
<div v-for="(item, index) in arrs" :key="item">
<div
:class="{ active: index === currentIndex }"
@click="itemClick(index)"
>{{ item }}</div>
</div>
data() {
return {
currentIndex: 0,
}
},
methods: {
itemClick(index) {
this.currentIndex = index;
}
}
七. 插槽
1. 默认插槽
// 父组件
<show-message>
<button>按钮</button>
</show-message>
// 子组件
<div class="content">
<slot>
<!-- 没有传入任何内容时,显示插槽的默认内容 -->
<div>插槽的默认内容</div>
</slot>
</div>
2. 具名插槽
// 父组件
<show-message>
<template v-slot:left>
<button>返回</button>
</template>
<template v-slot:center>
<button>内容</button>
</template>
<template v-slot:right>
<button>我的</button>
</template>
<button>默认插槽</button>
</show-message>
// 子组件
<div class="content">
<div class="left">
<slot name="left"></slot>
</div>
<div class="center">
<slot name="center"></slot>
</div>
<div class="right">
<slot name="right"></slot>
</div>
<div class="other">
<slot name="default"></slot>
</div>
</div>
3. 动态插槽名
// 可以通过修改name 的值来实现插槽绑定名字的变化
<template v-slot:[name]>
<button>按钮</button>
</template>
4. v-slot: 可以缩写成 #
// v-slot: 可以缩写成 #
<template #left>
<button>返回</button>
</template>
5. 作用域插槽
// 父组件
<show-message>
// <template v-slot="slotProps">
<template v-slot:default="slotProps">
<button>{{ slotProps.item }}</button>
</template>
</show-message>
// 子组件
<div class="content">
<slot :item="item" abc="cba"></slot>
</div>
八. Provide 和 Inject(非父子组件间的通信 祖先组件之间)
- 将props 沿着组件链逐级传递下去
- 父组件不需要知道哪些子组件使用它roovide 的property
- 子组件不需要知道inject 的property 来自哪里
- provide 也有对象的写法,但是不能通过this 绑定data 中的数据
- 函数写法可以通过this 绑定data 中的数据
- 箭头函数的this 指向provide 的this
- computed 函数包裹 意思是将this.name 成为响应式数据
- 即: this.name 发生改变 inject 拿到的name 值也会发生改变
// provide
export default {
// provide 也有对象的写法,但是不能通过this 绑定data 中的数据
// 函数写法可以通过this 绑定data 中的数据
// 箭头函数的this 指向provide 的this
// computed 函数包裹 意思是将this.name 成为响应式数据
// 即: this.name 发生改变 inject 拿到的name 值也会发生改变
provide() {
return {
name: computed(() => {
return this.name
}),
age: 18
}
}
}
// inject
<div>
{{ name.value }} - {{ age }}
</div>
export default {
inject: ["name", "age"]
}
九. 事件总线(非父子组件间的通信 任意组件之间)
// 发送
eventBus.emit("whyEvent", why, 18);
// 接收
eventBus.on("whyEvent", (name, age) => {
console.log(name, age);
})
// 移除监听
eventBus.off("whyEvent", this.offWhyEventHandler);
十. 生命周期
beforeCreate
created -> 1. 发送网络请求 2. 事件监听 3. this.$watch()
-> template 模板编译
beforeMount
-> 挂载到虚拟DOM -> 真实DOM -> 界面元素
mounted -> 元素已挂载、获取DOM、使用DOM
-> 数据更新
beforeUpdate
-> 根据最新数据生成新的VNode -> 新的虚拟DOM -> 新的真实DOM
updated
beforeUnmount
-> 将之前挂载在虚拟DOM 中的VNOde 从虚拟DOM 中移除
unmounted -> 取消事件监听、回收操作
十一. ref 引用
1. 引用元素
<div ref="divEl"></div>
this.$refs.divEl
2. 引用组件
<banner ref="banner"></banner>
// 获取子组件
this.$refs.banner
// 调用子组件的方法
this.$refs.banner.bannerClick();
// 获取子组件的元素
this.$refs.banner.$el (子组件最好只有一个根元素)
3. 获取当前组件的父组件 / 根组件
this.$parent
this.$root
十二. 动态组件
1. 定义动态组件
<component :is="currentTab"></component>
2. 动态组件传递数据
<component name="why"
:age="18"
@homeClick="homeCli"
:is="currentTab">
</component>
3. 动态组件的缓存
<keep-alive include="home, about"
exclude="category">
<component :is="currentTab">></component>
</keep-alive>
4. include 和 exclude 的值
string | RegExp | Array
"home, ablue" | 正则 | ['home', ' ablue']
5. 缓存的动态组件的生命周期
activated -> 活跃状态
deactivated -> 停用状态
十三. 异步导入文件, 利于SSR 优化,首屏加载优化
1. 同步导入js 文件
import math from './math'
2. 异步导入js 文件
import("./math").then(res => {
res.sum(20, 30)
})
3. 异步导入vue 文件
import { defineAsyncComponent } from 'vue'
const AsyncCategory = defineAsyncComponent(
() => import("./category.vue")
)
components: { category: AsyncComponent };
十四. 组件的 v-model
1. 默认绑定 modelValue
// 父组件
<counter v-model="appCounter"></counter>
// v-model 的本质
<counter v-bind:modelValue="appCounter"
v-on:update:modelValue="appCounter=$event">
</counter>
// 子组件
props: {
modelValue: {
type: Number,
default: 0
}
},
emits: ["update:modelValue"],
this.$emit("update:modelValue", 10)
2. 自定义的绑定
// counter
<counter v-model:counter="appCounter"></counter>
props: ["counter"],
emits: ["update:counter"]
this.$emit("update:counter", 10)
附:
- npm init vue @latest (vite 打包)