MVC 和 MVVM 区别
MVC
controller 控制层将数据层 model 层 的数据处理后显示在视图层 view层,同样视图层 view层 接收用户的指令也可以通过控制层 controller,作用到数据层 model
MVVM
隐藏了 controller 控制层,直接操控 View 视图层和 Model 数据层。MVC 的视图层和数据层交互需要通过控制层 controller 属于单向链接。MVVM 隐藏了控制层 controller,让视图层和数据层可以直接交互 属于双向连接
controller 控制层将数据层 model 层 的数据处理后显示在视图层 view层,同样视图层 view层 接收用户的指令也可以通过控制层 controller,作用到数据层 model
MVVM
隐藏了 controller 控制层,直接操控 View 视图层和 Model 数据层。MVC 的视图层和数据层交互需要通过控制层 controller 属于单向链接。MVVM 隐藏了控制层 controller,让视图层和数据层可以直接交互 属于双向连接
Vue的事件绑定原理
Vue中通过v-on或其语法糖@指令来给元素绑定事件并且提供了事件修饰符,基本流程是进行模板编译生成AST,生成render函数后并执行得到VNode,VNode生成真实DOM节点或者组件时候使用addEventListener方法进行事件绑定
为什么 data 是一个函数
组件中的 data 写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据,防止变量污染
Vue 组件间通信
(1)props / $emit 适用 父子组件通信
(2)$parent / $children 适用 父子组件通信
(3)EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信
(4)$attrs/$listeners 适用于 隔代组件通信
(5)provide / inject 适用于 隔代组件通信
(6)Vuex 适用于 父子、隔代、兄弟组件通信
(7)通过$refs获取组件实例
(2)$parent / $children 适用 父子组件通信
(3)EventBus ($emit / $on) 适用于 父子、隔代、兄弟组件通信
(4)$attrs/$listeners 适用于 隔代组件通信
(5)provide / inject 适用于 隔代组件通信
(6)Vuex 适用于 父子、隔代、兄弟组件通信
(7)通过$refs获取组件实例
父组件如何监听到子组件的生命周期
(1)通过 $emit 触发父组件的事件
// Parent.vue
<Child @mounted="doSomething"/>
<script>
// Child.vue
mounted() {
this.$emit("mounted");
}
</script>
(2)通过hook来监听
// Parent.vue
<Child @hook:mounted="doSomething" ></Child>
vue-router 路由模式有几种
- hash模式
使用 URL hash 值来作路由。 - history
依赖 HTML5 History API - abstract
支持所有 JavaScript 运行环境,如 Node.js 服务器端
如果发现没有浏览器的 API,路由会自动强制进入这个模式
Vue 数据双向绑定
- 实现一个监听器 Observer:
对数据对象进行遍历,包括子属性对象的属性
利用 Object.defineProperty() 对属性都加上 setter 和 getter
这样的话,给这个对象的某个值赋值,就会触发 setter,那么就能监听到了数据变化 - 实现一个解析器 Compile:
解析 Vue 模板指令,将模板中的变量都替换成数据,然后初始化渲染页面视图
并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者
一旦数据有变动,收到通知,调用更新函数进行数据更新 - 实现一个订阅者 Watcher:
Watcher 订阅者是 Observer 和 Compile 之间通信的桥梁
主要的任务是订阅 Observer 中的属性值变化的消息
当收到属性值变化的消息时,触发解析器 Compile 中对应的更新函数。 - 实现一个订阅器 Dep:
订阅器采用 发布-订阅 设计模式,用来收集订阅者 Watcher
对监听器 Observer 和 订阅者 Watcher 进行统一管理。
v-if 与 v-for 为什么不建议一起使用
v-for 和 v-if 不要在同一个标签中使用,因为解析时先解析 v-for 再解析 v-if。如果遇到需要同时使用时可以考虑写成计算属性的方式
props自定义验证
props: {
num: {
default: 1,
validator: function (value) {
// 返回值为true则验证不通过,报错
return [1, 2, 3, 4, 5].indexOf(value) !== -1
}
}
}
watch的immediate属性
比如平时created时要请求一次数据,并且当搜索值改变,也要请求数据,我们会这么写
created(){
this.getList()
},
watch: {
searchInputValue(){
this.getList()
}
}
使用immediate完全可以这么写,当它为true时,会初始执行一次
watch: {
searchInputValue:{
handler: 'getList',
immediate: true
}
}
computed实现传参
new Vue({
el: "#app",
data() {
return {
params: {
name: '杜恒',
age: 18
}
}
},
computed: {
total() {
// 通过返回一个高阶函数
return (arg) => {
return arg * 10
}
}
}
})
vue的hook的使用
我们常用的使用定时器的方式
export default{
data(){
timer:null
},
mounted(){
this.timer = setInterval(()=>{
console.log('1');
},1000);
}
beforeDestory(){
clearInterval(this.timer);
}
}
上面做法不好的地方在于:全局多定义一个timer变量,使用hook这么做:
export default{
methods:{
fn(){
const timer = setInterval(()=>{
console.log('1');
},1000);
this.$once('hook:beforeDestroy',()=>{
clearInterval(timer);
})
}
}
}
Vue的el属性和$mount优先级
如以下的情况,el的优先级会大于$mount
new Vue({
router,
store,
el: '#app',
render: h => h(App)
}).$mount('#root')
Vue中的动态指令和参数
<template>
<aButton @[someEvent]="handleSomeEvent()" :[someProps]="1000" />...
</template>
<script>
...
data(){
return{
...
someEvent: someCondition ? "click" : "dbclick",
someProps: someCondition ? "num" : "price"
}
},
methods: {
handleSomeEvent(){
// handle some event
}
}
</script>
相同的路由组件如何重新渲染
经常遇到的情况是,多个路由解析为同一个Vue组件。问题是,Vue出于性能原因,默认情况下共享组件将不会重新渲染,如果尝试在使用相同组件的路由之间进行切换,则不会发生任何变化
const routes = [
{
path: "/a",
component: MyComponent
},
{
path: "/b",
component: MyComponent
},
];
如果想要重新渲染,就需要使用key
<template>
<router-view :key="$route.path"></router-view>
</template>
xczczxcz czczx