Vue的入门知识我分红了如上四个顶层概念。
vue实例、指令、组件、模板。
vue官方文档已经很易懂了,可是我但愿把个人理解以及一些容易疏忽的地方记下来,方便我往后更轻松的使用它。css
vue是一套构建用户界面的渐进式框架。我对渐进式框架的理解是,你能够充分的使用vue的功能,包括简单的功能和复杂的功能,彻底按照vue的模式去构建程序。固然你也能够只使用相似数据响应的单一功能。他不强制要求你按照某个模式去书写,也就是说你能够在原有的代码基础上将少许功能用vue去实现也是可行的。html
最喜欢的vue的两个特色是,响应式数据和组件。响应式数据省去了不少监听数据的代码,能够专一在构建界面上。而组件做为模块化思想下延伸出的一个手段,不只能够很好的进行解耦使组件独立存在便于管理,并且能够很好的配合模块化技术进行模块化开发。ES6已经支持模块化。前端
data = Model
模板 + 指令 = View
new Vue() = ViewModelvue
推荐一个言简意赅的MVVM说明博文webpack
五种建立模板的方法:web
DOM元素模板(Vue实例用)chrome
script标签 + x-templatesegmentfault
template属性数组
.vue文件中template标签缓存
inline-template
直接用DOM元素做为模板的方式。仅限vue实例控制区域使用。下面四个是组件模板建立方式。
说明:受HTML限制,标签名不能用驼峰(html大小写不敏感)必须用aa-bb形式。另外受html标准影响,特殊元素内只容许存在特定元素,如tr内只能是td或th,若是想再相似tr里解析组件,要用is属性声明组件。
将script内的内容做为模板的方式。注意组件必须有一个根元素。好比下面那个无用div。并且模板与组件分离了,不在同一个位置,不便于管理。不推荐。
<script type="text/x-template" id="hello-world-template"> <div> <p>Hello hello hello</p> <p>Hello hello hello</p> </div> </script>
Vue.component('hello-world', { template: '#hello-world-template' })
最常规作法,也是最恶心的作法,在js语法环境写html代码,没有代码提示,没有格式化,恶心程度可想而知。
Vue.component('my-component', { template: '<div>A custom component!</div>' })
<template> <div>This will be pre-compiled</div> </template>
直接在插入组件的位置,声明模板。不过和script模板同样,分离了,不便于管理。不推荐。
<my-component inline-template> <div> <p>These are compiled as the component's own template.</p> <p>Not parent's transclusion content.</p> </div> </my-component>
vue实例也就是MVVM中的VM(ViewModel)。负责链接view和model。
既然是VM,那么vue实例主要做用是操做数据和自身。
vue实例提供了几个用来操做数据的选项。
做为MVVM中的M(Model),data属性用来存储未经处理的原始数据对象。
特性:
新添加的属性不会被响应
这个特性包括两点。
一点是指属性必须在 data 对象上存在它才是响应的。
var vm = new Vue({ data:{ a:1 } }) // `vm.a` 是响应的 vm.b = 2 // `vm.b` 是非响应的
一点是指Vue 不容许在已经建立的实例上动态添加新的根级响应式属性。既不能将响应属性添加到嵌套的对象上。
vm.a.b = 2
添加响应式新属性的替代方案(2种)以下:
// 第一种 Vue.set(vm.a, 'b', 2) this.$set(this.a,'b',2) // 第二种 vm.a = Object.assign({}, vm.a, { b: 2 }) this.a = Object.assign({}, this.a, { b: 2 })
不能响应的数组操做及对应替代方法
// 不能响应 vm.items[indexOfItem] = newValue // 替代方法 Vue.set(example1.items, indexOfItem, newValue) // 不能响应 vm.items.length = newLength // 替代方法 example1.items.splice(indexOfItem, 1, newValue)
vue称他为计算属性,用来对data数据进行处理。由于是对data进行计算,因此为了便于维护和理解,计算属性不要去修改data数据,仅仅引用便可。
特性:
用return的数据渲染view
数据是响应式的
基于依赖缓存计算结果。计算属性只有在它的相关依赖发生改变时才会从新求值。
好比两个div都靠计算属性A来渲染,那么渲染第二个div时不会从新执行计算属性A,而是直接返回渲染第一个div时计算的值
getter 和 setter。
默认只有一个getter,做用是依赖data变化来执行getter。能够本身设一个setter,做用是直接给计算属性赋值时会触发setter。
区别于computed的方法,一般用来做为事件的回调函数,或者不但愿使用computed的缓存特性时做为computed的替代品。methods方法一样是数据响应式的。
特性:
用return的数据渲染view
数据是响应式的
计算结果不缓存
问题:
如何在methods函数内引用事件元素自己?
一般直接用this就能够引用事件元素自己。
el.onclick = function(){ console.log(this) }
可是在Vue里this指向实例或组件自身,因此在Vue里这样引用事件元素自己。
<li @click="warn('msg', $event)"></li>
warn: function (message, event) { // 如今咱们能够访问原生事件对象 if (event) event.preventDefault() alert(message) console.log(event.currentTarget) // 绑定事件的元素自己 }
这里须要说明的是,引用的event对象是原生event对象,不是相似jQuery包装过的event对象。并且之所在模板里传入$event是由于,event对象的兼容性问题。在IE和chrome内能够经过window.event引用event对象,也就是不须要event形参,可是火狐不能够,火狐必须有event形参,并且将event对象做为实参传入,固然只有一个event形参时不须要显示的将event做为实参传入。问题在于event形参若是是非第一位参数,就必须将event对象显示的做为实参传入。在原生JS中能够以下实现。显然vue提供了很好的解决方法。
asd.onclick = function(event) { var ee = event function a (msg, event) { console.log(event) alert(msg) } a(window.value,ee) }
当你想要在数据变化响应时,执行异步操做或开销较大的操做时请使用watch
被用做一些常见的文本格式化。
vue实例从建立到销毁的过程。在这个过程当中能够经过配置生命周期钩子来处理一些逻辑。
推荐一个说明生命周期的博文
vue实例建立后,为了便于访问数据,vue实例对象会代理一些数据。
如vm.a
直接访问data数据、vm.$data直接访问整个data对象
用来在view层代表数据的用途
v-show是条件显示,只是切换display: none/block。
v-if是条件渲染。
用来声明该模板是哪一个组件。解决两个问题。
动态切换组件
<component v-bind:is="currentView"></component>
解决HTML元素限制
// bad <table> <my-row>...</my-row> </table> //good <table> <tr is="my-row"></tr> </table>
vue有一个最大限度复用原则,能够复用的元素会通过少许修改继续复用。
key属性能够屏蔽复用机制。有key属性的元素,每次都会从新渲染。
说明:
key值相同的元素之间也会复用,可是绑定key的元素被从新渲染时(渲染了非相同key的元素)原来的缓存会被清除,再也不被复用
vue实例对象能够经过变量名访问。可是组件没有变量名,因此没有能够访问的接口。
ref提供了访问组件的接口。
<child-comp ref="child"></child-comp>
访问
vm.$refs.child
vue组件是实施前端组件化的一个手段。一个完整的前端组件应该包括属于某一前端UI模块HTML CSS JS部分。可是显然入门教程里的注册方式有模板和JS,可是少了CSS,有点残次品的感受。因此条件容许我仍是更喜欢.vue文件的方式封装组件。
三种祖册方式
全局注册(不说了)
局部注册(不说了)
用.vue文件封装组件,并用做为模块进行require
给组件取个名
<child-comp ref="child"></child-comp>
访问组件
var parent = new Vue({ el: '#parent' }) // 访问子组件 var child = parent.$refs.child
简单理解就是,父组件模板里的内容应该如何处置。
内容分发规则有如下几点:
没有slot属性的内容分发给匿名slot
有slot属性的内容分发给对应有相同name属性的slot
slot内的内容在没有被分发内容时显示,并不用任何标签进行包裹
父子组件
递归组件
循环引用组件(A组件套了B组件,B组件里又套了A,A引用B B引用A)
问题:
递归组件:组件递归调用自身时会进入死循环,因此须要用相似v-if,并最终v-if值最终返回false
循环引用组件:因为互相引用,致使引用关系混乱。在用webpack构建时,webpack没法判断先引用谁。如A引用B B引用A时首先致使混乱的是B组件。Vue提供了一个解决方法。
beforeCreate: function () { this.$options.components.TreeFolderContents = require('./B.vue') }
vue组件最长提的是解耦。每一个组件只负责本身的部分,他只关心接收的数据。因此我以为组件间的通信是vue组件最重要的部分。
父组件给子组件传递数据遵循一个模式。
在父组件模板中声明传入的数据
在子组件中用props属性接收传入的数据
这样一来,子组件彻底解耦,他只负责接收。
父组件模板传入
<child :message="hello!"></child>
在子组件接收
Vue.component('child', { // 声明 props props: ['message'], template: '<span>{{ message }}</span>' })
说明:
传入数据是基本类型时,在子组件修改props会报错
传入数据是对象时,在子组件修改props的状况,由于对象是引用类型,修改props会同事修改到父组件
子组件给父组件传递数据遵循一个模式。
在父组件模板绑定并监听一个事件,该事件触发父组件方法。
在子组件触发监听的事件,进而触发父组件方法,并把数据做为参数传入该方法。
具体实现:
在父组件模板监听事件
<div id="counter-event-example"> <button-counter v-on:increment="incrementTotal"></button-counter> </div>
在子组件触发事件
methods: { increment: function () { this.counter += 1 this.$emit('increment', data) } }
非父子组件通信,因为两个组件独立存在,不能像父子间那样在父模板传入或监听。
非父子组件通信经过eventBus也就是一个空的vue实例对象做为中转站进行通信。具体实现以下。
建立一个空的vue实例
在组件生命周期前期(一般是mounted)在中转站上声明一个事件监听,表示谁触发这个事件就至关于通知我了。
在另外一个组件,触发这个事件,和子通知父同样。
因此非父子和子传父的区别在于,声明监听事件的方式不一样。
具体实现:
建立一个中转站
var eventBus = new Vue()
在A组件声明周期内,在中转站监听一个事件,并把该事件中的this指向自身(A组件自己)
mounted: function () { eventBus.$on('addBar', function () { this.a++ }.bind(this)) }
在B组件中触发事件来通知A组件
methods: { aaaAdd: function () { eventBus.$emit('addBar') } }
与父传子同样的模式,在slot传入,在分发内容接收。
具体实现:
传入
<div class="child"> <slot :text="msg"></slot> </div>
接收,具备特殊属性 scope 的 <template>
元素必须存在
<div class="parent"> <child> <template scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div>
有没有发现?四种不一样的通信方式各不相同,用了四种不一样的模式,并且有些在html文档里声明数据传入,有些在js文档里。我觉的很不优雅也不易理解和管理。
原理很简单,经过内置的component元素绑定is来实现切换。
<component v-bind:is="currentView"> <!-- 组件在 vm.currentview 变化时改变! --> </component>
可是切换出去的组件不会被缓存,从新切回来会从新渲染,若是想缓存。
<keep-alive> <component :is="currentView"> <!-- 非活动组件将被缓存! --> </component> </keep-alive>