vue.js 是采用数据劫持结合发布者-订阅者模式的方式,经过Object.defineProperty()来劫持各个属性的setter,getter,在数据变更时发布消息给订阅者,触发相应的监听回调。javascript
具体步骤:
第一步:须要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter
这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
第二步:compile解析模板指令,将模板中的变量替换成数据,而后初始化渲染页面视图,并将每一个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变更,收到通知,更新视图
第三步:Watcher订阅者是Observer和Compile之间通讯的桥梁,主要作的事情是:
一、在自身实例化时往属性订阅器(dep)里面添加本身
二、自身必须有一个update()方法
三、待属性变更dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
第四步:MVVM做为数据绑定的入口,整合Observer、Compile和Watcher三者,经过Observer来监听本身的model数据变化,经过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通讯桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变动的双向绑定效果。css
总共分为8个阶段建立前/后,载入前/后,更新前/后,销毁前/后html
说一下每个阶段能够作的事情前端
beforeCreate, created, beforeMount, mounted 这几个钩子vue
三种java
// 父组件 <div> <child :data="child" @send="getFromChild"></child> </div> data(){ return{ toChild: '大儿子', fromChild: '' } }, methods: { getFromChild(val){ this.fromChild=val } } // 子组件 <div @click="toParent">{{data}}</div> props:[data], methods: { toParent(){ this.$emit('send', '给父亲') } }
v-model实际上是props,emit的语法糖,v-model默认会解析成名为value的prop和名为input的事件jquery
// 父组件 <children v-model="msg"></children> <p>{{msg}}</p> data(){ return{ msg:'model' } } // 子组件 <input :value="value" @input="toInput" /> props: ['value'], methods: { toInput(e){ this.$emit('input', e.target.value) } }
// 父组件 <child /> data(){ return { msg: '父组件数据' } }, methods: { test(){ console.log('我是父组件的方法,被执行') } }, mounted(){ console.log(this.$children[0].child_msg); // 执行子组件方法 } // 子组件 <div>{{$parent.msg}}</div> data(){ return{ child_msg: '子组件数据' } }, mounted(){ // 子组件执行父组件方法 this.$parent.test(); }
// 父组件 <child :count.sync="num" /> data(){ return { num: 0 } } // 子组件 <div @click="handleAdd">add</div> data(){ return { counter: this.count } }, props: ["count"], methods: { handleAdd(){ this.$emit('update:count', ++this.counter) } }
2、兄弟组件通讯:能够经过查找父组件中的子组件实现,
this.$parent.$children
在$children中能够经过组件name查询到须要的组件实例,而后进行通讯
跨多层次组件通讯
可使用provide/inject,虽然文档中不推荐直接使用在业务中。
假设有父组件A,而后有一个跨多层次的子组件Bwebpack
// 父组件A export default{ provide: { data: 1 } } // 子组件B export default{ inject: ['data'], mounted(){ // 不管跨几层都能获取父组件的data属性 console.log(this.data); // 1 } }
3、任意组件
能够用Vuex或Event Bus解决
eventBus的使用
1.新建一个bus.js文件web
import Vue from 'vue'; export default new Vue();
2.使用它vue-router
<div @click="addCart">添加</div> import Bus from 'bus.js'; export default{ methods: { addCart(event){ Bus.$emit('getTarget', event.target) } } } // 另外一组件 export default{ created(){ Bus.$on('getTarget', target =>{ console.log(target) }) } }
答:在模板中放入太多的逻辑会让模板太重且难以维护,在须要对数据进行复杂处理,且可能屡次使用的状况下,尽可能采起计算属性的方式。
好处:
①使得数据处理结构清晰;
②依赖于数据,数据更新,处理结果自动更新;
③计算属性内部this指向vm实例;
④在template调用时,直接写计算属性名便可;
⑤经常使用的是getter方法,获取数据,也可使用set方法改变数据;
⑥相较于methods,无论依赖的数据变不变,methods都会从新计算,可是依赖数据不变的时候computed从缓存中获取,不会从新计算。
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取;
特色:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动做,对服务端安全无用,hash不会重加载页面。
hash 模式下,仅 hash 符号以前的内容会被包含在请求中,如 http://www.xxx.com,所以对于后端来讲,即便没有作到对路由的全覆盖,也不会返回 404 错误。
history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()能够对浏览器历史记录栈进行修改,以及popState事件的监听到状态变动。
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端若是缺乏对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还须要后台配置支持……因此呢,你要在服务端增长一个覆盖全部状况的候选资源:若是 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
1.与AngularJS的区别
相同点: 都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。 不一样点: AngularJS的学习成本高,好比增长了Dependency Injection特性,而Vue.js自己提供的API都比较简单、直观;在性能上,AngularJS依赖对数据作脏检查,因此Watcher越多越慢;Vue.js使用基于依赖追踪的观察而且使用异步队列更新,全部的数据都是独立触发的。
2.与React的区别
相同点: React采用特殊的JSX语法,Vue.js在组件开发中也推崇编写.vue特殊文件格式,对文件内容都有一些约定,二者都须要编译后使用;中心思想相同:一切都是组件,组件实例之间能够嵌套;都提供合理的钩子函数,可让开发者定制化地去处理需求;都不内置列数AJAX,Route等功能到核心包,而是以插件的方式加载;在组件开发中都支持mixins的特性。 不一样点: React采用的Virtual DOM会对渲染出来的结果作脏检查;Vue.js在模板中提供了指令,过滤器等,能够很是方便,快捷地操做Virtual DOM。
首页能够控制导航跳转,beforeEach,afterEach等,通常用于页面title的修改。一些须要登陆才能调整页面的重定向功能。
beforeEach主要有3个参数to,from,next:
to:route即将进入的目标路由对象,
from:route当前导航正要离开的路由
next:function必定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。能够控制网页的跳转。
只用来读取的状态集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
在main.js引入store,注入。新建了一个目录store,….. export 。
场景有:单页应用中,组件之间的状态、音乐播放、登陆状态、加入购物车
state
Vuex 使用单一状态树,即每一个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不能够直接修改里面的数据。
mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
getters
相似vue的计算属性,主要用来过滤一些数据。
action
actions能够理解为经过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操做数据。view 层经过 store.dispath 来分发 action。
modules
项目特别复杂的时候,可让每个模块拥有本身的state、mutation、action、getters,使得结构很是清晰,方便管理。
应用场景:单页应用中,组件之间的状态。音乐播放、登陆状态、加入购物车。
组件复用时全部组件实例都会共享data,若是data是对象就会形成一个组件修改data之后会影响到其余全部组件,因此须要将data写成函数,每次用到就调用一次函数得到新的数据
当咱们使用new Vue()的方式的时候,不管咱们将data设置为对象仍是函数都是能够的,由于new Vue()的方式是生成一个根组件,该组件不会复用,也就不存在共享data的状况
在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id 页面配置 :to="路由/ :id=123" 获取参数使用 this.$route.params.id 也可使用 Vue的get取值 页面配置 :to="路由?id=123" 获取参数 this.$route.query.id
watch: { obj: { handler (newValue, oldValue) { console.log('obj changed') }, deep: true } } // deep属性表示深层遍历,可是这么写会监控obj的全部属性变化,并非想要结果,修改以下: watch: { 'obj.a': { handler (newName, oldName) { console.log('obj.a changed') } } } // 还有一种方法,能够经过computed来实现,只须要 computed: { a1 () { return this.obj.a } } //利用计算属性的特性来实现,当依赖改变时,便会从新计算一个新值。
1.减小 HTTP 请求数量 在浏览器与服务器进行通讯时,主要是经过 HTTP 进行通讯。浏览器与服务器须要通过三次握手,每次握手须要花费大量时间。并且不一样浏览器对资源文件并发请求数量有限(不一样浏览器容许并发数), 一旦 HTTP 请求数量达到必定数量,资源请求就存在等待状态,这是很致命的,所以减小 HTTP 的请求数量能够很大程度上对网站性能进行优化。 二、CSS Sprites:国内俗称 CSS 精灵, 这是将多张图片合并成一张图片达到减小 HTTP 请求的一种解决方案,能够经过 CSS background 属性来访问图片内容。这种方案同时还能够减小图片总字节数。 三、.合并 CSS 和 JS 文件:如今前端有不少工程化打包工具, 如:grunt、gulp、webpack等。为了减小 HTTP 请求数量,能够经过这些工具再发布前将多个 CSS 或者 多个 JS 合并成一个文件。 四、.采用 lazyLoad:俗称懒加载,能够控制网页上的内容在一开始无需加载, 不须要发请求,等到用户操做真正须要的时候当即加载出内容。这样就控制了网页资源一次性请求数量。 五、 控制资源文件加载优先级 浏览器在加载 HTML 内容时,是将 HTML 内容从上至下依次解析, 解析到 link 或者 script 标签就会加载 href 或者 src 对应连接内容, 为了第一时间展现页面给用户,就须要将 CSS 提早加载, 不要受 JS 加载影响。通常状况下都是 CSS 在头部,JS 在底部。 六、.利用浏览器缓存 浏览器缓存是将网络资源存储在本地,等待下次请求该资源时, 若是资源已经存在就不须要到服务器从新请求该资源,直接在本地读取该资源。 七、.减小重排(Reflow) 基本原理:重排是 DOM 的变化影响到了元素的几何属性(宽和高), 浏览器会从新计算元素的几何属性,会使渲染树中受到影响的部分失效, 浏览器会验证 DOM 树上的全部其它结点的 visibility 属性, 这也是 Reflow 低效的缘由。若是 Reflow 的过于频繁,CPU 使用率就会急剧上升。 八、.减小 Reflow, 若是须要在 DOM 操做时添加样式, 尽可能使用 增长 class 属性,而不是经过 style 操做样式。 减小 DOM 操做,图标使用 IconFont 替换
大体能够分为以下7步: 1.输入网址; 2.发送到DNS服务器,并获取域名对应的web服务器对应的ip地址; 3.与web服务器创建TCP链接; 4.浏览器向web服务器发送http请求; 5.web服务器响应请求,并返回指定url的数据(或错误信息,或重定向的新的url地址); 6.浏览器下载web服务器返回的数据及解析html源文件; 7.生成DOM树,解析css和js,渲染页面,直至显示完成;
mvc和mvvm其实区别并不大。都是一种设计思想。主要就是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中大量的DOM 操做使页面渲染性能下降,加载速度变慢,影响用户体验。 区别:vue数据驱动,经过数据来显示视图层而不是节点操做。 场景:数据操做比较多的场景,更加便捷
1、低耦合。视图(View)能够独立于Model变化和修改,一个ViewModel能够绑定到不一样的"View"上,当View变化的时候Model能够不变,当Model变化的时候View也能够不变。 2、可重用性。你能够把一些视图逻辑放在一个ViewModel里面,让不少view重用这段视图逻辑。 3、独立开发。开发人员能够专一于业务逻辑和数据的开发(ViewModel),设计人员能够专一于页面设计。 4、可测试。界面素来是比较难于测试的,而如今测试能够针对ViewModel来写。
第一步:在components目录新建你的组件文件(如:indexPage.vue),script必定要export default {} 第二步:在须要用的页面(组件)中导入:import indexPage from '@/components/indexPage.vue' 第三步:注入到vue的子组件的components属性上面,components:{indexPage} 第四步:在template视图view中使用, 例若有indexPage命名,使用的时候则index-page
0 - (未初始化)尚未调用send()方法 1 - (载入)已调用send()方法,正在发送请求 2 - (载入完成)send()方法执行完成,已经接收到所有响应内容 3 - (交互)正在解析响应内容 4 - (完成)响应内容解析完成,能够在客户端调用了