有 Vue2 的基础,笔记只记载之前不熟悉的知识
一、Vue 基本知识
1. Vue3 基本指令
1.1 v-pre
v-pre
用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签:
跳过不需要编译的节点,加快编译的速度;
<template>
<div>
<div v-pre>{{message}}</div>
<div>{{message}}</div>
</div>
</template>
- 使用
v-pre
,将不会渲染message
对应的内容,直接显示文本{{message}}
1.2 v-bind 用法
1.2.1 动态绑定属性名称
<template>
<div>
<div :[name]="value"></div>
<!-- 上述渲染后相当于下方 -->
<div abc="cba"></div>
</div>
</template>
<script>
export default {
data(){
return {
name: 'abc',
value: 'cba'
}
}
}
</script>
1.2.2 v-bind绑定一个对象
绑定对象后,会将对象解构,赋值到相应的标签上。
作用于组件时,可一次性将子组件需要的props进行传递
<template>
<div v-bind="info">哈哈哈哈</div>
<div :="info">哈哈哈哈</div>
<!-- 上述渲染后相当于下方 -->
<div name="fct" age="18" height="1.88">哈哈哈哈</div>
</template>
<script>
export default {
data() {
return {
info: {
name: "fct",
age: 18,
height: 1.88
}
}
}
}
</script>
1.3 v-for 中 key 的作用
主要是Diff算法运用
-
key
这个特殊的 attribute 主要作为 Vue 的 虚拟 DOM 算法 提示,在比较新旧节点列表时用于识别 vnode。 -
在没有
key
的情况下,Vue 将使用一种最小化元素移动的算法,并尽可能地就地更新/复用相同类型的元素。源码如图:
-
如果传了
key
,则将根据 key 的变化顺序来重新排列元素,并且将始终移除/销毁 key 已经不存在的元素。源码如图:
-
同一个父元素下的子元素必须具有唯一的 key。重复的 key 将会导致渲染异常。
2. 侦听器 watch
2.1 函数形式
ownName
为需要侦听的变量的名称,如:要侦听 data 中 userName 的改变,对应的 侦听器为 userName(new, old){}
。
但是当需要侦听的为对象或其他引用类型的值时,使用函数形式的侦听器只能侦听引用类型数据的地址改变,而不能侦听内部值的改变。
{
data() {
return {
userInfo: { userName: 'fct', age: "18" },
ownName: 'changqing'
}
},
watch: {
// 侦听 ownName
ownName(newValue, oldValue) {
// 处理逻辑
},
// 侦听 userInfo 对象
userInfo(newValue, oldValue) {
// 处理逻辑
},
// 侦听 userInfo 对象中的 userName的改变
"userInfo.userName": function(newValue, oldValue) {
// 处理逻辑
}
}
}
2.2 对象形式
- 相当于函数形式:
watch: {
userInfo: {
handler(newValue, oldValue){
// 处理逻辑
}
}
}
- 深度侦听
watch: {
userInfo: {
handler(newValue, oldValue){
// 处理逻辑
},
deep: true, // 深度侦听,能侦听到对象内值的改变
}
}
- 立即执行(第一次渲染后就执行一次侦听器,而不是等到侦听的值改变再执行第一次)
watch: {
userInfo: {
handler(newValue, oldValue){
// 处理逻辑
},
deep: true, // 深度侦听,能侦听到对象内值的改变
immediate: true // 立即执行
}
}
2.3 $watch API
使用$watch
API来侦听:
- 第一个参数:侦听的源
- 第二个参数:侦听的回调函数callback
- 第三个参数配置选项对象:如deep、immediate
created(){
this.$watch('userInfo', (newValue, oldValue) => {
// 处理逻辑
},{
deep: true,
immediate: true
})
}
3. 组件
3.1 全局注册组件
// app 是全局根实例,APPObj是配置对象
const app = Vue.createApp(appObj);
// 全局注册组件
app.component('my-component', {
// 配置对象
})
二、Vue 组件化
1. $attrs
前提:当父组件传递参数给子组件时:
<son-component class="title" title="标题1" content="内容"></son-component>
对应的子组件有相应的props来接受title
和content
属性,而class属性属于非props属性,Vue默认会将非props属性传递给子组件的根元素来继承。而Vue3中组件可以不用设置根元素来包裹,所以当在子组件不设置根元素的话,vue控制台输出警告。
那如何消除警告?
- 给子组件设置根节点元素。
- 使用
$attrs
取捕获非props属性,并加以使用
<template>
<h2 :class="$attrs.class">陈平安</h2>
<p>{{ title }}</p>
<p>{{ content }}</p>
</template>
<script>
export default {
props: ['title', 'content'],
mounted() {
console.log(this.$attrs);
// { class: 'title' }
}
};
</script>
2.子组件与父组件通信
Vue3 和 Vue2有区别:
Vue3 需要提前注册声明自定义事件。可以使用数组或对象形式
export default { emits: ['自定义事件名称'], // 对象语法允许我们对触发事件的参数进行验证: emits: { '自定义事件名称1':null, '自定义事件名称2': (plaload1,....) => { // 通过返回值为 `true` 还是为 `false` 来判断 // 验证是否通过 } } }
父组件:
<template>
<div class="hello">
<h2>{{ count }}</h2>
<!-- 在子组件上注册事件接收 -->
<count-operator @add="add" @reduce="reduce"></count-operator>
</div>
</template>
<script>
import CountOperator from './CountOperator.vue';
export default {
components: { CountOperator },
data() {
return {
count: 0
};
},
methods: {
add() {
this.count++;
},
reduce() {
this.count--;
}
}
};
</script>
子组件
<template>
<div>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script>
export default {
// 声明自定义事件
emits: ['add', 'reduce'],
methods: {
increment() {
// 触发自定义add
this.$emit('add');
},
decrement() {
// 触发自定义reduce
this.$emit('reduce');
}
}
};
</script>
3. 非父子组件通信
3.1 provide、inject
用于一些深度嵌套的组件,孙组件想要获取父组件的部分内容;
父组件有一个 provide
选项来提供数据;
孙组件有一个 inject
选项来开始使用这些数据;
3.1.1 组件结构
App.vue----->Home.vue----->HomeNavBar.vue
App.vue
export default {
provide: {
fct: '我是app组件'
}
}
HomeNavBar.vue
export default {
inject: ['fct']
}
3.1.2 provide 的函数形式
如果Provide
中提供的一些数据是来自data,那么我们可能会想要通过this来获取。
直接在provide对象中使用 this 会报错,是因为 provide 中的 this 指向的不是vue实例,而是当前vue组件的script标签的根this,而根 this 为 undefined。
要正确使用this,则需要更改provide为函数形式:
<script>
export default {
data() {
return {
names: ['a', 'b']
}
},
provide() {
return {
fct: '我是app组件',
length: this.names.length
}
}
}
</script>
3.1.3 处理响应式数据
在上例的基础上,当我们在names数组中新增数组项,而provide提供给孙组件的数据没有变化,不是响应式数据。
这时我们需要Vue提供的响应式函数来解决:computed
函数
<script>
import { computed } from 'vue'
export default {
data() {
return {
names: ['a', 'b']
}
},
provide() {
return {
fct: '我是app组件',
length: computed(() => this.names.length)
}
}
}
</script>
在孙组件中,取值需要通过.value
取值。因为computed
函数返回的是一个ref对象
。
3.2 全局事件总线 mitt库
Vue3从实例中移除了 $on、$off 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库:
-
Vue3官方有推荐一些库,例如
mitt
或tiny-emitter
; -
这里我们主要讲解一下
mitt
库的使用;
3.2.1 安装:
npm i mitt
3.2.2 使用:
- 封装工具
eventbus.js
import mitt from 'mitt';
const emitter = mitt();
export default emitter;
- 触发事件
App.vue
<script>
import emitter from './utils/eventBus';
export default {
methods: {
clickEvent() {
emitter.emit('fct', { name: 'fct' });
}
}
};
</script>
- 监听事件
其他组件
<script>
import emitter from './utils/eventBus';
export default {
created() {
// 监听单一事件
emitter.on('fct', (data) => {
console.log('fct-', data);
});
// 监听所有事件
emitter.on('*', (type, data) => {
console.log('* event', type, data);
});
},
};
</script>
- Mitt事件的取消
// 取消mitter中所有的监听
emitter.all.clear()
// 定义一个函数
function onFoo() {}
emitter.on('foo', onFoo); // 监听
emitter.off('foo', onFoo); // 取消监听
4. 插槽
5.动态组件
动态组件有时会配合
keep-alive
使用,因为当使用<component :is="...">
来在多个组件间作切换时,被切换掉的组件会被卸载。通过 KeepAlive组件 强制被切换掉的组件仍然保持“存活”的状态。
6. 异步组件
常用:
import { defineAsyncComponent } from 'vue'
const AsyncComp = defineAsyncComponent(() =>
import('./components/MyComponent.vue')
)
搭配 Suspense 使用
异步组件可以搭配内置的 <Suspense>
组件一起使用, Suspense 中查看。
可进行设定异步组件加载失败后展示的组件
7. $refs、$parent、$root
$refs
获取在template模板中设置有ref属性的标签或组件。
<!-- 模板引用 -->
<input ref="input">
<script>
this.$refs.input.focus()
</script>
$parent
获得当前组件的父组件的引用。
$root
获得当前组件的所在的根组件。
Vue3已经移除
$children
属性
8.组件的v-model
标签:vue,default,笔记,学习,export,Vue3,组件,model,modelValue From: https://www.cnblogs.com/fuct/p/17010984.html