一. Vue2 篇
1.MVC MVVM区别
首先呢这是两种模式
MVC指的是 modal,view, controller
MVVM 指的是 modal ,view, view modal
mvc和mvvm区别是:1、处理业务的模式不同,MVC里,View是可以直接访问Model,而MVVM是将页面与数据逻辑分离的模式,它把数据绑定工作放到一个JS里去实现;2、处理数据操作不同,MVVM通过数据来显示视图层而不是节点操作。
2. vue的优点
采用MVVM框架,我们只需要关注对数据的修改就好,提供大量api,减少我们对dom的直接操作。采用spa页面,用户体验更佳。减轻服务器压力(服务器不需要发送html页面,只需要发送数据即可)。提供虚拟dom,减轻页面渲染压力。
3. vue组件间传值
(1)父传子
<son :data="data"/>
props接
(2)子传父
<son @getData="getData">
this.$emit("getData",data)
(3) 兄弟传
发布订阅模式
事件总线
4. v-show和v-if
就是是否显示和是否销毁。
实现本质方法区别
v-show本质就是标签display设置为none,控制隐藏
v-if是动态的向DOM树内添加或者删除DOM元素
编译的区别
v-show其实就是在控制css
v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件
编译的条件
v-show都会编译,初始值为false,只是将display设为none,但它也编译了
v-if初始值为false,就不会编译了
性能
v-show只编译一次,后面其实就是控制css,而v-if不停的销毁和创建,故v-show性能更好一点。
5. 常见的vue指令
v-on / :绑定事件
v-for :循环渲染
v-modal:双向绑定
v-if:显示或者销毁(就是css里的display是不是none的问题)
v-show:是否展示(只是显示或者隐藏,而不是销毁)
v-bind:绑定数据
6. 数据响应式原理(vue2,vue3的与此有差异)
在vue2中,对数据的代理主要
什么是响应式,也即是说,数据发生改变的时候,视图会重新渲染,匹配更新为最新的值。
Object.defineProperty 为对象中的每一个属性,设置 get 和 set 方法,每个声明的属性,都会有一个 专属的依赖收集器 subs,当页面使用到 某个属性时,触发 ObjectdefineProperty - get函数,页面的 watcher 就会被 放到 属性的依赖收集器 subs 中,在 数据变化时,通知更新;
当数据改变的时候,会触发Object.defineProperty - set函数,数据会遍历自己的 依赖收集器 subs,逐个通知 watcher,视图开始更新;
原文链接:https://blog.csdn.net/qq_44182284/article/details/111191455
下面写一个实例
用obj2代理obj1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let obj1 = { a: 1, b: 2 }
let obj2={c:3}
Object.defineProperty(obj2, "a", {
get() {
return obj1.a
},
set(value) {
obj1.a = value
}
})
console.log(obj2);
</script>
</body>
</html>
我们可以看到obj2为
除了本身的c:3属性外,还有我们代理的a属性,并且有get和set方法,我们可以在调试工具中修改obj2.a=5
此时查看obj1
发现obj1的a也变成了5,这就是一波简单的代理。或者我们修改obj1.a=10
再查看obj2
发现obj2的a也变成了10,这就是双向绑定。
但是该绑定模式在vue2中是有缺点的,他对于数组和对象的修改有时候会出现问题,最典型的就是根据索引修改数组信息或者对象信息。直接修改对于vue来说是不会及时响应的,我们需要的是使用vue.$set(源,索引,修改值)或者$nextTick强制更新才行。
7. vue2 解决修改数组对象时数据代理问题
除了上面说到的nextTick和$set, 其实vue帮我们重写了数组的那七大方法,例如push,pop,shift,unshift,splice等等。通过这些方法修改数组,vue就可以及时响应并更新页面。
8. data是函数的问题
我们自己在连续vue时,在一个html文件中引入vue.js 我们发现data可以是对象的形式,也可以是函数的形式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="./js/vue.js"></script>
</head>
<body>
<div id="root">
<h1>{{name}}</h1>
</div>
<script>
// 阻止vue产品提示
Vue.config.productionTip = false
// 创建vue实例
const x = new Vue({
//控制接管容器
// el: '#root',
// data 第一种写法
// data: {
// name: 'test1'
// }
// data 第二种写法
data:function(){
return{
name:"test1",
testObj:{
name1:"111",
name2:'2222'
}
}
}
})
// 另一个绑定方式
x.$mount('#root')
console.log(x);
</script>
</body>
</html>
但是在脚手架中开发时为什么都要使用函数方式呢。
原因是对象是引用数据类型。如果以对象形式写,会造成声明空间的污染,不同组件之间data数据的干扰。所以要使用函数返回的方式。
9. watch和computed的区别
计算属性computed :
(1)、支持缓存,只有依赖数据发生改变,才会重新进行计算
(2)、不支持异步,当computed内有异步操作时无效,无法监听数据的变化
(3)、computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
(4)、如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
(5)、如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
(1)、不支持缓存,数据变,直接会触发相应的操作;
(2)、watch支持异步;
(3)、监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
(4)、当一个属性发生变化时,需要执行对应的操作;一对多;
(5)、监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行, deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。注意:deep无法监听到数组的变动和对象的新
增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
10. 生命周期(超级重要)
生命周期其实就是在vue组件生成挂载以及销毁过程中一系列的关键时间节点,vue给我们提供各种对应时间节点的回调函数(也叫钩子函数)来执行我们需要的逻辑。
直接上图
通俗来讲,先创建created(主要就是数据初始化),再挂载,也就是mounted(dom操作)。数据更新走updata,销毁组件走destroyed。然后再加上他们的before就是所有的钩子。
这里最常考的就是:对于数据初始化,最好再created钩子里进行,对dom操作,最好再mounted里操作。
还有一些特殊的钩子,比如路由的钩子
// 路由的钩子
activated() {
this.timer = setInterval(() => {
console.log("@");
}, 1000);
console.log("被激活了");
},
deactivated() {
console.log("不看了",this);
clearInterval(this.timer);
},
第一个是通过路由进入显示该组件时调用
第二个是通过路由离开该组件时调用
11. 路由
基本情况
vue的路由通过监视我们浏览器地址栏的变化决定展示什么组件内容。
分为两种模式:hash模式和history模式
hash模式(默认):每次点击跳转后我们的地址栏会有一个#
注意#后的任何数据都不会被发送到服务器。
history模式:每次跳转就和我们普通的页面跳转类似,地址栏后面不会有#,这种情况下的地址会被发送到服务器,在部署时需要特殊解决一下。
路由的基本格式如下
import VueRouter from "vue-router";
import page1 from '../components/Page1'
import page2 from '../components/Page2'
import page1son from '../pages/Page1son'
import page2son from '../pages/Page2son'
//默认是hash模式 可以设置history
const router = new VueRouter({
mode: 'history',
routes: [
{
name: 'Page1',
path: '/Page1',
component: page1,
children: [
{
name: 'page1son',
path: 'page1son',
component: page1son,
// props:{a:11111,b:'ccc'},
// 这样所有param的参数就会以props传过去
// props:true,
props() {
return { id: ' query.id', title: 'query.title' }
},
// //独享路由
// beforeEnter:(to,from,next)=>{
// }
}
]
},
{
name: 'page2',
path: '/Page2',
component: page2,
meta: { isAuth: true },
children: [
{
path: 'page2son',
component: page2son,
}
]
},
{
name: 'selectList',
path: '/selectList',
component: () => import(/* webpackChunkName: "about" */ '../components/selectList.vue'),
}
]
})
// 全局前置路由守卫
// router.beforeEach((to, from, next) => {
// if (to.meta.isAuth == true) {
// alert("需要权限");
// next()
// } else {
// console.log("路由调用", to, from, next);
// next()
// }
// })
// // 全局后置路由守卫
// router.afterEach((to, from) => {
// console.log(to.name, from.name);
// document.title=to.name
// })
export default router
实现跳转的方式
第一种
<router-link
replace
:to="{ path: '/page1/page1son', query: [(id = 1111), (title = data)] }"
>page1-child</router-link
>
<router-view></router-view>
to就是跳转的地方,下面是跳转后组件展示的区域。
第二种
this.$router.push({ path: "/page1/page1son" });
一个效果,这个就是把地址push到了history的栈里
路由守卫
// 全局前置路由守卫
router.beforeEach((to, from, next) => {
if (to.meta.isAuth == true) {
alert("需要权限");
next()
} else {
console.log("路由调用", to, from, next);
next()
}
})
// 全局后置路由守卫
router.afterEach((to, from) => {
console.log(to.name, from.name);
document.title=to.name
})
分为前置守卫,后置守卫
前置守卫负责确定权限或者做一些跳转前的初始化处理,主要三个参数,到哪来,从哪去,能不能继续,能就调用next()
后置守卫主要就是改个文档标题啥的,不算特别重要。
当然还有组件内置守卫
//组件内路由
beforeRouteEnter(to, from, next) {
console.log("刚进", to, from);
next();
},
beforeRouteLeave(to, from, next) {
console.log("走", to, from);
next();
},
很好理解,来之前干嘛,离开前干嘛,只不过是写在组件内的。
12. vuex
主要是状态管理,通俗说就是如果多个组件会处理同一个数据,那么可以用vuex集中管理
首先三个状态 Actions Mutations State
Actions主要用来记录组件需要进行的动作,我们可以在里面进行判断等等操作
Mutations负责修改数据,而数据就统一存在State中。
组件调用Actions里的方法时,使用的是dispatch("函数名",参数)
Actions通知Mutations修改State时,调用的是commit("函数名",参数)
然后Mutations修改数据
data.sum += value
下面是代码实例
vuex的
import Vuex from 'vuex'
import Vue from 'vue'
// 用于响应动作
const actions = {
increment: function (context, value) {
console.log('收到的参数', context, value);
context.commit('increment', value)
}
}
// 用于操作数据
const mutations = {
increment: function (data, value) {
console.log("state中的数据", data, value);
data.sum += value
},
decrement(data,value){
data.sum-=value
}
}
//用于存储
const state = {
sum: 0
}
// 加工state中的数据
const getters ={
bigSum(state){
return state.sum*10
}
}
Vue.use(Vuex)
const store = new Vuex.Store({ actions, mutations, state, getters })
// 暴露store
export default store
组件中操作
<template>
<div>
<h1>当前求和值为:{{ sum }}</h1>
<h1>×10后的值为{{ bigSum }}</h1>
<select v-model.number="num">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="3">3</option>
</select>
<button @click="increment">+</button>
<button @click="decrement">-</button>
<button @click="oddincrement">当前求和奇数再加</button
><button @click="waitincrement">等一等再加</button>
</div>
</template>
<script>
import {mapState,mapGetters} from 'vuex'
export default {
name: "countvuex",
data() {
return {
num: 1,
};
},
computed:{
// 直接映射state中的数据
// ...mapState({he:'sum'})
// 不换名字映射
...mapState(['sum']),
...mapGetters(['bigSum'])
},
mounted(){
},
methods: {
increment() {
this.$store.dispatch("increment", this.num);
},
decrement() {
this.$store.commit("decrement", this.num);
},
oddincrement() {
if (this.sum % 2 == 1) {
this.sum = this.sum + this.num;
}
},
waitincrement() {
setTimeout(() => {
this.sum = this.num + this.sum;
}, 1000);
},
},
};
</script>
<style>
</style>
12.vue2双向绑定模拟
解释一下为什么会给input标签添加input事件,是因为v-modal本身就只是一个语法糖,它相当于
v-modal="valueA" <=> @input = "valueA=event.target.value"
当然如果是chexkbox它就对应@change事件
它只是帮我们完成修改标签数据的同时修改我们组件的data。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- 为什么要在标签里直接定义输入事件呢,其实v-modal本身就是个语法糖 -->
<input type="text" id="dom1" />
<input type="text" id="dom2" />
<script>
class Watcher {
constructor(dom, msg) {
this.dom = dom
this.msg = msg
}
update(data) {
this.dom.value = data
}
}
//其实就是个发布订阅
class Def {
constructor() {
this.subs = {}
}
//发布消息
publish(msg, data) {
if (this.subs[msg]) {
this.notice(msg, data)
}
}
subscribe(item) {
if (!this.subs[item.msg]) {
this.subs[item.msg] = []
}
this.subs[item.msg].push(item)
}
notice(msg, data) {
for (let item of this.subs[msg]) {
item.update(data)
}
}
}
class VM {
constructor(data, Watchers) {
this.data = data
this.def = new Def()
this.Watchers = Watchers
}
Observe() {
for (let key in this.data) {
Object.defineProperty(this, key, {
get() {
this.def.subscribe(this.WillUpdate)
return this.data[key]
},
set(newValue) {
//修改数据相同也会触发set,过滤一下。
if (newValue !== this.data[key]) {
this.data[key] = newValue
this.def.publish(key, this.data[key])
}
}
})
}
}
default() {
for (let item of this.Watchers) {
this.WillUpdate = item
item.dom.value = this[item.msg]
//就是v-modal语法糖的原理
item.dom.addEventListener("input", (e) => {
this[item.msg] = e.target.value
})
}
}
}
function data() {
return {
a: 111,
b: 222,
c: 'test',
}
}
const Watcher1 = new Watcher(document.getElementById("dom1"), "a")
const Watcher2 = new Watcher(document.getElementById("dom2"), "b")
let Watchers = [Watcher1, Watcher2]
const vm = new VM(data(), Watchers)
vm.Observe()
vm.default()
</script>
</body>
</html>
13. 自定义指令
直接看例子就懂了(实现指令控制字体颜色)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="../js/vue.js"></script>
</head>
<body>
<div id="root">
<div v-color="color">{{name}}</div>
</div>
<script>
const vm = new Vue({
el: "#root",
data() {
return {
name: '小明',
host: 'xxx',
color: "red"
}
},
directives: {
color(dom, obj) {
// 标签和v-test等于的值
console.log("@@@", dom, obj);
dom.style.color=obj.value
},
// // 完整写法
// fbind: {
// // 指令与标签结合
// bind(el, data) {
// },
// // 标签挂到页面上
// inserted(el, data) {
// },
// // 标签更新
// update(el, data) {
// },
// }
}
})
console.log(vm);
</script>
</body>
</html>
效果图
二. Vue3
1. Vue3与Vue2的对比
(1)双向数据绑定的原理发生改变
vue2是Object.definpropetry,但是有个缺点就是vue2中的数据代理无法检测通过索引修改的数组,对象变化,不能及时的更新页面。vue3的原理是proxy,一个window自带的api,并且读取数据以及修改数据使用了反射接口,可以更好的检测数组对象的变化。(后面有详细说明)。
(2)标签变化
vue3的模板标签下可以有多个根标签,而vue2只能有一个根标签。
(3)Composition API
Vue2与Vue3 最大的
区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
直接给例子
vue2
<template>
<div>
<div class="father">我是父组件 {{ sondata }} {{ sondata1 }}</div>
<son :testf1="testf1" @senddata1="senddata1">
<!-- <template scope="data1">
<div class="slotdemo">我是插槽插进去的:{{ data1.data1 }}</div>
</template> -->
</son>
<son2 />
</div>
</template>
<script>
import son from "./son.vue";
import son2 from "./son2.vue";
export default {
name: "father",
components: {
son,
son2,
},
data() {
return {
tip: "father",
sondata: "",
sondata1: "",
};
},
methods: {
senddata1(e) {
this.sondata1 = e;
console.log(e);
},
testf1(val) {
console.log("son 的数据: ", val);
this.sondata = val;
},
},
};
</script>
<style scoped>
.father {
width: 200px;
height: 200px;
background-color: bisque;
}
.slotdemo {
width: 200px;
height: 200px;
background-color: red;
}
</style>
选项类型api就是需要什么写什么。需要data,就把数据都放在data里,需要定义方法时间,就都写在methods里。
vue3
<template>
<!-- 现在把所有的标签都保管在一个fragment虚拟根标签中 -->
<button @click="tpshow = !tpshow">tpshow</button>
<teleport to="body">
<div v-if="tpshow">11111111111</div>
</teleport>
<h1 @click="say">{{ name }}--{{ fullname }}</h1>
<input v-model="fullname" />
<p>{{ age }}</p>
<p>我是a---{{ a }}</p>
<button @click="age++">sum+1</button>
<button @click="obj.a++">a+1</button>
<button @click="obj.c.test = '111'">
{{ obj.c }}数据使用markraw非响应式属性
</button>
<input v-model="myRefData" />
<p>{{ myRefData }}</p>
</template>
<script>
// import { h } from "vue";
import {
ref,
toRefs,
reactive,
computed,
watch,
watchEffect,
toRef,
toRaw,
markRaw,
customRef,
provide,
inject,
isReactive,
onMounted,
getCurrentInstance,
} from "vue";
export default {
name: "SetUp",
props: ["TmdData"],
// setup在beforecreat之前调用 this是undefined
setup(props, context) {
const { proxy } = getCurrentInstance();
console.log("props", props);
console.log("context", context);
onMounted(() => {
console.log(proxy, "@@@@@@@@@@@@@@");
console.log("生成setup组件");
});
let name = "1111";
let tpshow = ref(false);
//ref底层还是vue2那一套 响应数据
let age = ref(18);
//底层是proxy----------------------------------------
let obj = reactive({
a: 111,
b: 2222,
});
//----------------------------------------------------
// 这些is的就是用来判断的
console.log(isReactive(obj), "判断是不是reactive的");
//----------------------------------------------------
// 给自己的后代传数据
provide("age", age);
// 收provide的数据
let injectdata = inject("age");
//----------------------------------------------------
// 自定义ref
let myRefData = myRef("hello");
function myRef(value) {
//来一手防抖
let timer;
return customRef((track, trigger) => {
return {
get: function () {
//模板重新解析后追踪该数据变化
track();
return value;
},
set: function (newval) {
clearTimeout(timer);
timer = setTimeout(() => {
console.log("newval", newval);
value = newval;
//重新解析模板
trigger();
}, 1000);
},
};
});
}
// ---------------------------------------------------
//toRef在读取已有数据时创造响应式对象,包括toref 就是为了页面使用的时候舒服点直接
//越过前缀 比如state.a
let direA = toRef(obj, "a");
let A = obj.a;
console.log("toRef", direA, A);
//让添加对象的属性为非响应式
obj.c = markRaw({ test: "test" });
// ------------------------------------------------------
// 输出原生变量非代理
console.log("old", obj, "new", toRaw(obj));
//----------------------------------------------------------
// 计算属性
//1. 简写情况是只读的 无法修改
let fullname = computed(() => {
return obj.a + obj.b;
});
//2. 完整写法
let fullage = computed({
get() {
return obj.a;
},
set(val) {
obj.a = val;
},
});
// 监视多个用数组
//坑 监视reactive代理对象时读不到老的值 并且此时自动为deep
watch(
[age, obj],
(newval, oldval) => {
console.log("变化", newval, oldval);
},
{ immediate: true }
);
//只监视reactive中的一个值的变化
watch(
() => obj.a,
(newval, oldval) => {
console.log("a变化", newval, oldval);
}
);
function say() {
age.value = 19;
console.log(age, name);
}
// 全监视 看回调用了谁就监视谁
watchEffect(() => {
console.log("执行了watchEffect", obj.a);
});
return {
myRefData,
obj,
name,
age,
say,
...toRefs(obj),
fullname,
fullage,
direA,
A,
tpshow,
};
//渲染函数
// return () => {
// return h("h1",'33333');
// };
},
};
</script>
<style>
</style>
大家都写在setup大舞台中。
(4). 生命周期钩子
Vue2--------------vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
————————————————
版权声明:本文为CSDN博主「star@星空」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43638968/article/details/108800361
这个就直接复制了,可以看出来比较好理解,除了create都归setup()管以外,其他的就是在2的基础上多了一个on。然后on后第一个字母大写。最后就是destroyed改名为unmount,其实就是卸载的意思,比毁灭销毁贴切点。
2. Vue3数据代理
先上示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="logProxy()">输出源对象与代理对象</button>
<script>
let person = {
name: 'zs',
age: 18,
}
//vue2 响应式
// let p = {}
// Object.defineProperty(p, 'name', {
// //可配置的
// configurable: true,
// get() {
// return person.name
// },
// set(val) {
// person.name = val
// console.log("修改数据为", val);
// }
// })
//vue3底层
const p = new Proxy(person, {
get(target, propName) {
console.log(target, propName);
return Reflect.get(target, propName)
},
set(target, propName, value) {
console.log(target, propName, value, "111");
// target[propName] = value
Reflect.set(target, propName, value)
},
deleteProperty(target, propName) {
delete target[propName]
return Reflect.deleteProperty(target, propName)
}
})
//通过reflect来操作源对象
function logProxy() {
console.log("源对象", person, "代理对象", p);
}
</script>
</body>
</html>
可以看出来明显的区别就是,proxy代替Object.defineProperty。获取,设置,删除数据用的都是Reflect反射api。
为什么使用反射呢
bject上的一些属性,reflect也有
比如给object定义相同属性名,会导致代码单线程卡住,阻塞下面代码运行
例如让obj代理两个c属性 一个是obj1的c。一个是obj2的c。
那么就报错
但是使用反射后,就不会直接保错,而是通过返回的布尔值知道是否成功。
虚拟dom
用普通js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
我们先根据真实DOM生成一颗virtual DOM,当virtual DOM某个节点的数据改变后会生成一个新的Vnode,然后Vnode和oldVnode作对比,发现有不一样的地方就直接修改在真实的DOM上,然后使oldVnode的值为Vnode。
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁。
————————————————
版权声明:本文为CSDN博主「田野啸风」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44439675/article/details/116461376
vue用到的设计模式
1.订阅者发布者模式 2.Mvvm 3. 工厂模式
vue父组件子组件的生命周期执行顺序
Vue 的父组件和子组件生命周期执行顺序可以理解为以下 4 点:
加载渲染过程
父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
子组件更新过程
父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
父组件更新过程
父 beforeUpdate -> 父 updated
销毁过程
父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
————————————————
版权声明:本文为CSDN博主「没有码力」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45272820/article/details/120450822
$nextTick有什么用?
- Vue是异步渲染的框架。
- data改变之后,DOM不会立刻渲染。
- $nextTick会在DOM渲染之后被触发,以获取最新的DOM节点。
- 连续多次的异步渲染,$nextTick只会执行最后一次渲染后的结果。