内容 | 参考链接 |
---|---|
Vue基本使用 | Vue的基本使用(一文掌握Vue最基础的知识点) |
Vue通信和高级特性 | Vue组件间的通信及高级特性(多种组件间的通信、自定义v-model、nextTick、插槽) |
Vue高级特性 | Vue的高级特性(动态组件、异步加载、keep-alive、mixin、Vuex、Vue-Router) |
Vue原理1 | Vue原理(理解MVVM模型、深度/监听data变化、监听数组变化、深入了解虚拟DOM) |
Vue原理2 | Vue原理(diff算法、模板编译、组件渲染和更新、JS实现路由) |
Vue面试题 | web前端面试高频考点——Vue面试题 |
props
常用于 父给子 传递数据this.$emit
常用于 子给父 传递数据event.$emit
常用于 兄弟组件间 传递数据示例:两个子组件(输入框组件&列表组件)动态添加和删除
父组件(index.vue)
@add
和 @delete
自定义事件<template>
<div>
<Input @add="addHandler" />
<List :list="list" @delete="deleteHandler" />
</div>
</template>
<script>
import Input from "./Input";
import List from "./List";
export default {
components: {
Input,
List,
},
data() {
return {
list: [
{
id: "id-1",
title: "标题1",
},
{
id: "id-2",
title: "标题2",
},
],
};
},
methods: {
// 添加项目
addHandler(title) {
this.list.push({
id: `id-${Date.now()}`,
title,
});
},
// 删除项目
deleteHandler(id) {
this.list = this.list.filter((item) => item.id !== id);
},
},
// 创建
created() {
console.log("index created");
},
// 挂载
mounted() {
console.log("index mounted");
},
// 更新前
beforeUpdate() {
console.log("index before update");
},
// 更新
updated() {
console.log("index updated");
},
};
</script>
子组件(input.vue)
this.$emit('add', this.title)
调用父组件的事件event.$emit("onAddTitle", this.title)
调用自定义事件(兄弟组件定义的事件)<template>
<div>
<input type="text" v-model="title" />
<button @click="addTitle">add</button>
</div>
</template>
<script>
import event from "./event";
export default {
data() {
return {
title: "",
};
},
methods: {
addTitle() {
// 调用父组件的事件
if (this.title.trim() !== "") {
this.$emit("add", this.title);
// 调用自定义事件
event.$emit("onAddTitle", this.title);
this.title = "";
} else {
alert('输入内容不能为空')
}
},
},
};
</script>
子组件(List.vue)
this.$emit("delete", id)
调用父组件的事件,根据 id,进行删除 event.$on("onAddTitle", this.addTitleHandler)
挂载(mounted)的时候绑定自定义事件event.$off("onAddTitle", this.addTitleHandler)
销毁前(beforeDestroy)的时候销毁自定义事件<template>
<div>
<ul>
<li v-for="item in list" :key="item.id">
{{ item.title }}
<button @click="deleteItem(item.id)">删除</button>
</li>
</ul>
</div>
</template>
<script>
import event from "./event";
export default {
// props: ['list']
props: {
// prop 类型和默认值
list: {
type: Array,
default() {
return []
}
},
},
methods: {
deleteItem(id) {
this.$emit("delete", id);
},
addTitleHandler(title) {
console.log("on add title", title);
},
},
created() {
console.log("list created");
},
mounted() {
console.log("list mounted");
// 绑定自定义事件
event.$on("onAddTitle", this.addTitleHandler);
},
beforeUpdate() {
console.log("list before update");
},
updated() {
console.log("list updated");
},
beforeDestroy() {
// 及时销毁,否则可能造成内存泄露
event.$off("onAddTitle", this.addTitleHandler);
},
};
</script>
event.js 文件
$emit
,$off
,$on
等方法import Vue from 'vue'
export default new Vue()
分割线 -----------------------------------------------------------------------------------------------------------
分割线 -----------------------------------------------------------------------------------------------------------
分割线 -----------------------------------------------------------------------------------------------------------
生命周期详解【参考链接】
参考 props 和 $emit 的示例的结果,总结父子组件生命周期如下:
01.父组件 before create
02.父组件 created
03.父组件 before mount
04.子组件 before create
05.子组件 created
06.子组件 before mount
07.子组件 mounted
08.父组件 mounted
09.父组件 before update
10.子组件 before update
11.子组件 updated
12.父组件 updated
13.父组件 before destroy
14.子组件 before destroy
15.子组件 destroyed
16.父组件 destroyed
自定义 v-model,$nextTick,slot,动态、异步组件,keep-alive,mixin
示例:自定义实现 v-model
CustomVModel.vue 子组件
<template>
<input
type="text"
:text="text1"
@input="$emit('change1', $event.target.value)"
/>
</template>
<script>
export default {
name: "CustomVModel",
model: {
prop: "text1", // 对应 props text1
event: "change1",
},
props: {
type: String,
default() {
return "";
},
},
};
</script>
index.vue 父组件
<template>
<div>
<p>vue 高级特性</p>
<hr />
<p>{{ name }}</p>
<CustomVModel v-model='name'/>
</div>
</template>
<script>
import CustomVModel from "./CustomVModel.vue";
export default {
name: "index",
components: { CustomVModel },
data() {
return {
name: '杂货铺'
}
}
};
</script>
示例:添加子节点,并获取子节点的总长度
NextTick.vue 组件
this.$nextTick(() => {...})
为异步渲染,待 DOM 渲染完再回调$nextTick
则输出的结果是 3<template>
<div>
<ul ref="ul1">
<li v-for="(item, index) in list" :key="index">
{{ item }}
</li>
</ul>
<button @click="addItem">添加一项</button>
</div>
</template>
<script>
export default {
name: "NextTick",
data() {
return {
list: ["a", "b", "c"],
};
},
methods: {
addItem() {
this.list.push(`${Date.now()}`);
this.list.push(`${Date.now()}`);
this.list.push(`${Date.now()}`);
// 异步渲染,$nextTick 待 DOM 渲染完再回调
// 页面渲染时会将 data 的修改做整合,多次 data 修改只会渲染一次
this.$nextTick(() => {
// 获取 DOM 元素
const ulElem = this.$refs.ul1;
console.log(ulElem.childNodes.length); // 6
});
},
},
};
</script>
html
结构
标签体内为默认内容,即父组件没设置内容时,这里显示示例:默认插槽的基本使用
index.vue 父组件
{{ website.title }}
是子组件插槽中要呈现的内容<template>
<div>
<p>vue 高级特性</p>
<hr />
<SlotDemo :url="website.url">
{{ website.title }}
</SlotDemo>
</div>
</template>
<script>
import SlotDemo from "./SlotDemo.vue";
export default {
components: { SlotDemo },
data() {
return {
website: {
url: "http://baidu.com/",
title: "Baidu",
subTitle: "百度",
},
};
},
};
</script>
SlotDemo.vue 子组件
<template>
<a :href="url">
<slot>
默认内容,即父组件没设置内容时,这里显示
</slot>
</a>
</template>
<script>
export default {
props: ['url'],
};
</script>
分割线 -----------------------------------------------------------------------------------------------------------
示例:显示子组件的 title,使用父组件的链接
index.vue 父组件
标签内使用 v-slot 绑定自定义属性 slotProps<template>
<div>
<p>vue 高级特性</p>
<hr />
<ScopedSlot:url="website.url">
<template v-slot="slotProps">
{{ slotProps.slotData.title }}
</template>
</ScopedSlot>
</div>
</template>
<script>
import ScopedSlot from "./ScopedSlot.vue";
export default {
components: { ScopedSlot},
data() {
return {
website: {
url: "http://baidu.com/",
title: "Baidu",
subTitle: "百度",
},
};
},
};
</script>
ScopedSlot.vue 子组件
标签内自定义动态属性 slotData,绑定 data 中的 website<template>
<a :href="url">
<slot :slotData="website">
{{ website.subTitle }}
</slot>
</a>
</template>
<script>
export default {
props: ["url"],
data() {
return {
website: {
url: "http://bilibili.com/",
title: "Bilibili",
subTitle: "哔哩哔哩",
},
};
},
};
</script>
中使用 name='xxx'
给插槽命名
中使用 v-slot:xxx
或者 #xxx
对应子组件的插槽示例:具名插槽的使用
index.vue 父组件
中使用 v-slot:xxx
或者 #xxx
对应子组件的插槽<template>
<div>
<p>vue 高级特性</p>
<hr />
<NamedSlot>
<template v-slot:header>
<h4>将插入到 header slot 中</h4>
</template>
<p>将插入到 main slot 中,即未命名的 slot</p>
<template #footer>
<p>将插入到 footer slot 中</p>
</template>
</NamedSlot>
</div>
</template>
<script>
import NamedSlot from "./NamedSlot.vue";
export default {
components: { NamedSlot }
};
</script>
NamedSlot.vue 子组件
中使用 name='xxx'
给插槽命名<template>
<div>
<header>
<slot name="header">默认头部</slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer">默认尾部</slot>
</footer>
</div>
</template>
<script>
export default {};
</script>
不积跬步无以至千里 不积小流无以成江海
点个关注不迷路,持续更新中…