vue MVVM原理 ,生命周期,以及方法和数据传递

VUE官网:https://cn.vuejs.org/

• vue我们现在学习和使用的是第二代版本
• VUE是渐进式框架
• Vue是一个类
• 每当创建一个实例,就相当于创建一个viewModel监听器:可以监听对应视图和对应数据的相互改变
•  在框架中,框架没有直接操作真正的DOM,而是操作了虚拟的DOM(js对象),更改数据以后,就会更改虚拟的DOM,然后进行DOM-diff的对比,只需要把发生变化的那个地方进行替换,大大地提高了页面的性能
•  指令 : 以v-开头,放在行间属性上,有着特殊意义的一些词;就是指令;
•  VUE的dom渲染是异步的
• 在Vue中,想更新视图,一定要去更新数据;
• VUE项目优化参考网址:https://www.jianshu.com/p/1896789fc8a8

渐进式框架
• 渐进式:类库或者框架都是重量级的,里面包含很多方法,但是实际项目开发中,我们用不到这么多东西,所以在开啊他们的时候,会把功能按照模块进行单独开发,使用者可根据自身情况选择一个模块三个模块的导入使用
• vue:基础模块(基础语法、核心实现、组件开发、相关指令等都在这里)
• vue-router:构建SPA单页面应用的路由
• vuex:公共状态管理
• vue-cli: vue脚手架
• components: vue element、 iview、 vux. . .
• 这些东西就是vue全家桶

VUE是MVVM双向数据绑定的框架

• 参考网址:https://www.jianshu.com/p/ea201ccc9ba9
• 双向数据绑定的框架:VUE本身实现了数据和视图的相互监听影响
• MVC是单向数据绑定,数据更改可以渲染视图,但是视图更改没有更改数据,需要我们自己在控制层基于change事件实现数据的更改( REACT)
• m: model 数据层
• v: view 视图层(视图: 浏览器打开页面)
• vm:viewModel 实际上,数据层和视图层不能直接通信,需要通过vm进行数据传递,vm中有一个观察者,当model中数据发生改变以后,会通知视图进行对应的视图更新;当视图发生改变,vm也能监听到视图的变化,通过元素的DOM事件进行监听视图是否发生改变,如果改变,通知数据进行更改;
• 数据影响视图;当vue中的data数据发生改变,视图也会发生改变;
• 视图层改变: vm也会帮我们把数据重新更改

MVVM的实现原理

• vue实现过程:当打开网页时,视图层先加载,当加载到js的new Vue()时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行解析,初始化视图,并订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。当数据发生变化时,Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。
• 观察者-订阅者(数据劫持,也就是mvvm的实现方式): 
• vueObserver 数据监听器,把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象(data)所有的属性,并使用Object.defineProperty()方法把这些属性全部转成setter、getter方法。当data中的某个属性被访问时,则会调用getter方法,当data中的属性被改变时,则会调用setter方法。
• Compile指令解析器,它的作用对每个元素节点的指令进行解析,替换模板数据,并绑定对应的更新函数,初始化相应的订阅。当数据发生变化之后,是observe通过Object.defineProperty进行监听到,通知对应的更新函数执行,视图就会更新。
• Watcher 订阅者,作为连接 Observer 和 Compile 的桥梁,能够订阅并收到每个属性变动的通知,执行指令绑定的相应回调函数。
• Dep 消息订阅器,内部维护了一个数组,用来收集订阅者(Watcher),数据变动触发notify 函数,再调用订阅者的 update 方法。

用Object.defineProperty方法,模拟实现v-model

    <div id="app">
        <input type="text" id="box">
    </div>
    <script>
        let box = document.getElementById("box");
        // 数据影响视图
        let  obj = {};// 用来存储数据的一个对象;
        Object.defineProperty(obj,"val",{
            get:function(){
                // 这是一个函数,不是一个箭头函数
                return box.value;
            },
            set(newVal){
                //console.log(newVal);// 这个是obj的val的最新的值;
                box.value = newVal;
            }
        });
        // 视图影响数据==> DOM事件
        box.addEventListener("input",function(){
            // 触发这个事件的目的是更改obj的val的属性值
            obj.val = this.value;
        })
    </script>
</body>

VUE的指令

• 在使用指令时,会先找数据类型中的值,如果数据类型中没有,那么就去找data或methods中的属性名;如果没有,就报错
• 指令: v-开头,放在元素的行间属性,有着特殊意义的一些词;

写在vue实例参数对象里的属性

	• el : element 当前监听器监听的视图(基于querySelector获取),代表Vue的语法的范围,相当于获取dom元素
	• data : 当前监听器监听的数据(这些监听的数据会挂载到vm实例上,也就是vm.msg=xxx来操作了),data可以传一个对象,或者传一个函数return一个对象,如果是函数,函数中的this指向vue实例
	• data中的数据如果数组中某一项发生改变,不能引起视图的更新;如果是对象的属性名对应的属性值更新,会引发视图的更新;
	• 数组内置的方法,能够引发原数组发生变化,可以引发视图的更新
	• methods : 这里面存储的是键值对。给元素绑定的事件的方法,需要放在methods中,methods中的方法名不能和data中属性重名(因为vue会先到data中查找属性,data没有才会来methods查找,如果data中有这个属性,那么就会采用data的属性值),事件函数中的this指向当前vue的实例,事件函数可以传参
	• filters : 过滤器:把需要再视图中渲染的数据进行二次或多次的处理,里面方法第一个参数是需要过滤的数据,剩下的参是方法传的实参,页面显示的内容为filters里的方法的return的值(过滤器方法只能在胡子语法和v-bind中使用,过滤器中的方法没有挂载到实例上,this指向window)    
	• created : 这是一个钩子函数; 当new Vue时,没有渲染真实的DOM之前,会执行这个钩子函数created;请求到数据立即对data中的数据赋值,那么当编译DOM结构时,采用最新的数据编译;减少DOM的渲染;一般情况下;请求数据都是在created中执行获取数据,( 钩子函数中的this都指向vue的实例)
	• computed : 计算属性,在真实项目中,我们一般会用一个计算属性和某些响应式数据进行关联,响应式数据发生改变时,会立即执行get方法,并且重新计算当前最新的val值,最后重新渲染视图,否则使用的是上一次计算出来的缓存结果(computed中属性不能喝data重名,也不能和methods重名。computed :会默认走缓存,节省性能。this都指向vue的实例)
		• 如果computed中的属性值是函数,默认就是get;在函数中必须要关联一个响应式数据,否则这个函数只执行一次
		• computed中不支持异步;如果a的依赖数据是通过异步被更新的,那么a不能监听到最新发生的变化
		• 只要获取这个属性值就会触发get方法执行,会默认把get的值返回给这个属性值,get的参数是vue实例
		• 当设置更改这个属性值时,会默认执行set方法执行,set方法的形参代表的是当前属性值的最新的值
	• watch : 侦听属性;监听的是data的属性,当属性发生改变以后,会做的一些事情
		• 里面传一个函数,第一个参数是最新的值,第二个参是修改前的值
		• 深度监听: 如果监听了对象,当这个对象中的属性名对应的键值对发生改变以后,并不会触发监听的这个对象的函数;因为这个引用数据类型的地址没发生改变;这个时候需要把watch监听的方法改成对象的写法,handler相当于函数,deep:true,是对这个person对象中的每一个属性进行监听,immediate:true,可以让函数立即执行一次;当其中一个属性发生改变,也会触发handler这个函数;
		• 监听对象的时候写在handler方法的参数只写一个就可以,这个参数代表改变之后的值
		• 如果想监听对象里的一个属性值可以写成'对象.属性名' ,这个时候写在handler方法的参数就得写两个,第一个参数是最新的值,第二个参是修改前的值
	• directives自定义指令 :自己来定义命令
		• 全局命令:所有的vue实例都可以用,inserted方法里的参数代表使用自定义方法的元素,有几个元素,方法就执行几次
		• 局部指令:只有当前vue实例才可以用,方法里的参数代表使用自定义方法的元素,有几个元素,方法就执行几次(this指向vue实例)
	• template 模板 : 如果有template属性,当初始化实例时,会把template的属性值编译并替换掉el属性里的App元素
		• template中只能有一个根元素,如果有两个,会默认取第一个作为根元素(会报错)
		• template中可以获取到data中数据和methods中的方法
		• template有两种写法
			• 第一种可以直接在vue实例中以字符串格式写出模板内容
			• 第二种在vue实例中以字符串写出标签的id名,并在html中在标签<template></template>中,写出模板的内容
		• slot插槽:把调取组件的时候写在组件中间部分的内容获取到,放置到组件的某个位置(具体位置根据需求来),依托这种方式,可以让当前组件具备更强的扩展性

写在html标签行内的指令

• {{}} :小胡子语法,写在标签中的语法,小胡子语法可以将data中数据放入元素中。
• 小胡子语法支持表达式
• null 和undefined不能被解析
• 支持三元运算符
•  v-model : 一般用于表单元素;将data中数据放在input框中,当input值发生改变,数据也会跟着发生改变;
• input返回的数据格式固定为字符串
	• 在单选框中,被选中的那一项,会把input框的value值赋值给v-model的值;如果v-model的值和value值相同单选框就会被选中,其他的单选框就不会被选中了
• 单选框的v-model的值必须用一样的data属性名
• 多选框:v-model可以绑定一个数组,那么当该项被选中时,会把该input框中value放到数组里面;如果多选框v-model绑定的不是一个数组,那么默认会将该值转成布尔值,控制所有复选框的选中状态
• v-text : 可以将data中的文本放入元素中
• v-html : 可以将data中的文本放入元素中,可以识别标签
• v-show : 通过设置布尔值来控制元素是否显示,如果是true,则显示,false,则隐藏;如果不是一个布尔值,那么会默认转布尔;通过设置元素的display属性来控制是否显示;
• v-if : 控制元素的显示隐藏;如果不是布尔,会默认转成布尔;如果是false,直接删除了原有的元素;
•  v-else-if
• v-else
• v-for : 循环,需要创建什么元素,就把v-for放在哪个元素身上,可以循环数组,字符串,数字,对象
• v-for="(item,index)  in arr"  item代表数组的每一项,index代表数组的索引 arr是data中一个变量
	• v-for后面要加key 参考网址:https://www.jianshu.com/p/1896789fc8a8
• v-on : 给元素绑定事件的指令 (v-on:可以简写成@) 
	• 绑定事件时,可以有小括号,也可以没有
	• 如果有小括号,但是没有传参,那么e(第一个参)默认是undefined
	• 如果需要事件对象,并且需要传参,那么需要在绑定时使用$event进行占位
• vue的事件修饰符
	• .stop: 阻止事件的冒泡传播;
	• .prevent : 阻止事件的默认行为
	• .capture : 控制事件在捕获阶段执行
	• .once : 只执行一次
	• .passive : 修饰onscroll事件,不会等到onscroll执行完,就会立即执行下一次,提高代码的性能;
	• .self :只有点击自己的时候才会执行 
• 键盘修饰符 : .enter  .tab  .delete  .esc  .space  .up .down  .left .right
• v-bind : (可以简写成 : )  将普通的属性转成动态的属性,可以去获取data中的数据,v-bind:class :属性值可以写成一个对象,里面的属性名是class的名字,属性值时true,该样式有效,false该样式无效;如果是数组的话,就会去获取data中的属性名对应的属性值,就是class的名字
• v-once : 只渲染一次,以后更改数据页不再更新了,当写静态结构时,可以使用这个指令
• v-pre :  跳过这个元素的编译,加快了编译过程,可以用来显示原始 Mustache 标签
• v-cloak : 这个指令保持在元素上直到关联实例结束编译。和 CSS 规则如 [v-cloak] { display: none } 一起用时,这个指令可以隐藏未编译的 Mustache 标签直到实例准备完毕。

computed和watch的不同

• 参考网站:https://www.cnblogs.com/jiajialove/p/11327945.html
• 如果用computed和watch都可以实现,能用computed就不要用watch;原因是computed有缓存;
• computed
	a. computed 会默认走缓存,减少性能的开销
	b. computed不支持异步
	c. 当一个属性依赖多个属性变化而变化时,这个属性适合用computed;多对一
• watch
	a. watch :不走缓存,性能开销大
	b. watch支持异步
	c. 当这个属性发生改变会影响其他属性时,这个属性用watch,一对多

VUE实例的属性

• $el : 获取到vue实例挂载的元素对象
• $options : 当前实例的一些参数
• $refs : 可以用来获取DOM元素,在标签行间写上 ref="a" ,a是自己起的名字,如果名字相同那么后面的会替掉前面的
• $set : 向data中的对象新增键值对
	•   如果更改对象中的属性名对象的属性值,视图会进行更新的,但是新增键值对视图不会更新,用$set新增键值对就可以让视图更新( vm.$set(vm.msg,"a",200))
• $delete: 删除属性
• $destroy : 销毁实例
• $mount: 挂载
• $on : 订阅
• $emit : 发布
• $off :移除
• $nextTick : 用于DOM的异步更新;

VUE方法

vue.use方法
	• 安装 Vue.js 插件。如果插件是一个对象,必须提供 install 方法。如果插件是一个函数,它会被作为 install 方法。install 方法调用时,会将 Vue 作为第一个参数传入。
	• 该方法需要在调用 new Vue() 之前被调用。
	• 当 install 方法被同一个插件多次调用,插件将只会被安装一次。
vue.mixin方法
	• 全局注册一个混入,影响注册之后所有创建的每个 Vue 实例。插件作者可以使用混入,向组件注入自定义的行为。不推荐在应用代码中使用。
	• vue.mixin传入一个对象,把对象中的data合并到每一个组件的data中,如果和组件中的属性重名,那么以组件data中值为准;
	• 还可以吧对象中的钩子函数混入到每一个组件中,并且是先执行混入对象的钩子函数,再执行组件自己的钩子函数
	• 如果不重名就是新增,如果重名,则以组件内部的属性为准
	• mixin中的this代表当前使用混入对象的实例
	• 有多少个vue实例,mixin执行多少次,并且每次执行都会指向不同的组件实例
	局部混入
		• 设置局部混入,首先要有一个对象,然后再vue实例中写入mixins属性,属性值为一个数组,数组中是要混入的对象,可以有多个
render渲染函数
	• Vue 选项中的 render 函数若存在,则 Vue 构造函数不会从 template 选项或通过 el 选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
	• render函数的参数为一个函数,return参数执行,参数的参数第一个为字符串,字符串的内容为标签,第二个参数为对象,可以传class名,其他行内属性需要用attrs加,第三个属性为字符串,是标签的内容
            Vue.component('my', {

VUE的生命周期

• 参考网址:https://www.jianshu.com/p/5cd198945d41
• 从new Vue的创建到销毁的过程是生命周期
• 生命周期: Vue是一个构造函数,当执行这个函数时,相当于初始化vue实例;在创建实例过程中,需要设置数据监听,编译模板,将实例挂载到DOM上,数据更新能够让DOM也更新,在这个初始化,又会在不同阶段默认调用一些函数执行,这些函数就是生命周期的钩子函数;
• 生命周期钩子函数,能够让咱们在初始化实例时,添加自己的代码;
• 生命周期的钩子函数中的this,会默认指向vue的实例
• beforeCreate
• 在这个钩子函数中,不能获取data中的数据
• 这个函数不能操作DOM
• 在这个钩子函数执行之前初始化事件以及生命周期
• created
• 不能操作DOM
• 可以获取data的数据
• 可以发送请求
• beforeMount
• 执行这个钩子函数之前判断是否有el,template,编译vue
• mounted
• 挂载: 把VUE实例生成的虚拟的DOM转成真实的DOM,放在了页面中,这就是挂载;
• 编译出的DOM把原有的DOM替换完毕;
• 可以获取最终的DOM元素
• beforeUpdate
• 当数据更新时,会调用beforeUpdate 和updated钩子函数;上面四个不再运行
• 更新数据之前执行
• updated
• 数据更新,虚拟的DOM更新,然后更新真实的DOM;最后触发这个函数
• beforeDestroy
• 销毁之前执行
• destroyed
• 销毁子组件,销毁观察者,事件监听者
• 元素的事件还在,但是更改数据不会再让视图进行更新了;
• activated
• 当缓存组件有被显示出来时,会触发这个钩子函数
• deactivated
• 当缓存的组件隐藏时,会触发这个钩子函数;
• errorCaptured
• 当子孙组件出错时,会调用这个钩子函数
• 此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。

生命周期参考图片

在这里插入图片描述

VUE组件

• 组件的特点
• 每个组件就是一个自定义标签
• 可复用性
• 方便维护
• 方便拆分
• 每一个VUE组件都是一个独立的个体(独立的vue实例),作用域隔离(互不干扰),有完整的生命周期,有自己的响应式数据和各种方法(事件)
• 能够实现组件的嵌套:需要掌握组件之间的信息通信
• 组件命名规范
• 组件名字单词首字母大写  PasalCase  
• 以横线作为分隔符  kabab-case
• 不能使用内置的标签名作为组件名称
• 调取组件的时候,会把所有组件的单词渲染为小写
• 命名的时候尽量不要出现其他的特殊字符
• 调取组件的方法
• 单闭合:不符合w3c规范,调取完成后,后面的视图不识别(避免使用的)
• 双闭合:可以设置除组件规定内容外的其余内容(slot插槽)
• 创建组件的时候,data必须返回一个函数,并且函数返回一个对象,不能直接写对象
• child 是Vm这个vue实例的子组件;判断组件在哪个实例中注册,就是谁的子组件;
全局组件
• 全局组件可以在任何的vm实例中使用,每一个组件都相当于一个vue的实例,当调用这个组件时,就会生成vue的生命周期,每当使用一次就会执行一遍生命周期钩子函数
• 如何创建全局组件:在Vue属性上有一个component函数,执行可以创建一个组件,接收两个参数,第一个是组件的名字,第二个是组件的信息对象
局部组件
• 局部组件只能在注册的vue实例中使用该组件,不能跨组件使用,但是可以在另一个组件vue实例中再注册一次
• 如何创建局部组件:写一个组件实例,然后在vue实例的component属性中起一个属性名,属性值为组件的名字
• 组件methods中的方法的this指向了当前组件的实例

插槽(slot)

•   slot:内置的组件:可以将父组件中的子组件里面的模板数据(标签的内容)进行显示
• 具名插槽
• slot属性值和子组件中slot插槽中的name属性对应
• 子组件的slot组件上的name属性会和父组件中的slot属性进行匹配,并按照子组件的顺序显示对应的模板数据
• 没有name属性的slot会解析默认的标签
• 作用域插槽
•  slot-scope:作用域插槽;可以让我们在父组件这个位置取到子组件的数据
•   能够让父组件使用子组件中的组件

keep-alive缓存组件

• component 和keep-alive 都是内置组件,在VUE代码已经内置好的组件;
• 闭合标签使用组件
•  keep-alive:用于缓存组件,如果该组件还会再启用,那么可以使用keep-alive进行组件缓存和优化,提高性能,缓存的组件不需要销毁,也不需要再创建()
component动态显示组件
• component : 内置组件,根据is属性来显示对应的组件;is属性的属性值保持和组件名字一致;然后可以显示对应的组件
• 如果是动态属性,那么会去data中取值
• component每次能动态显示一个组件,当切换下一个组件时,当前组件要销毁

VUE组件之间的数据传递

父传子
1. 把父组件的数据以动态属性的方式放在当前子组件的行间属性上
2. 在子组件中用props接收到这个属性 (数组、对象)
3. 在子组件取值使用动态的属性名取值
• 在子组件标签上的v-bind的值取自他的父组件
	props验证
		• props接收到的属性也会放在组件实例上一份 
		• props可以传一个对象或者数组,如果是数组的话在数组里写上组件标签名的属性名就可以
		• 如果是对象属性名为组件标签名的属性名,属性值为对象,对象里可以写一些键值对
		• type:[Number] :对传递过来的数据进行校验,验证不满足则抛出警告
		• equired:true :这个键值对的意思是必须用v-bind传递一个名字为对象属性名的值
		• default:200 :这是一个默认值,如果没传,值就是它
		• validator(val){} :  val就是传递过来的值,这个函数返回一个布尔值,如果返回true,说明这个值没有问题,如果返回false,那么会抛出异常

子传父
	• 子组件不能直接修改父组件的数据
	• 方法一
		• 用和父传子类似的方法,在父组件里写一个改变值的方法,然后在子组件的标签上用v-bind传给子组件这个方法,由子组件调用。这种方法没法传参,值只能是固定的,所以不推荐
	• 方法二(利用自定义事件来改变)
		• 自定义的名称必须小写
		• $emit : 用来发布自定义事件
		• 在父组件里写一个改变值的方法,将值传给子组件,然后在子组件的标签名上写一个自定义方法,方法对应的函数为父组件的方法,然后再子组件中写一个方法,用$emit方法绑定自定义方法,第二个值为参数
	• 方法三($event方法)
		• $event接收的是$emit的第二个参数
		• 先在父组件中引入子组件,然后在子组件标签中引入data属性,然后在子组件标签中写一个自定义方法
	兄弟组件传递数据
		• eventBus是一个容器,是联系兄弟的纽带
		• $on : 订阅
		• $emit : 发布;轮询对应的事件池,让其中的方法执行
	祖先元素传递给子孙数据
		• $attrs和$listeners
		• $attrs: 把行间属性放在一个对象上,传给孙子组件的$attrs属性  $listeners :方法

VUE的单向数据流

• 当父组件中的数据通过某些方法发生改变,更改了自己的数据,子组件如果使用到这个数据也会随着发生更改,父组件的数据流向了子组件,子组件也更新,这就是组件之间的数据传递的单向数据流
• 但是子组件发生变化,不能引发父组件变化
• 当父组件更新时(执行顺序):父组件的beforeUpdate => 子组件的beforeUpdate => 子组件的updated => 父组件的updated
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MVVM是Model-View-ViewModel的简写,它是MVC的改进版。MVVM分为三个部分,即模型层(Model)、视图层(View)和连接桥梁(ViewModel)。模型层主要负责业务数据相关,视图层负责展示视图,而ViewModel作为连接桥梁,负责监听模型和视图的变化,实现双向绑定的功能。 使用MVVM的好处在于将视图的状态和行为抽象化,实现视图UI与业务逻辑的分离。MVVM支持双向绑定,当模型层数据发生修改时,ViewModel会察觉变化并通知视图层进行相应的修改;反之,当视图层发生修改时,ViewModel也会通知模型层进行数据的修改,实现视图与模型层的解耦。 关于Vue中的MVVM实现原理具体可以参考Vue的源码实现。根据引用中的代码,可以看出,在Vue中,创建一个MVVM实例时,会将数据对象传入,并通过observe方法进行监听。同时,Vue还会创建一个Compile实例来编译模板,并将MVVM实例作为参数传入。然后,通过数据劫持和模板编译的机制,最终实现MVVM的双向绑定功能。 总结来说,VueMVVM原理主要是通过数据劫持和模板编译来实现的,数据劫持负责监听数据的变化,模板编译负责将数据视图进行绑定。这样就实现数据的双向绑定,当数据变化时,视图会自动更新,并且当视图发生变化时,数据也会相应地更新。<span class="em">1</span><span class="em">2</span><span class="em">3</span><span class="em">4</span>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值