一、MVC和MVVM
MVC
- Model, 数据模型
- View, 视图
- Controller, 控制器
MVVM
- Model
- View
- ViewModel
MVC强调数据和视图分离,通过Controller协调页面的更新,MVVM的特点是数据绑定,通过抽象ModelView层,把数据和视图关联,从而实现数据和视图的同步。
Vue中是如何进行数据绑定的?
// Mustache
<template>
<p>{{msg}}<p>
</template>
// v-model,双向绑定
<template>
<input v-model="msg">
</template>
二、.vue文件的语法
vue3.0提倡使用composition api,相比2.0的选项式更加灵活,不需要再按照选项式的语法书写代码,可以按照业务逻辑等自由组织代码,直接书写js代码,更加符合前端开发者的习惯。vue3是兼容vue2的。
选项式API
export default {
name: "HelloWorld",
props: {
msg: String,
},
data() {
return {
count: 0,
};
},
computed: {},
methods: {},
components: {},
};
组合式API
<script setup>
import { ref, reactive } from "vue";
const list = reactive([]); // 响应式数据
const add = () => {
list.push(Date.now());
};
</script>
三、Vue 模板的常见指令
- v-bind: value, 缩写:value
- v-model
- v-on: click, 缩写: @click
- v-show,通过display属性控制元素的显示和隐藏
- v-if,v-else-if,v-else
- v-for
- v-once, 组件和元素只渲染一次,后续数据变化不会重新渲染
- v-text
- v-pre, 跳过{{}}的编译,显示原始数据
- v-clock, 显示元素之前会先显示v-clock,直到元素渲染完成才会显示元素
四、生命周期
- beforeCreate, 开始创建组件实例,注册事件等,此时实例还没有初始完成,无法访问实例上的数据
- created, 实例初始完成,可以访问vue实例
- beforeMounted, 模板编译完成,生成虚拟DOM, 真实DOM还没有渲染
- mounted, DOM挂载完毕,可以操作DOM
- beforeUpdate, 响应式数据发生变化之后,已生成对应的虚拟DOM,还没有更新真实DOM
- updated, 响应式数据变化之后,DOM已经更新
- beforeDestory, 组件销毁之前调用,通常用来清除effect,如定时器、事件监听的清除。
- destoryed, vue实例销毁,与vue相关的事件监听等解绑 在vue3中beforeDestore和destoryed对应beforeUnmounted和unmounted
选项式api的生命周期
<script>
export default {
name: "Option",
beforeCreate() { },
created() { },
beforeMount() { },
mounted() { },
beforeUpdate() { },
updated() { },
beforeUnmount() { },
unmounted() { },
}
</script>
组合式api的生命周期
组合式API使用setup替代了create阶段,setup在beforeCreate和created之间调用,此时实例没有初始化完成,不能访问组件实例。
<script setup>
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted
} from "vue";
onBeforeMount(() => { });
onMounted(() => { });
onBeforeUpdate(() => { });
onUpdated(() => { });
onBeforeUnmount(() => { });
onUnmounted(() => { });
</script>
父子组件的生命周期
-
父子组件加载过程: 父组件beforeate、父组件created、父组件beforemount、子组件beforecreate、子组件created、子组件beforemount、子组件mounted、父组件mounted。
-
父子组件更新过程: 父组件beforeupdate、子组件beforeate、子组件updated、父组件updated。
原因:所有的子组件完成之后,父组件才算完成,所以父组件的mounted必须要在所有子组件mounted之后调用。之所以在父组件beforemounted之后就开始子组件的解析,是因为这一步之后已经得到了父组件的虚拟dom,可以向下深度遍历子组件了。
五、组件通信
1. 父组件通过props向子组件通信
// 子组件
<template>
<span>{{ props.count }}</span>
</template>
<script setup>
import { defineProps } from "vue";
const props = defineProps({
"count": {
type: Number,
required: true,
default: 0,
}
})
</script>
// 父组件
<template>
<UserCard :count="count" />
</template>
<script setup>
import { ref } from "vue";
import UserCard from "./components/UserCard";
const count = ref(0);
</script>
- 子组件通过$emit与父组件通信
// 父组件
<template>
<UserCard @message="message" />
</template>
<script setup>
import UserCard from "./components/UserCard";
const message = (msg) => {
alert(msg);
};
</script>
// 子组件
<template>
<button @click="sendMessage">发送当前时间给父组件</button>
</template>
<script setup>
import { defineEmits } from "vue";
const emit = defineEmits(["message"]);
const sendMessage = () => {
emit("message", Date.now());
}
</script>
其它: 事件总线、inject/provider、vuex、pinia、eventemitter。 vue3不再提倡使用事件总线,而是提倡使用eventemitter这样的三方库。
六、QA
6.1 为什么vue2中新增的对象属性不能触发响应式的页面更新,而vue3中可以?
vue2对使用definePropert对属性进行监听,只能监听到已有属性的修改。而vue3使用的ES6的proxy可以监听到对象的任何操作。
6.2 为什么data是一个函数不是一个对象?
为了做数据隔离,每个组件实例有单独的数据。