一、vue 数据绑定
1.vue是个框架 框架指的是让我们的项目遵循一定的规则和模式,方便后期维护和多次使用 模式有MVM MVC
2.一个项目是否使用框架需要考虑框架复杂度和项目应用复杂度 需要做一个平衡
3.目前3大流行框架vue angular react
4.vue的几个基本概念 数据绑定 虚拟DOM 组件化
5.vue The Progressive JavaScript Framework 渐进式的js框架
6.vuex 状态管理系统
7.vue-router 单页面应用
8.通过new Vue({})可以去创造一个vue的实例,这个vue的实例就可以控制着某个元素标签
var vm = new Vue({
el : "选中元素",
data : {
msg : "hello world",
firstName : "yuansheng",
lastName : "guo"
},
methods : {
getFullName : function(){
return this.firstName+" "+this.lastName;
}
}
});
9.把数据输出到标签,{{在里面写的是一个js表达式,可以进行简单的运算}}
10.在es6里面新增的函数定义(形参)=>{}这样定义的函数this指向已经不存在指向本函数了,一般指向混乱,指向window
11.正常定义的this指向vue示例
12.vue 指令就是告诉DOM要操作什么 为我们操作DOM提供的
1.v-指令名:指令的参数=指令的表达式
13.<a v-bind:href="url">baidu</a>指定href绑定url这个数据
1.v-bind:属性名="属性值" 可以用于属性的绑定
14.v-on指令的使用 绑定事件的一个执行
1.v-on:事件类型="要执行的函数"
2.vue还提供了一些事件修饰符,用于达到某些需求,如果stop可以取消冒泡
v-on:click.stop="show"
3.阻止默认事件的的修饰符是prevent
4.事件修饰符就是修饰事件的,对事件的一些操作
5.事件修饰符enter监测enter键v-on:keyup.enter=""
6.其他一些键盘修饰符esc space键,当然还可以是键盘的which值来规定按谁触发v-on:keyup.13=""
7.还可以链式调用v-on:keyup.enter.space.37=""
8.系统修饰符按键如shift必须配合其他按键一起使用
9.系统修饰符meta键指代window键或者mac上的command键
10.在表达式或者形参里面想要获得时间对象可以使用$event这个是vue提供的
15.双向数据绑定
1.双向的数据绑定可以通过v-bind 和 v-on一起来实现,但vue提供了一个更加简便的方法v-model
2.v-model也有一个修饰符trim去除前后的空格v-model.trim
3.number修饰符v-model.number可以转会成number类型数字
4.lazy修饰符v-model.lazy会等到失去焦点的时候才会把数据绑定上去,不会实时更新,默认双向数据绑定数据是实时更新的
5.双向数据绑定
1.v-bind可以修改属性的值
2.v-on可以触发事件执行js代码然后去操作DOM
3.v-model是v-bind和v-on的结合
16.条件渲染
1.{{这里面渲染变量或者js表达式时只当做一个字符串来渲染}} html : "<h1>呵呵</h1>"
2.好处:防止用户随意更改页面 防止跨域脚本攻击
3.但是有的时候又想作为dom节点输出 使用也是一个指令v-html="html" 记得前提是数据是安全的,防止别人修改或者跨域脚本攻击
4.当然还提供了一个安全的方法v-once只有初始化的时候渲染一次,后面就不渲染了
5.v-if v-else v-else-if判断,可以得到谁显示谁隐藏,隐藏的底层是直接把DOM节点删了,而不是设置display:none
6.v-if v-else v-else-if判断适用于兄弟节点
7.显示和隐藏还有一个指令v-show="布尔值" 他的底层是修改display:none
8.渲染的时候如果因为网络问题vue.js没有加载完成,那么里面的数据也就不会得到渲染,只会原样输出,等待加载完毕后再去渲染
9.v-cloak指令用于监测vue实例是否加载完成,加载完成v-cloak就会自动消失,他是一个标签属性
10.列表渲染,多个数据在数组里面想要都加载出来v-for="别名 in 数组" v-for="(别名,索引) in 数组"
11.v-for循环会导致DOM也多次复制
12.注意事项
1.v-for循环数组或者对象的时候,如果索引不变,就算值改变了,也还是不会去渲染已经修改的值
2.如果想要渲染就需要使用vue提供的一个方法Vue.set(要修改的数组,索引,修改成什么值);
3.导致这个小bug的原因是VUE内部自己也无法检测到数组内部值的改变,只能检测到索引值发生改变
4.观察者模式,当数组内部发生了改变,vue可以监测到了,数组使用push方法跟原始的push方法是不一样的,vue重写了push方法,reverse、pop、shift、unshift、splice方法也被重写了,
5.模板复用,就会导致如果后面再跟一个input框值就不会跟着修改,如果想要修改可以给他加一个独一无二的key
17.{{这里可以是一个变量,一个函数,一个js表达式}}
18.计算属性,因为有的时候只需要改变一个数据而不想让其他数据也重新渲染,因为其他数据并没有发生改变,但使用methods里面的方法时就会全部重新渲染一遍,这样是很耗费性能的
19.所以为了解决这个问题,Vue提供了计算属性computed,Vue会去分析里面的方法然后去判断是否要修改对应的DOM而methods是不会去分析的
20.计算属性会去判断函数里面使用的变量是否发生值的改变,如果发生改变他才去重新渲染页面,监听数据发生
21.页面渲染前,Vue系统会先去监测computed计算属性里面的是否发生改变,他会随时监测自己依赖的变量,如果发生改变就会渲染到页面
22.计算属性有缓存机制,执行一次后就会把对应的值缓存下来,如果还需要使用就不会去重新执行函数,而是直接使用缓存
23.正常methods没有缓存机制,用几次就执行几次
24.计算属性的复杂使用
<script>
new Vue({
el : "#app",
data : {
num : 0,
firstName : "aa",
lastName : "bb"
},
methods : {
add : function(){
this.num++;
},
change : function(){
this.fullName="nn mm"
}
},
computed : {
fullName : {
get : function(){
alert("我执行了get");
return this.firstName+" "+this.lastName;
},
set : function(newName){
var arr = newName.split(" ");
this.firstName=arr[0];
this.lastName=arr[1];
}
}
}
})
</script>
25.箭头函数里面this指向父亲或者调用者
26.计算属性watch用法和computed类似,但是各有差别,computed必须要有返回值,如果没有return返回值就只能使用watch,computed里面代码必须是同步的代码,watch可以是异步操作,不需要返回值
27.计算属性监测数组变化,数组新加数据时需要使用push方法,如果用字面量方法增加将无法监测到
28.watch可以监控所有数据的变化,并且会得到数据变化后的值
29.filter过滤器 数据筛选过滤处理 他的function可以传两个参数,第一个参数默认是要处理的字符串会自动穿进去,第二个参数可以自己传
1.示例{{msg|upcase(第二个参数)}} msg是第一个参数
2.进行多次筛选{{msg|upcase(第二个参数)|trim}} 按顺序筛选
30.Vue进行样式修改提供两种方法 内联样式 类定义样式
1.v-bind:style="{在里面写一个对象,可以是数组存多个对象}"
2.写内联样式的时候使用v-bind绑定style属性可以进行参数修改,虽然有两个style,但是vue会在底层把两个style柔和成一个
3.定义类样式有两个方案添加类名 隐藏或者显示类名
30.data里面是不能使用this的 那么为了解决问题可以在计算属性里面写修改的对象,数据发生改变就会重新渲染页面
31.v-bind简写形式是: v-on简写成@
32.复习
1.v-bind:href 绑定属性,绑定后就是表达式
2.v-on:click=“”绑定事件 后面还有事件修饰符
1.stop修饰符阻止冒泡
2.preven修饰符阻止默认事件
3.键盘修饰符按键,enter space esc 按键e.which
3.v-model双向数据绑定
1.修饰符有lazy 懒惰更新文本框失去焦点
2.number修饰符
4.v-if=“布尔值” v-else-if v-else听见判断显示或者隐藏
5.template标签不会渲染到页面
6.v-show="布尔值"也是显示或者隐藏,他设置的是display:none
7.列表渲染v-for="(item,index) in 数组" item是数组的value
8.列表渲染对象v-for="(item,index) in 对象" item是对象的value
9.计算属性watch和computed都是对数据进行监听,发生改变就更新数据,computed必须要有返回值
10.filter过滤器 对数据进行处理筛选,里面写函数方法function(val,参数二)val参数默认传入,参数2待定自己写
33.单页面应用就是只有一个页面,加载完了就不需要有其他加载,但是加载的时候看网速快慢,加载完就快了
34.vue-router就是用于单页面应用的构建
35.vuex是对参数变量的管理
36.正常vue是通过js里面代码数据把数据渲染到html页面中,HTML页面本身都是空的,这就不适合搜索引擎爬虫去抓取我们的页面
37.HTML页面本来是空的,浏览器的js引擎通过对js文件的解析然后才把数据渲染到页面中
38.ssr就是这样一个技术,他在服务器就把页面渲染好了然后给客户端,这样页面就有东西了。搜索引擎爬虫就可以爬到
二、vue组件化
1.组件化开发 多人协作 就是自定义标签然后去渲染到页面
2.html模板<div class="app"></div>
3.vue实例 就是把数据挂载到html模板上new Vue({
el : "#app",
data : {
msg : "hehe"
}
template : "<div>hehe{{msg}}</div>" template模板会把HTML模板覆盖掉,只显示template模板
})
4.不使用template的原因是在template模板里面写html不能换行,而且没有提示,没有单词颜色,不方便,虽然es6解决了可以换行,但是高亮颜色还是没有
5.所以template主要是用于组件化开发
6.正常一个vue实例只能渲染一个元素,想要让他多次渲染就需要使用组件化开发
7.全局组件 这样定义的组件在全局都可以调用
<script>
Vue.component("my-component",{
template : `
<div>
<button v-on:click="clickme">{{count}}</button>
</div>
`,
data : function(){
return {
count : 0
}/*使用return的意义在于,保持各组件不相互影响,如果直接使用变量,一个组件改变另一个组件就会跟着改变*/
},
methods : {
clickme : function(){
this.count++
}
}
})
new Vue({
el : "#app"
})
new Vue({
el : "#app2"
})
</script>
8.局部组件 这样定义的组件只能在app里面访问
<script>
var component={
template : `
<div>
<h1>联系方式</h1>
<p>电话{{msg}}</p>
</div>
`,
data : function(){
return {
msg : 123456789
}
}
}
//Vue.component("my-component",component)
new Vue({
el : "#app",
components : {
'my-component' : component
}
})
new Vue({
el : "#app2"
})
</script>
9.使用vue命令行模式快速构建项目
1.推荐使用vue官方提供的项目模板webpack-simple
2.创建方法 进入需要创建的一个文件夹 vue init webpack-simple(类型) vue-lesson(项目名称)
3.进入项目安装依赖npm install
4.开启测试服务器npm run dev
5.任务运行器目前比较火是scripts npm run dev命令就是执行了scripts里面的dev命令
6.以vue文件后缀指的是单文件组件
7.图片一般浏览器会缓存,如果每次访问都是一样图片那么就会走缓存,所以vue一般会给图片加一个hash值,每个图片的hash值都是不一样的
8.render是一个最底层的编译带有vue代码的HTML模板的函数,浏览器是不识别这种带vue代码的html页面,需要提前又vue编译好,就是render编译的
9.展示页面一般是html模板和template模板,vue会把html模板和template编译成一个对象,当然也可以单文件的vue文件作为模板
10.vue文件又3个标签组成<template></template> <script></script> <style></style> 如果style加上scoped属性那么该样式就只能在该vue文件里面使用
11.vue文件组件里面的style样式是全局样式,会应用到整个页面,这是很危险的,所以一般会写成局部作用<style scoped></style>
12.数据由父组件传给子组件,在父组件新加数据,然后通过v-bind绑定属性的方式绑定到子组件,子组件通过props数组接收绑定的的数据,就达到了由父组件把数据传给子组件
13.有时候还为了规定用户只能传入字符串,而传入number就报错,可以把props写成一个对象{articlename : String}这样就规定articlename只能传入字符串,传入其他的类型就会报错
14.js里面对代码不支持短横线变量命名,需要换成驼峰
15.子组件把数据传给父组件
1.子组件事件上定义一个自定义事件,子组件事件如果被触发,父组件上的自定义事件也会跟着触发
16.<slot>{{msg}}</slot>如果在父组件里面有内容就显示父组件的内容,没有就显示子组件里面的<slot>{{msg}}</slot>
17.规则是父组件的里面子组件里的内容会覆盖到slot标签里面去,把slot里面内容覆盖掉
18.组件化
1.父组件向子组件传值 定义一个自定义属性
2.子组件向父组件传值 定义一个自定义事件
3.父组件向子组件插入DOM节点 通过有名的slot
19.主组件都要去main.js里面注册
20.主组件app里面如果写了标签内容会把子组件里面的内容覆盖掉,配合slot可以进行有选择性的匹配覆盖
21.es6中的箭头函数中this指代混乱
22.v-bind绑定属性后等于好后面的字符串可以是js表达式,可以是对象,对象里面还可以是表达式
1.<div v-bind:class="{ active: isActive ,'text-danger': hasError}"></div>
2.<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
23.设置标签显示隐藏v-if v-else-if v-else v-show
24.vue中的自定义事件this.$emit('myEvent',{参数})
25.指令注册Vue.directive('',{})
框架出生顺序:angular--react--vue
angular特点:模板 数据绑定
react特点:组件化 虚拟DOM
vue集合了angular和react的优点
vue的扩展插件:
1.vue-cli vue脚手架
2.vue-resource(axios) ajax请求,官方推荐axios
3.vue-router 路由
4.vuex 状态管理
5.vue-lazyload 图片懒加载
6.vue-scroller 页面滑动相关
7.mint-ui 基于vue的UI组件库,移动端
8.element-基于vue的UI组件库,PC端
MVVM模型:M是数据也就是vue实例中data V是视图也就是显示的东西,也就是el选择器所管理的那个DOM显示,VM是new Vue()出来的实例
v-model="data里面的变量"
{{显示data里面变量}}
页面展示--管理者---------------------------数据
View-----ViewModel------------------------Model
DOM------DOM Listeners Data Bindings------实例中的data部分
v-model双向数据绑定实现原理:监听input框里面的内容变化,然后把变化后的数据绑定到页面,监听input框使用input值变化事件
oninput 事件在用户输入时触发,它是在元素值发生变化时立即触发;
onchange事件,要在 input 失去焦点的时候才会触发;
v-on事件绑定
v-bind属性绑定
v-text 展示文本
v-html展示html可以解释标签
注意:只要是使用了指令,就是表达式
computed计算属性,监测data中数据的变化并实时更新,计算属性作为一个function方法,带返回值,通过返回值返回
computed : {
fullName : function(){
return this.firstName + ' ' + this.lastName;
},
fullName : {
get(){
获取fullName时执行的回调函数
},
set(value){
改变fullName时执行的回调函数,value是改变后的值
}
}
}
还有一个watch与计算属性相似,他可以监测数据的变化
watch : {
firstName : function(value){
}
}
所有vm实例的而外方法都是以$开头如vm.$watch()
多次获取相同的数据,如果数据未发生改变那么会有缓存,下次读取就不需要再次执行相应函数,而是直接拿缓存
get和set就会涉及缓存,拿和存,缓存是个对象,用计算的对象作为key,值作为value
通过class类的绑定实现元素样式改变
<style>
.aClass{
color : red;
}
.bClass{
color : blue;
}
</style>
<p v-bind:class="表达式,可以是字符串,对象,数组"></p>
<p v-bind:class="a"></p>
<p v-bind:class="{aClass:true,bClass:false}"></p>
data : {
a :“aClass”
}
条件渲染:
1.v-if="布尔值" v-else="布尔值" 直接删除DOM节点
2.v-show="布尔值" 设置display:none;适合切换
列表渲染:
1.v-for="(item,index) in 数组"遍历数组和对象
2.v-for="(value,key,index) in 数组/对象"遍历数组和对象
3.数组更新监测
正常vue是无法监测数组内部元素发生了什么改变,比如直接修改值是无法监测到的,arr[0]='jack'无法监测
但是vue重写了一个数组的方法如push() pop() shift() unshift() sort() reverse() splice()
事件修饰符 事件对象$event
v-on:click="test(默认不传参的话系统自动会传入事件对象,如果传参了就需要手动传入事件对象参数$event)"
阻止事件冒泡原来是event.stopPropagation();阻止默认事件是event.preventDefault()
vue里面直接使用事件修饰符stop和prevent
键盘按键修饰符,直接可以是键盘代数keyCode,以往如果想要实现这个需要判断event.keyCode
收集表单数据 表单默认有个submit事件
vue生命周期:初始化--更新--死亡每个阶段都对应一些回调函数,这些回调函数有个叫法叫勾子函数
对应的勾子函数都可以写到vue示例中,当执行到该阶段时就会执行该回调函数
new Vue()--初始化--beforeCreate()---created()------beforeMount()--mounted()--beforeDestroy()--destroyed()
先在内存中解析分析该Vue示例所管理的区域,分析完毕后全部一次性展示到页面,也就是挂载到页面
死亡一个vue实例:vm.$destroyed() 正常收尾工作会在beforeDestroy()这个勾子函数中执行,比如清除定时器
mounted阶段是更新数据,有两个勾子函数,beforeUpdate() updated()
总结:
1.初始化显示
beforeCreate()
created()
beforeMount()
mounted()
2.更新显示
beforeUpdate()
updated()
3.销毁vue实例 方法是vm.$destroyed()
beforeDestroy()
destroyed()
常用方法:
mounted() 发生ajax请求,启动定时器等异步任务,绑定事件监听this.$on('事件名',回调函数)
beforeDestroy() 收尾工作,清除定时器
vue中的过渡和动画
动画:操作css的transition和display 添加transition标签
自定义动画 animation
vue过滤器 Vue.filter("过滤器名字",function(会自动传入要处理的数据){数据处理函数});
指令:
ref指令,为标签取一个唯一标识,相当于id,ref="content" 获取这个标签使用this.refs.content,vue提供的textContent属性获取标签里面的值
v-cloak属性,给标签加上这个属性,当模板未加载完成时该属性会一直存在,加载完成后该属性自动消失,适用于当展示数据时{{msg}}如果获取数据时间太长就是展示获取数据的表达式{{msg}}这样是不好的而是让他隐藏,
v-cloak属性就发挥作用了,因为他刚好是在模板未解析OK前存在,就可以使用属性选择器选中然后display:none
自定义指令:
全局指令
局部指令
Vue.directive('',function(){})这个是VUE的函数对象,函数对象
vue插件 插件js一般都使用立即执行函数包裹
自定义插件
let MyPlugin = {};
MyPlugin.install = function (Vue, options) {
// 1. 添加全局方法或属性
Vue.myGlobalMethod = function () {
// 逻辑...
}
// 2. 添加全局资源
Vue.directive('my-directive', {
bind (el, binding, vnode, oldVnode) {
// 逻辑...
}
...
})
// 3. 注入组件
Vue.mixin({
created: function () {
// 逻辑...
}
...
})
// 4. 添加实例方法
Vue.prototype.$myMethod = function (methodOptions) {
// 逻辑...
}
}
window.MyPlugin = MyPlugin;把插件暴露到全局,插件里面可以添加全局方法,添加自定义指令,添加实例方法$,实例方法都挂载vue的原型上,全局方法都挂载vue函数对象上
脚手架搭建项目
1.vue init webpack 项目文件夹名
2.npm run dev 运行项目
打包项目 npm run build 运行此命令后会生成一个dist文件夹
发布项目
可以使用静态服务器工具包
1.安装静态服务器工具包npm install serve -g
2.执行命令serve dist
可以使用动态服务器tomcat
1.修改webpack.prod.conf.js文件,在output项添加一项publicPath:'/项目文件夹名,就是要放到tomcat上的那个文件夹名/'
2.重新打包,将生成的dist文件夹命名为publicPath里面的文件夹名,然后放到服务器就可以运行
自定义事件 应用于子组件向父组件传递信息
使用:
1.在父组件上绑定自定义事件的监听@event="在父组件执行的函数可以接受子组件传过来的data"
2.在子组件上触发事件this.$emit('event',data);
3.每个组件中的this指代的是该组件,如果想在父组件选中子组件,可以使用ref="属性值"标签属性,然后this.refs.属性值
4.自定义事件适合于父子之间传递,不适合于孙子之间传递
组件之间通信 消息的订阅和发布 使用PubSub.js库 安装下载npm install pubsub-js --save
1.订阅PubSub.subscribe('msg',function(msg,data){})------事件监听,msg类似事件名,在vue生命周期的mounted中执行触发
2.发布消息PubSub.publish('msg',data)--------------------触发事件,在相应函数中触发
3.PubSub优点适用于父子组件通信,父孙组件通信,兄弟组件通信,任意组件通信,回调函数中要使用箭头函数,不然this指向出错
组件之间通信值slot插槽,应用于父组件向子组件传递标签数据
1.slot是个占位标签,先在子组件占位,并带有一个名字
2.在父组件建立标签,并有一个slot属性
3.插槽准备传递的标签都是在父组件进行编译的,所以相应的数据操作都要写在父组件中
js模块 向外暴露函数或者对象 取决于需要暴露几个功能
1.暴露函数 只需要暴露一个功能就使用函数
2.暴露对象 暴露多个功能
vue中的两个ajax库 是vue的插件
适用于1.x版本是vue-resource 适用于2.x版本的是axios
安装方法npm install axios --save
vue的插件使用:
1.引入插件import VueResource from 'vue-resource'
2.声明插件使用 Vue.use(VueResource) 内部会给vm对象和组件对象添加一个属性:$http里面有两个方法一个get一个post
3.axios在哪使用就在那引入,不需要使用Vue.use()声明,直接axios.get().then().catch()
兄弟之间通信使用pubsub-js很舒服
vue ui组件库 都是饿了么公司出的
mint 适用于移动端
elment适用于pc端
vue路由 路由就是映射关系,类似key-value 前台路由就是组件之间 后台路由就是处理请求的回调函数
vue-router插件向外暴露的是一个VueRouter构造函数
创建vue-router实例new VueRouter({多个配置项});
路由配置routes[{},{}] 多个路由,每个路由是一个对象,都由path:"",component:组件名
想使用路由那么还需要配置路由器
1.import router from './router'
2.new Vue({router})
使用路由标签
1.<router-link>用来生成路由链接 <router-link to="/xxx"></router-link>
2.<router-view>显示当前路由组件界面 <router-view></router-view>
基本路由
使用路由的3个步骤
1.定义路由组件
2.祖册路由
3.使用路由(<router-link> <router-view>)
基础路由 即在routes里面数组配置 嵌套路由即在组件中的children中配置 默认路由
import Vue from 'vue'
import Router from 'vue-router'
import About from '../view/About.vue'
import Home from '../view/Home.vue'
import News from '../view/News.vue'
import Message from '../view/Message.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/about',
component: About
},
{
path: '/home',
component: Home,
children:[
{
path:'/home/news',
component:News
},
{
path:'/home/message',
component:Message
},
{
path:"",
redirect:'/home/news'
}
]
},
{
path:'/',
redirect:'/about'
}
]
})
缓存路由机制 比如一个文本框里面写了数据,如果切换路由组件,之前的数据就会消失,组件之间的切换都是重新加载一次
解决这个问题只需要一个标签<keep-alive><router-view></router-view></keep-alive> 但是也有一定的缺陷,这样就会一直保存着以前的数据就算更新了也还是之前的
向路由组件传递数据
1.$route
2.通过router-view携带参数
编程式路由导航
以前想要页面跳转:a标签 js的location.href=url
this中两个重要属性$router带有的是一些方法和$route带有的是一些数据
VUE源码分析 vue作为一个MVVM框架实现原理:数据代理 模板解析 数据绑定
vue中将伪数组转换成数组使用的是Array.prototype.slice.call()
vue中的el.nodeType节点类型,不同节点nodeType值不一样,文本节点3 元素节点1
Object.defineProperty(obj,propertyName,{描述符})给对象添加属性 obj是配置的目的对象,给谁配置添加属性
1.属性描述符中的配置项有:
1.数据描述符
configurable 是否可以重新定义
enumerable 是否可以枚举
value 初始值
writable 是否可以修改属性值
2.访问描述符
get 回调函数,根据其他相关的属性初始计算得到当前属性值
set 回调函数,监视当前属性值的变化
Vue中的监视属性利用的就是对象的get和set
Object.keys(obj) 返回的是对象的所有属性组成的数组
Object.defineProperty是es5中的语法,w3c以前的浏览器不支持IE8
obj.hasOwnProperty(prop) 检查对象是否含有该属性,返回值是布尔值
DocumentFragment 文档碎片 高效批量更新多个节点
document:对应显示的页面,包含n个element,一旦某个element更新那么整个页面就会更新,因此如果有很多节点要更新那么页面更新次数就会很多,
DocumentFragment 文档碎片 就是为了解决多次更新的,它首先在内存中保存n个element的容器对象,更新此容器中的节点,页面不改变
使用方法:一般适用于ul和li 用于vue的模板解析核心 通过获取标签里面的{{name}}然后通过正则表达式进行匹配,判断节点类型进行相应的操作
1.创建一个fragment
const fragment = document.createDocumentFragment()
2.获取需要存入容器的元素保存到fragment
const el = document.getElementById('id');
let child;
while(child=el.firstChild){//一个节点只能有一个父亲
fragment.appendChild(child)//先将child从el中移除,添加到fragment子节点
}
3.更新fragment中的节点
Array.prototype.slice.call(fragment.childNodes).forEach(node=>{
if(node.nodeType === 1){
node.textContent = 'baidu'
}
})
4.将fragment插入到要修改的位置
el.appendChild(fragment)
数据代理 底层原理利用的是Object.defineProperty(被代理的对象,属性,{属性描述符即配置项})中的get和set
const vm = new Vue({
el:"",
data:{
name:"hehe"
}
})
console.log(vm.name) 事实上name被保存到了vm对象的_data属性里面,本应该是vm._data.name 这就是数据代理
console.log(vm)
console.log(vm._data.name)
数据代理的核心代码
var me = this;
Object.defineProperty(vm,key,{
configurable:false,
enumerable:true,
get(){
return me._data[key]
},
set(value){
me._data[key] = value
}
})
模板解析的核心是fragment
指令解析 通过获取标签属性然后判断其是否是指令看v-
1.事件指令 如果判断其是指令然后判断其是不是事件指令,判断其是否是事件指令看v-on中的on 然后获取到vm.$options.methods中事件回调函数
2.一般指令 如果不是事件指令那么就是一般指令,根据指令名然后调用原生的方法进行匹配操作,比如v-text调用是textContent v-html调用innerHTML v-class使用的是className因为class可能有多个,因此需要先获取然后覆盖或者糅合
数据绑定 一旦更新了data中某个属性数据,所有界面上直接使用或间接使用了此属性的节点都会更新
1.数据绑定的实现是通过数据劫持来实现数据绑定的效果
2.核心也是defineProperty()监视data的变化,通过get和set
区别:vm中的set是通过修改_data对象中的数据,进而达到修改data中数据,data通过get得到_data中数据的变化
vm中的set和get是实现数据代理的功能
数据劫持是通过get和set监视数据变化的
vue的核心是初始化显示和更新显示
数据绑定两个部分:初始化显示和更新显示
new 一个MVVM实例内部做了什么事情
new Vue({})
1.创建了一个Observe对象用于劫持/监视data中所有层次的属性
2.创建了一个Compile对象用于解析指令属性和大括号表达式---->初始化---->Updater
vuex是vue的一个插件 作用:对vue应用中多个组件的共享状态进行集中式管理(读/写)
vuex状态管理过程:view----->Action------>state-----view
state:驱动应用的数据源
view:以声明的方式将state映射到视图
action:响应在view上的用户输入导致的状态变化(包含n个更新状态的方法)
多组件共享状态的问题 对于复杂的应用,路由比较多,之前解决数据共享问题是:比如在3个组件中都要使用到同一个数据,那么就会把数据统一定义到一个共同的组件中方便进行管理
vuex就是用来解决复杂应用的数据状态管理
vuex使用条件
1.多个视图依赖于同一状态
2.来自不同的视图需要变更同一状态
vuex核心:
vuex核心是向外暴露了一个store对象
先引入store
store对象:
1.所有用vuex管理的组件中都会都会都一个属性$store 他就是一个store对象
2.如果某个组件要读取vuex管理的数据,那么就在该组件的computed中读取,使用...mapState(['变量名'])很方便
使用前需要从vuex解构出import {mapState,mapGetters,mapActions} 如果使用原始语法$store.state.todos也可以
3.一旦使用了vuex进行数据管理,那么操作管理数据和管理数据的方法就不需要在组件之间传来传去了,只需要想办法调用$store中的方法或者计算属性了
4.vuex相当于全局的,任何一个组件就可以看得到里面的数据,任何组件都可以使用
5.如果不需要多组件管理的数据依然可以使用老方法进行传递,一些必要的参数也可以使用老方法props进行传递
6.书写流程:
1.先在组件中要进行数据更新的地方使用this.$store.dispatch('方法名',要传递的数据)
2.然后去actions中写入对应的方法并在形参中传入{commit}和对应要传递进来的数据
3.然后去mutation中书写actions中对应的commit('要提交的方法')
7.mutations中是方法对数据进行操作的核心方法,actions中的方法的作用就是提交通知mutations去执行核心的方法,因此系统会默认把vuex所管理的数据传入到mutations中方法的形参里面,第二个参数是actions传递进来的数据
8.getters中保存所有需要计算的计算属性,getters中函数方法可以自动获得store中管理的数据对象作为第一个形参的第一个参数,如果一个计算属性需要使用到getters中
的其他计算属性,getters可以作为第二个形参参数传入该方法,直接使用getters.计算属性名
9.只要是要更新数据状态就可以使用this.$store.dispatch()
10.在一个组件中想要使用store中actions中的某个方法,可以将mapActions映射到该组件,只需要在methods中使用...mapActions(['在actions中有的函数方法名字']) 然后此名字的函数就可以使用了
11.actions中可以执行异步代码如ajax setTimeout 定时器 actions触发条件:组件中this.$store.dispatch()
12.vuex还有一个modules模块 当应用非常大时才会创建模块 modules作为store文件夹下的子文件夹
详细看renwu项目
main.js中文件作用解释
import App from './App'
new Vue({
el: '#app',
store,
components: { App },//将引入的App组件映射成标签
template: '<App/>'//使用标签
})
映射和使用App组件有个简便方法:render: h=>h(App) render是一个渲染函数 h作为形参,也是个函数,底层是createElement()