Vue只是聚焦视图层,是一个构建数据驱动的Web界面的库。
Vue经过简单 API提供高效的数据绑定和灵活的组件系统javascript
轻量css
数据绑定html
指令前端
插件化vue
架构从传统后台MVC 向REST API + 前端MV*迁移
DOM是数据的一种天然映射java
Vue核心:组件化
和数据驱动
node
组件化: 扩展HTML元素,封装可重用的代码
每一个组件对应一个工程目录,组件所须要的各类资源在这个目录下就近维护。react
对比标准:文件大小(性能)
,入门曲线(易用)
,社区繁荣
,吸收优势
linux
与AngularJs区别webpack
相同点:
支持指令 -- 内置指令和自定义指令
支持过滤器 -- 内置过滤器和自定义过滤器
支持双向绑定
都不支持低端浏览器(IE6/7/8)
不一样点:
在性能上,ANgualrJS依赖对数据作脏检查,因此Watcher
越多越慢,Vue使用依赖追中的观察而且使用异步队列更新,全部的数据都是独立触发的。
与React的区别
相同点:
React采用特殊的JSX
语法,Vue在组建开中也推崇编写.vue
特殊文件格式,对文件内容都有一些约定,二者都须要编译后使用。
中心思想相同:一切都是组件,组件实例之间能够嵌套。
都提供合理的钩子函数,能够去定制化的去处理需求。
都不内置相似AJAX,Router等功能到核心包,而是以其它方式(插件)加载。
在组建开发中,都支持mixins的特性。
不一样点:
React依赖 Virtual DOM,而Vue使用的DOM模板。React采用的Virtual DOM会对渲染出来的结果作脏检查
Vue在模板中提供了指令,过滤器等。能够方便快捷的操做DOM。
脏检查:在angular中,没有办法对数据是否作了更改,因此设置触发条件,当触发这些条件,就执行一个检查来遍历全部的数据,对比更改的地方,而后执行变化,保留没有更改的地方。
效率不高,不少多余,称之为 脏检查。(过程:数据修改了,结果:保留就数据)
Vue稳定版本:1.0.24
数据绑定是将数据和视图想关联,当数据发生变化时,能够自动更新视图。
mustache标签
文本插值:{{}}
有时候只需渲染一次数据,后续数据变化再也不关心,使用:{{*}}
HTML片断:{{{}}}
注意:Vue指令和自身特性内是不能够插值。
mustache标签能够由JavaScript表达式和过滤器(本质上是一个JavaScript函数)构成。
表达式:各类数值,变量,运算符的综合体。
{{var a = 100;}}
// 错误。 是语句,并非表达式{{if (true) return 'a'}}
// 条件控制语句是不支持,可使用 三目运算符
做用:当表达式的值发生变化时,将这个变化也反映到DOM上。
分隔符
delimiters
Vue.config.delimiters = ['<%', '%>'];
修改了默认的文本插值的分隔符,则文本插值的语法由{{example}}
变为<%example%>
unsafeDelimiters
Vue.config.unsafeDelimiters = ['<$', '$>'];
若是修改了默认的HTML插值的分隔符,则HTML插值的语法由{{example}}
变为 <$emample$>
指令的值限定为绑定表达式。
做用:当其表达式的值改变时把某些特殊的行为应用到DOM上。
v-if
根据表达式的值在DOM中生成或移除一个元素。
v-show
根据表达式的值来显示或隐藏HTML元素。
在切换v-if
模块时,Vue有一个局部编译/卸载过程,由于v-if
中的模板可能包括数据绑定或子组件,v-if
是真实的条件渲染,由于它会包缺条件块在切换时合适地销毁与重建条件块内的时间监听器和子组件
v-if
是惰性的---若是初始渲染时条件为假,则什么也不作,在条件第一次变为真时才开始局部编译(编译会被缓存起来)
相比v-show
-- 元素始终被编译并保留,只是简单的基于CSS切换。
v-if
有更高的切换消耗,而v-show
有更高的初始渲染消耗。所以,若是须要频繁的切换,则使用v-show
较好,若是在运行时条件不大可能变化,则使用v-if
较好
v-else
必须跟着v-if
或v-show
后面,充当else
功能
v-model
用来在 input
, select
, text
, checkbox
, radio
等表单控件元素上建立双向数据绑定。根据控件类型,v-model自动选取正确的方法更新元素。
在v-model
指令能够添加参数number
,lazy
,debounce
<input type="text" v-model="msg" number /> <!-- 输入的自动转换为Number类型(若是原始的转换结果为NaN,则返回原始值) --> <input type="text" v-model="msg" lazy /> <!-- 默认状况下,v-model 在 input 时间中同步输入框的值与数据, 能够添加一个lazy特性,从而将数据改到 change事件中发生 -->
v-for
基于源数据重复渲染元素,可使用$index
来呈现相对应的数组索引
<ul id="demo"> <li v-for="item in items" class="item-{{$index}}"> {{item.childMsg}} </li> </ul>
Vue 1.0.17及之后支持 of分隔符
.
<div v-for="item of items"></div>
使用v-for
,将获得一个特殊的做用域,须要明确指定props属性传递数据,不然在组建内江获取不到数据。(隔离做用域)
<my-item v-for="item in items" :item="item" :index="$index"> <p>{{item.text}}</p> </my-item>
Vue包装了被观察数据的变异方法,它们能触发视图更新。push()
,pop()
,shilt()
,unshift()
,splice()
,sort()
,reverse()
Vue重写了这些方法以后,触发了notify
Vue增长了两个方法来观测变化:$set
,$remove
。
$set : 经过索引设置数组元素并触发视图更新。
vm.animals.$set(0, {name: 'Aardvark'});
$set,$remove 底层都是调用splice()
方法。
应该尽可能避免直接设置数据绑定的数组元素,由于这些变化不会被Vue检测到,由于也不会更新视图渲染,可使用$set()
.
Vue不能检测到数组的变化
直接用索引设置元素. 例如:vm.items[0] = {};
修改数据的长度, 例如:vm.items.length = 0;
解决方法:
vm.items.$set(0, {});
第二个问题,用一个空数据替换items便可。
v-for
遍历一个对象,每个重复的实例都将有一个特殊的属性$key
,或者给对象的简直提供一个别名。
<li v-for="itme in item">{{$key}} : {{item}}</li> <li v-for="(key, value) in item">{{key}} : {{item.msg}}</li>
v-for
支持整数
<li v-for="itme in 10"></li>
ECMAScript没法检测到新属性添加到一个对象上或者在对象中删除。要处理这样的情况Vue增长三种方法:$add(key,value)
,$set(key, value)
,$delete(key)
这些方法能够用来添加和删除属性,同时能够触发视图的更新。
v-text
v-text
指令能够更新元素的textContent。在内部,{{ Mustache }}
插值也被编译为textNode的一个v-text
指令。
<span v-text="msg"></span> <span>{{msg}}</span>
v-html
能够更新元素的InnerHTML。内容按普通 HTML插入 -- 数据绑定被忽略。
{{{Mustache}}}
插值也会被编译为锚节点上的一个v-html
指令
不建议直接动态渲染任意的HTML片断,很容易致使XSS
攻击.
<div v-html="html"></div> <div>{{{html}}}</div>
v-bind
响应更新HTML特性,将一个或多个attribute,或一个组件prop动态绑定到表达式。
<img v-bind:src="imgSrc" /> <img :src="imgSrc" />
在绑定prop时,prop必须在子组件中声明。能够用修饰符指定不一样的绑定类型。
修饰符为:
.sync
--- 双向绑定,只能用于prop绑定。
.noce
--- 单次绑定,只能用于prop绑定
.camel
--- 将绑定的特性名字转换驼峰命名(一般用于绑定用驼峰命名的SVG特性)
<my-component :prop="smoeThing"></my-component> <my-component :prop.sync="smoeThing"></my-component>
v-on
用于绑定事件监听器,事件类型由参数指定。
在监听原生DOM事件时,若是只定义一个参数。 DOM event 为事件的惟一参数;若是在内联语句处理器中访问原生DOM事件,则能够用特殊变量$event把它传入方法中。
<!-- 方法 --> <button v-on:click="methods"></button> <!-- 内联语句 --> <button v-on:click="methods(123, $event)"></button> <!-- 缩写 --> <button @click="methods"></button>
<!-- 中止冒泡 --> <button @click.stop="methods"></button> <!-- 阻止默认行为 --> <button @click.prevent="methods"></button> <!-- 阻止默认行为,没有表达式 --> <button @submit.prevent></button> <!-- 串联修饰符 --> <button @click.stop.prevent="methods"></button> <!-- 修饰符,键别名 --> <button @keyup.enter="onEnter"></button> <!-- 键修饰符,键代码 --> <button @keyup.13="onEnter"></button>
v-ref
在父组件上注册一个子组件的索引,便于直接访问。不须要表达式,必须提供参数id。能够经过父组件的$refs
对象访问子组件
v-el
为DOM元素注册一个索引,方便经过所属实例的$els访问这个元素。能够用v-el:smoe-el
设置this.$els.smoeEl
<div class="app"> <span v-el:msg>hello</span> <span v-el:other-msg>Vue</span> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '.app', ready: function () { console.log( this.$els.msg.textContent ); // hello console.log( this.$els.otherMsg ); // <span>Vue<span> } }); </script>
v-pre
编译时跳过当前元素和它的子元素。能够用来显示原始Mustache标签。跳过大量没有指令的节点会加快编译。
v-cloak
v-cloak
这个指令保持在元素上知道关联实例结果编译。
解决闪烁问题
[v-cloak] { dispnay: none; } <div v-cloak> {{message}} </div>
自定义指令提供一种机制将数据的变化映射为DOM行为。
钩子函数
Vue中的钩子函数都是可选的,相互之间没有制约关系
bind, 只调用一次,在指令第一次绑定到元素上时调用。
update, 在bind以后当即以初始值为参数第一次调用,以后每当绑定值变化时调用,参数为新值与旧值。
unbind,只调用一次,在指令从元素上绑定时调用。
Vue.directive('my-directive', { bind: function () { // 准备工做 // 例如,添加时间处理器或只须要运行一次的高耗任务 }, update: function ( newValue, oldValue ) { // 值更新时的工做 // 也会以初始值为参数调用一次 }, unbind: function () { // 清理工做 // 例如,删除bind() 添加的事件监听器 } });
使用指令:
<div v-my-direactive="someValue"></div>
只须要update函数是,能够传入一个函数替代定义对象
Vue.direactive('my-directive', function () { // update(); });
指令实例属性
全部的钩子函数都将被复制都实际的指令对象中,在钩子内this指向这个指令对象。
el -- 指令绑定的元素
vm -- 拥有该指令的上下文ViewModel
expression -- 指令的表达式,不包括参数和过滤器。
arg -- 指令的参数
name -- 指令的名字,不包含前缀
modifires -- 一个对象,包括指令的修饰符
descriptor -- 一个对象,包含指令的解析结果
将这些属性视为只读,不要修改他们。
<div id="app" @click="up"> <div v-my-directive:hello.a.b="msg"></div> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.directive('my-directive', { bind: function() { console.log('bound!'); }, update: function( value ) { this.el.innerHTML = 'name -' + this.name + '<br />' + 'expression - ' + this.expression + '<br />' + 'argument - ' + this.arg + '<br />' + 'modifiers - ' + JSON.stringify(this.mondifiers) + '<br />' + 'value -' + value + '<br />' + 'vm-msg' + this.vm.msg; } }); //name -my-directive //expression - msg //argument - hello //modifiers - undefined //value -hello //vm-msghello new Vue({ el: '#app', data: { msg: 'hello' }, methods: { up: function() { console.log('click'); } } }); </script>
自定义指令提供一种机制将数据的变化映射为DOM行为
params
自定义指令能够接收一个params数组,指定一个特性列表,Vue编译器将自定提取绑定元素的这些特性。
<div id="app"> <my-direactvie class="hello" name="hi" a="aaaa"></my-direactvie> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.elementDirective('my-direactvie', { params: ['a'], bind: function() { console.log(this.params.a); console.log(this.el.getAttribute('name')); } }); new Vue({ el: '#app' }); </script>
支持动态(v-bind),this.params[key]会自动保持更新。能够指定一个回调,在值变化时调用。
<div id="app"> <my-direactvie class="hello" name="hi" v-bind:a="someValue"></my-direactvie> <input type="text" v-model="someValue" name="" id="" value="" /> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.elementDirective('my-direactvie', { params: ['a'], paramWatchers: { a: function() { console.log('a changed!'); } } }); new Vue({ el: '#app', data: { someValue: '' } }); </script>
deep
若是自定义指令使用在一个对象上,当对象内部属性变化时要触发update,则在指令定义对象中指定 deep:true
<div id="app"> <div v-my-directive="a"></div> <button @click="change">change</button>{{a.b.c}} </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.directive('my-directive', { deep: true, update: function( obj ) { console.log( obj.b.c ); } }); new Vue({ el: '#app', data: { a: { b: { c: 2 } } }, methods: { change: function() { this.a.b.c = 4; } } }); </script>
twoWay
若是指令想VUe实例写回数据,则在指令定义对象中指定twoWay:true
做用:容许在指令中使用this.set(value)
<div id="app"> 自定义组件: <input v-exp="a.b.c" /> <br /> 父做用域:{{a.b.c}} </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.directive('exp', { twoWay: true, bind: function() { this.handler = function() { // 把数据写回 vm // 若是指令这样绑定 v-exp="a.b.c" // 这里将会绑定 `vm.a.b.c` 赋值 this.set(this.el.value); }.bind(this); this.el.addEventListener('input', this.handler) }, update: function() { this.el.removeEventListener('input', this.handler); } }); new Vue({ el: '#app', data: { a: { b: { c: 2 } } } }); </script>
acceptStatement
传入acceptStatement:true
可让自定义指令接受内联语句,就像v-on那样。
<div id="app"> <div v-my-directive="a++"></div> {{a}} </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.directive('my-directive', { acceptStatement: true, update: function( fn ) { // 传入一个是函数 // 调用它是将在所属实例做用域内计算"a++"语句 console.log( fn.toString() ); fn(); } }); new Vue({ el: '#app', data: { a: 5 } }); </script>
Terminal
Vue经过递归遍历DOM树来编译模块。可是遇到terminal
指令时会中止遍历这个元素的后代,这个指令将会接管编译这个元素及其后代的任务。 v-if
和 v-for
都是terminal
指令
priority
能够给指令指定一个优先级。若是没有指定优先级,普通指令默认是1000,terminal指令默认是2000.同一个元素上优先级高的指令会比其它指令处理得早已一些,优先级同样的指令按照它在元素特性列表中出现的顺序依次处理,可是不能保证这个顺序在不一样浏览器中是一致的。
流程控制指令 v-if
和v-for
在编译过程当中始终拥有最高的优先级。
指令可以使用的配置项:
Vue.directive(id, { params: [], deep: true, // 使用对象,对象内部属性变化,触发update twoWay: true, // 指令把数据写回Vue实例 acceptStatement: true, // 自定义指令接受内联语句 (相似`v-on`) priority: 2222, // 优先级 bind: function() {}, update: function() {}, unbind: function() {} }); Vue.directive(id, function() { });
问题:
v-on能够绑定多个方法吗?
v-on
能够绑定多种类型的方法,能够是click,能够是focus事件,也能够是change事件
可是使用v-on
绑定了两个甚至多个click事件,那么v-on
只会绑定第一个click事件,其它会被自动忽略。
<input type="text" :value="name" @input="onInput" @focus="onFocus" @blur="onBlur" />
一个Vue实例能够绑定多个element元素吗?
el
为实例提供挂载元素,值能够是CSS选择符,或实际的HTML元素,或返回HTML元素的函数。这边,元素只用做挂载点。若是提供了模板,则元素被替换,除非replace为false.元素能够用vm.$el访问。
在Vue中如何让v-for循环出来的列表里面的click事件只对当前列表内元素有效?
从数据角度出发,定好数据结构,而后操做数据
经过$event对象,获取当前事件源,而后操做下面的元素.
<div class="app"> <ul> <li @click="toggle(item)" v-for="item in items"> <span v-show="item.show">{{item.content}}</span> </li> </ul> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '.app', data: { items: [ { content: '1 item', show: true }, { content: '2 item', show: true }, { content: '3 item', show: false } ] }, methods: { toggle: function ( item ) { item.show = !item.show; } } }); </script>
一般会在模板中绑定表达式,模板是用来描述视图结构的。若是模板中的表达式存在过多的逻辑,模板会变成臃肿不堪,维护变得很是困难,所以,为了简化逻辑,当某个属性值依赖于其它属性的值,可使用计算属性。
计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的DOM部分也会同步自动更新。
<div class="app"> <input type="text" v-model="didi" /> <input type="text" v-model="family" /> <br /> didi = {{didi}}, family = {{family}}, didiFamily = {{didiFamily}} </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '.app', data: { didi: 'didi', family: 'family' }, computed: { didiFamily: { get: function () { return this.didi + this.family; }, set: function ( val ) { var names = val.split(' '); this.didi = names[0]; this.family = names[1]; } } } }); </script>
计算属性方法中执行大量的耗时操做,则可能会带来一些性能问题。
例如:在计算属性getter中循环一个大的数组以执行不少操做,那么当频繁调用该计算属性时,就会致使大量没必要要的运算。
而在 Vue 0.12.8
版本中,在这方面进行了优化,即只有计算属性依赖的属性值发生了改变时才会从新执行getter
这样存在一个问题:就是只有Vue实例中被观察的数据发生了改变时才会从新执行getter。可是有时候计算属性依赖实时的非观察数据属性。
<div class="app"> <input type="text" v-model="welcome" name="" id="" /> {{welcome}} <p>{{example}}</p> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '.app', data: { welcome: 'welcome to join didi' }, computed: { example: function () { return Date.now() + this.welcome; } } }); </script>
在每次访问example时都取得最新的事件而不是缓存的事件。从Vue 0.12.11
版本开始,默认提供了缓存开关。 在计算属性对象中指定cache字段来控制是否开启缓存。
new Vue({ el: '.app', data: { welcome: 'welcome to join didi' }, computed: { example: { cache: false, // 关闭缓存,默认为true get: function () { return Date.now() + this.welcome; } } } });
设置cache为false关闭缓存以后,每次直接访问vm.example 时都会从新执行getter方法。
问题:
计算属性getter不执行的场景
当计算属性依赖的数据属性发生改变时,计算属性的getter方法就会执行。在有些状况下,虽然依赖数据属性发生了改变,但计算属性的getter方法并不会执行。
当包含计算属性的节点被移出模板中其它地方没有再引用该属性时,那么对应的计算属性的getter不会执行。
<div class="app"> <button @click="toggleShow">Toggle Show Total Price</button> <p v-if="showTotal">Total Price = {{totalPrices}}</p> {{totalPrices}} </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '.app', data: { showTotal: true, basePrice: 100 }, computed: { totalPrices: function () { return this.basePrice + 1; } }, methods: { toggleShow: function () { this.showTotal = !this.showTotal; } } }); </script>
text
设置文本框v-model
为name
<input type="text" v-model="name" />
checkbox
通常的,使用多个复选框,被选中的值将会放入一个数组中。
<div id="app"> <input type="checkbox" id="flash" value="flash" v-model="bizLines" /> <label for="flash">快</label> <input type="checkbox" id="premium" value="premium" v-model="bizLines" /> <label for="premium">专</label> <p>Checked lines: {{bizLines | json}}</p> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { bizLines: [] }, ready: function() { console.log( this.bizLines ); } }); </script>
radio
单选按钮被选择时,v-dmoel中的变量值会被赋值为对应的value值。
select
经过v-for
指令来冬天生成option
<div id="app"> <select v-model="bizLine"> <option v-for="option in options" :value="option.value"> {{option.value}} {{option.premium}} </option> </select> <p>bizLine: {{bizLine}}</p> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> new Vue({ el: '#app', data: { bizLine: 'falsh', options: [ { text: '快', value: 'falsh' }, { text: '专', value: 'premium' } ] } }); </script>
checkbox
使用 :value
进行绑定
<input type="checkbox" id="falsh" :value="flash" v-model="bizLines" /> <label for="falsh"></label>
vm.bizLines === vm.flash
视图与Model之间同步数据
lazy
通常的,v-model
在input时间中同步输入框的值与数据,能够添加一个lazy特性。从而改到change事件中去同步。
<input v-model="msg" lazy /> <br /> {{msg}}
debounce
设置一个最小延迟,通常的在 AJAX 请求时,有效。
number
能够在v-model
所在的控件上使用number指令,该指令会在用户输入被同步到Model中时将其转化为数值类型,若是装换结果为NaN,则对应的Model值该是用户输入的原始值。
过滤器,本质上都是函数,其做用在于用户输入数据后,它可以进行处理,并返回一个数据结果。
Vue支持在任何出现表达式的地方添加过滤器,除了{{}}
mustache风格的表达式以外,还能够在绑定指令的表达式后调用。
<span v-text="message | uppercase"></span>
过滤器能够接收参数,参数跟在过滤器后面,参数之间以空格分隔。
<p>{{msg | filterFunction 'arg1' arg2}}</p>
过滤器函数始终以表达式的值做为第一个参数,带引号的参数会被看成字符串处理,而不带引号的参数会被看成数据属性名来处理。
Linux shell 的管道符号,上一个命令的输出能够做为下一个命令的输入。
Vue过滤器支持链式调用,上一个过滤器的输出的结果能够做为下一个过滤器的输入。
<span>{{'ddfe' | capitalize | reverse}}</span> <!-- -> 'ddfe' => 'Defe' => 'efeD' capitalize 过滤器: 将输入字符串中的单词的首字母大写 reverse过滤器: 反转字符串顺序 -->
字母操做
capitalize
,uppercase
,lowercase
三个过滤器用于处理英文字符。
capitalize
过滤器: 将表达式中的首字母转大写形式。uppercase
过滤器:全部字母转换为大写形式。lowercase
过滤器:全部字母转为小写形式。
json
json过滤器本质上时JSON.stringify(); 的精简缩略版。
做用:将表达式的值转换为JSON字符串。
限制limitBy
,filterBy
,orderBy
用于处理并返回过滤后的数组。 例如与v-for
搭配使用。
limitBy
limitBy
过滤器的做用时限制数组为开始的前N个元素,其中N由传入的第一个参数指定。第二个参数可选用于指定开始的偏移量。默认偏移量为 0. 若是第二个参数为3,则表示从数组下标第3个的地方开始计数。
<div v-for="item in tiems | limitBy 10"></div>
filterBy
第一个参数能够是字符串或者函数。
<div v-for="item in times | fitlerBy 'hello'"></div> <!-- 过滤出含有hello 字符串的元素 -->
orderBy
返回排序后的数组
<ul> <li v-for="user in users | orderBy 'lastName' 'firsetname' 'age'">{{user.lasetName}}--{{user.firsetName}}--{{user.age}}</li> </ul>
fitler语法
Vue.filter(ID, function() {});
单参数
<div id="app"> <p v-text="message | reverse"></p> </div> <script type="text/javascript"> Vue.filter('reverse', function( val ) { return val.split('').reverse().join(''); }); new Vue({ el: '#app', data: { message: 'abcdeq' } }); </script>
多参数
<div id="app"> <p v-text="message | reverse 'before' 'after'"></p> </div> <script type="text/javascript"> Vue.filter('reverse', function( val, begine, end ) { return begine + '---' + val + '---' + end; }); new Vue({ el: '#app', data: { message: 'abcdeq' } }); </script>
双向过滤器
Vue支持把视图(input元素)的值在写回模型前进行转化。
Vue.filter('MSG', { // model -> view // read 函数可选 read: function() { console.log( 123 ); }, // view -> model // write函数将在数据被写入Model以前调用 // 两个参数分别为表达式的新值和旧值 write: function( newVal, oldVal ) { console.log( newVal, oldVal ); } });
动态参数
若是过滤器参数没有用引号包起来,则它会在当前vm做用域内动态计算。过滤器函数的this始终指向调用它的vm
<div id="app"> <input type="text" v-model="userInp" /> <p>{{msg | concats userInp}}</p> </div> <script type="text/javascript"> Vue.filter('concats', function( val, inp ) { if (inp) { return val + inp; } return val; }); new Vue({ el: '#app', data: { msg: 'a' } }); </script>
过滤器注意点:
须要给定过滤器一个惟一标识。若是用户自定义的过滤器和Vue内置的过滤器冲突,那么Vue内置的过滤器将会被覆盖。若是后注册的过滤器和以前的过滤器冲突,则以前注册的过滤器层被覆盖。
过滤器函数的做用时输入表达式的值,通过处理后输出。所以,定义的函数最好能够返回有意义的值。函数没有return语句不会报错,但这样的过滤器没有意义。
问题
filterBy/orderBy 过滤后$index 的索引
在使用 filterBy
或者 orderBy
对表达式进行过滤时,若是同时须要将$index 做为参数,此时的$index将会根据表达式数组或对象过滤后的值进行索引。
<div id="app"> <ul> <li v-for="item in items | orderBy 'age'"> {{item.msg}} -- {{$index}} </li> </ul> </div> <script type="text/javascript"> new Vue({ el: '#app', data: { items: [ { msg: '顺', age: 1 }, { msg: '出', age: 10 }, { msg: '快', age: 6 } ] } }); </script>
自定义 filter 的书写位置
<script> // 第一种写法 Vue.filter('reverse', function () { }); // 第二种写法 new Vue({ el: '', data: {}, fitlers: { // 自定义 filter事件的位置 reverse: function () { } }, methods: {} }); </script>
Vue实例提供一些有用的属性和方法,这些属性和方法名都已前缀$
开头
组件树访问
$parent 访问当前组件实例的父实例
$root 访问当前组件书的根实例,当前组件没有父实例,$root 表示当前组件的实例自己。
$children 访问当前组件实例的直接子组件实例。
$refs 访问使用v-ref指令的子组件。
DOM访问
$el 访问挂载当前组件实例的DOM元素。
$els 访问$el元素中使用了v-el
指令的DOM元素。
数据访问
$data 访问组件实例观察的数据对象,该对象引用组件实例化时选项中的data属性。
$options 用来访问组件实例化时的初始化选项对象。
当实例建立后本来不存在的属性,是没法绑定在视图上的。
可使用Vue.set()
,vm.$set()
来解决.
$appendTo
$appednTo();方法用来将el所指的DOM元素或片断插入到目标元素中。
参数:
elementOrSelector(字符串或DOM元素),该参数能够是一个选择器字符串或者DOM元素。
callback -- (可选,该回调函数会在el元素被插入到目标元素后背触发。(若是在el上应用了过渡效果,则回调会在过渡完成后被触发)
$before
用来将el所指的DOM元素或片断插入到目标元素以前
参数:
elementOrSelector
callback-- (可选)
$after
将el所指的DOM元素或片断插入到目标元素以后。
参数:
elementOrSelector
callback-- (可选)
$remove
将el所指的DOM元素或片断从DOM中删除
参数:
callback -- (可选)
$nextITick
在下次DOM更新循环后执行的回调函数,使用该方法能够保证DOM中的内容已经与最新数据保持同步。
参数:
callback -- (可选)该回调函数会在DOM更新循环后被执行。它和全局的Vue.nextTick(); 方法同样,不一样的是,callback中的this会自动绑定到调用它的Vue实例上。
$on
监听实例上的自定义事件
$once
监听实例上的自定义事件,当之触发一次。
$emit
触发事件
参数:
event(字符串),该参数能够是一个事件名称
args (可选),传递给监听函数的参数
$dispatch()
派发事件,即先在当前实例触发,再沿着父链一层一层向上,若是对应的监听函数返回false就中止。
参数:
event(字符串),该参数能够是一个事件名称
args (可选),传递给监听函数的参数
$boradcast()
广播事件,即遍历当前实例的$children,若是对应的监听函数false就中止。
参数:
event(字符串),该参数能够是一个事件名称
args (可选),传递给监听函数的参数
$off()
删除事件监听器
参数:
event(字符串),该参数能够是一个事件名称
args (可选),对应的回调函数
若是没有参数,即删除全部的事件监听器,若是只提供一个参数--事件名称,即删除它对应的全部监听器。若是提供两个参数--事件名称和回调函数,即删除对应的这个回调函数。
组件核心目标是:可重用性高,减小重复性的开发。
Vue的组件能够理解为预先定义好行为的ViewModel类。一个组件能够预约义选项。
组件核心选项:
模板(template) -- 声明了数据和最终展示给用户的DOM之间的映射关系
初始化数据(data) -- 一个组件的初始数据状态。对于可复用的组件来讲,一般是私有的状态。
接收的外部参数(props) -- 组件之间经过参数来进行数据的传递和共享。参数默认是单向绑定(由上至下),但也能够显示声明为双向绑定。
方法(methods) -- 对数据的改动操做通常都在组件的方法内进行。能够经过v-on
指令将用户输入事件和组件方法进行绑定
生命周期钩子函数 -- 一个组件会触发多个生命周期钩子函数,好比:created
,attached
,destoryed
等。在这些钩子函数中,能够封装一些自定义的逻辑,和传统的MVC想必,着能够理解为Controller的逻辑被分散到了这些钩子函数中。
注册
全局注册
Vue.component('wind-component', WindComponet);
参数:
function, 能够是Vue.extend();建立的一个组件构造器,
Object ,Vue在背后自动调用Vue.extend();
组件的模板替换了自定义元素,自定义元素的做用只是做为一个挂载点,能够用实例replace决定是否替换自定义元素。
局部注册
不须要每一个组件都全局注册,可让组件只能用在其它组件内。可使用 实例选项中componets
注册
<div class="app"> <wind-component></wind-component> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var Child = Vue.extend({ template: '<div>I am Child</div>' }); var Prent = Vue.extend({ template: '<div>I am Parent</div> <Child></Child>', components: { child: Child } }); new Vue({ el: '.app', components: { 'wind-component': Prent } }); </script>
为了让事件更简单,能够直接传入选项对象而不是构造器给Vue.component(); 和 components选项
Vue组件三种数据传递方式:
props
组件通讯
slot
props
'props'是组建数据的一个字段,指望从父组件传下来数据。由于组件的实例的做用域是孤立的,着意味着不能而且不该该在子组件的模板内直接引用父组件的数据,因此子组件须要显示的用props选项来获取父组件的数据。props选项能够是字面量,也能够是表达式,还能够绑定修饰符。
字面量语法
<div class="app"> <child msg="wind"></child> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // 字面量 var Child = Vue.component('child', { props: ['msg'], template: '<div>{{msg}}</div>' }); new Vue({ el: '.app', components: { child: Child } }); </script>
动态语法
能够利用v-bind
将动态props绑定到父组件的数据。每当父组件的数据变化时,该变化也会传到给子组件。
动态语法:在父级组件连接 :wind="msg"
。只能在Vue.extend({}).
<div class="app"> <child msg="wind"></child> </div> <script src="vue1.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // 动态语法 // v-bind var Child = Vue.extend({ props: ['wind'], template: '<div>{{wind}}</div>', // replace: true }); var Parent = Vue.extend({ template: '<p>parent</p><br /><child :wind="msg"></child>', data: function () { return { 'msg': 'msgConent' }; }, components: { 'child': Child } }); new Vue({ el: '.app', components: { child: Parent } }); </script>
绑定修饰符
props默认是单向绑定 -- 当父组件的属性变化时,将传导给子组件,可是反过来不会。着是为了防止子组件无心修改父组件的状态。
.sync
,双向绑定
.once
, 单次绑定
双向绑定会把子组件的msg属性同步会父组件的parentMsg属性
<!-- 默认为单项绑定 --> <child :msg="parentMsg"></child> <!-- 双向绑定 --> <child :msg.sync="parentMsg"></child> <!-- 单词绑定 --> <child :msg.once="parentMsg"></child>
双向绑定会把子组件的msg属性同步到父组件的parentMsg属性,单次绑定在创建以后不会同步以后的变化。若是props是一个对象或数组,那么它是按引用传递的。在子组件内修改会影响父组件的状态,而无论是用哪一种类型绑定。
组件通讯
子组件能够用this.$parent
访问它的父组件,父组件有一个数组this.$children
,暴行它全部的子元素,根实例的后代能够用this.$root
访问根实例,不过子组件应当避免直接依赖父组件的数据,尽可能显式的使用 props传递数据。
在子组件中修改父组件的状态缺点:
父组件与子组件紧密地耦合
只看父组件,很难理解父组件的状态,由于它可能被任意子组件修改。在理解状况下,只有组件本身能修改其状态。
由于做用域是有层次的,因此能够在做用域链上传递时间。
通常的,选择事件传递方式,判断规则: 查看要触发事件的做用域。若是要通知整个事件系统,就要向下广播。
每个Vue实例都是一个事件触发器:
$on() -- 监听事件
$emit() -- 把事件沿着做用域向上派送
$dispatch() -- 派发事件,事件沿着父链冒泡。 调用
$broadcast() -- 广播事件,事件向下传导给全部的后代
<template id="child-template"> <input v-model="msg" /> <button @click="notify">Dispatch Event</button> </template> <div id="app"> <p>Messages: {{messages | json}}</p> <child></child> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // 注册子组件 // 将当前消息派发出去 Vue.component('child', { template: '#child-template', data: function() { return { msg: 'hello' } }, methods: { notify: function () { if ( this.msg.trim() ) { this.$dispatch('child-msg', this.msg); this.msg = ''; } } } }); // 初始化父组件 // 收到消息时将事件推入一个数组中 var parent = new Vue({ el: '#app', data: { messages: [] }, // 在建立实例时 `events` 选项简单的调用`$on` events: { 'child-msg': function ( msg ) { // 事件回到内的`this` 自动绑定到组册它的实例上 this.messages.push(msg); } } }); </script>
从父组件的代码中不能直接观看到child-msg
事件来自哪里。若是在模板中子组件用到的地方声明事件处理器。 可使用v-on
来监听。
<template id="child-template"> <input v-model="msg" /> <button @click="notify">Dispatch Event</button> </template> <div id="app"> <p>Message {{messages | json}}</p> <child @child-msg="shandleIt"></child> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> // 组册子组件 Vue.component('child', { template: '#child-template', data: function () { return { msg: 'hello' } }, methods: { notify: function () { if ( this.msg.trim() ) { this.$dispatch('child-msg', this.msg) this.msg = ''; } } } }); // 初始化父组件 new Vue({ el: '#app', data: { messages: [] }, methods: { 'shandleIt': function () { alert(123); } }, events: { 'child-msg': function ( msg ) { if ( msg ) { this.messages.push(msg); } } } }); </script>
当子组件触发了child-msg
事件时,父组件的 hadleIt
方法将被调用。全部影响父组件状态的代码都放到父组件的hadleIt
方法中。 子组件只关注触发事件。
尽管有props
和events
,可是有时候仍须要在JavaScript中直接访问子组件。所以,须要使用v-ref
为子组件指定一个索引ID。
v-ref
直接访问子组件
<div id="app"> <comp v-ref:aa></comp> <comp v-ref:bb></comp> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script> Vue.component('comp', { template: '<div>嘻嘻哈哈</div>', }); new Vue({ el: '#app', data: { msg: [] }, ready: function () { console.log( this.$refs.aa ); console.log( this.$refs.bb ); } }); </script>
slot分发内容
场景:
使用组件时,经常须要组合使用:
<pink> <pink-header></pink-header> <pink-footer></pink-footer> </pink>
注意:
<pink>组件不知道他的挂载点会有什么内容,挂载点的内容是由<pink>的父组件决定的。
<pink>组件极可能有它本身的模板。
为了让组件能够组合,须要一种方式来混合父组件的内容与子组件本身的模板。称之为:内容分发
Vue使用特殊的<slot>元素左右原始内容的插槽
定义在父组件中,父组件中嵌套的其它内容不会被替换。
编译做用域
分发内容是在各自做用域中被编译。
父组件模板的内容在父组件做用域内编译,子组件模板的内容在子组件做用域内编译。
单个 slot
父组件的内容被抛弃,除非子组件模板包含<slot>.若是子组件模板只有一个没有特性的slot,父组件的整个内容将查到slot所在的地方并替换它。
<slot>标签的内容视为回退内容。回退内容在子组件的做用域内编译,当宿主元素为空而且没有内容供插入时显示这个回退内容。
<template id="pink"> <div> <h1>This is my component!</h1> <slot> 若是没有分发内容则显示我 </slot> </div> </template> <div id="app"> <pink-component> <p>This is some original conent</p> <p>This is some more original conent</p> </pink-component> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component('pink-component', { template: '#pink' }); new Vue({ el: '#app', }); </script>
具名slot
<slot>
元素能够用一个特殊特性name
配置如何分发内容。多个slot
能够有不一样的名字。具名slot
将皮撇内容片断中有对应slot
特性的元素。
·具名slot·仍然能够有一个匿名slot
.做为找不到匹配的内容片断的回退插槽,它是默认slot。若是没有默认slot,这些找不到匹配的内容片断将被抛弃。
<template id="pink"> <div> <slot name="a"></slot> <slot></slot> <slot name="b"></slot> </div> </template> <div id="app"> <pink-multi> <p slot="a">ONE</p> <p slot="b">TWO</p> <p>defalut A</p> </pink-multi> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> Vue.component('pink-multi', { tempate: '#pink' }); new Vue({ el: '#app' }); </script>
混合
以一种灵活的方式为组建提供分布复用的功能。混合对象能够包含任意的组件选项。
当组件使用了混合对象时,混合对象的全部选项将别“混入”组件本身的选项中。
<div id="app"> <mixin-com></mixin-com> </div> <script type="text/javascript"> Vue.config.debug = true; // mixin对象 var myMixin = { created: function () { this.hello(); }, methods: { hello: function (){ console.log( 'hello from mixin!' ); } } } // 定义组件,使用 mixin对象 var mixinCom = Vue.extend({ mixins: [myMixin], template: '<h1>HELLO ~ </h1>' }); // 建立根实例 new Vue({ el: '#app', components: { 'mixin-com': mixinCom } }); </script>
HTML中是不区分大小写,而JavaScript是区分大小写。在给组件取属性名时,要注意大小写问题。尽可能使用小写加中横线
当混合对象和组件包含同名选项时,这些选项将以适当的策略合并。
例如:同名钩子函数被并入一个数组中,于是都会被调用。另外,混合的钩子函数将在组件本身的钩子以前调用。
<div id="app"> <my-componet></my-componet> </div> <script src="//cdn.bootcss.com/vue/1.0.2/vue.js" type="text/javascript" charset="utf-8"></script> <script type="text/javascript"> var myMixin = { created: function () { this.hello(); }, methods: { hello: function () { console.log('hello from mixin~'); } } } // 定义组件,使用混合对象 var com = Vue.extend({ mixins: [myMixin], template: '<h1>HELLO ~</h1>', created: function () { console.log('component hook called'); } }); // 建立根实例 new Vue({ el: '#app', components: { 'my-componet': com } }); </script>
混合全局注册,一旦全局注册混合,它就会影响全部以后建立的Vue实例。
慎用全局混合,由于它会影响到每一个所建立的Vue实例,包括第三方组件。大多数状况下,它应当只用于自定义选项。
动态组件
多个组件可使用同一个挂载点,而后动态的在他们之间切换。使用保留的<component>
元素,懂她id绑定到它的is
特性上。
<component :is="show"></component> <script> new Vue({ data: { show: true } }); </script>
keep-alive
做用:切换组件时,保留组件状态。减小内存开销。
<component :is="currentView" keep-alive></component>
activate钩子
做用: 控制切换组件的切换时间。切入组件添加activate
钩子函数
Vue.component('actiate-exp', { activate: function ( done ) { var self = this; loadDataAsync(function ( data ) { self.smoeData = data; done(); }); } });
activate 钩子只做用于动态组件切换或静态组件初始化渲染的过程当中,不做用于使用实例方法手工插入的过程当中。
transition-mode
transition-mode
特性用于指定连个动态组件之间如何过渡。
在默认状况下,进入与离开平滑的过渡。
in-out --- 新组建先过分进去,等它的过去完成以后当前组件过渡出去。
out-in 当前组件先过渡出去,等它过渡完成后新组件过渡进入
<!-- 先淡出再淡入 --> <component :is="view" transition="fade" transiion-mode="out-in"></component> <style> .fade-transition { transtion: opacity .3s ease; } .fade-enter, .fade-leave { opacity: 0; } </style>
组件和 v-for
自定义组件能够像普通元素同样直接使用v-for
。
由于组件的做用域是孤立的,没法将数据传递那个到组件内部。
<pink v-for="item in items" :item="item" :index="$index"></pink> <!-- 显式声明数据来自哪里可让组件复用再其它地方 -->
<div id="app"> <pink v-for="item in msg" :wind="item" :item="item" :index="$index"></pink> </div> <script type="text/javascript"> Vue.component('pink', { props: ['wind'], template: '<div>pink -- {{wind}}</div>' }); new Vue({ el: '#app', data: { msg: ['pink', 'tan', 'red', 'yellow'] } }); </script>
编写可复用组件
在编写组件时,时刻考虑组件是否可复用是否有好处的。
一次性组件跟其它组件紧密耦合不要紧,可是可复用组件必定要定义侵袭的公开接口。
Vue组件 API来自三部分 -- prop
, Evnet
, slot
prop容许外部环境传递数据组给组件
事件容许组件发出发布环境的action
slot运行外部环境将内部插入到组件的视图结构内。
使用v-bind
和 v-on
的简写语法,模板的缩进清楚并简洁
异步组件须要将应用拆分为小块,每块按实现按需加载。Vue容许将组建定义为一个工厂函数,动态的解析组件的定义。Vue只在组件须要渲染时触发工厂函数,并把结果缓存起来。
Vue.component('async-exp', function ( resoluve, reject ) { setTimeout(function () { reslove({ tempate: '<div>ASYNC!</div>' }); }, 1000); });
工厂函数接受一个resolve回调,在收到从服务器下载的组件定义时调用。
片断实例
在使用template选项时,模板的内容将替换实例的挂载元素,于是推荐模板的顶级元素始终是单个元素。
下面的状况会让实例变成一个片断实例
模板包含多个顶级元素
模板只包含普通文本
模板包含其余组件(其它组件多是一个片断实例)
模板只包含一个元素指令,如<partial> 或 vue-router的<router-view>
模板根节点有一个流程控制指令,如 v-if 或 v-for
让实例有未知数据的顶级元素,它将把其DOM内容看成片断。片断实例仍然会正确的渲染内容。不过没有一个根节点,它的$el指向一个锚节点,即一个空的文本节点(在开发模式下是一个注释节点)
组件元素上的非流程控制指令,非prop特性和过分将被忽略。
<!-- 不能够,由于没有根元素 --> <examplte v-show="ok" transition="fade"></examplte> <!-- props 能够 --> <examplte :prop="someData"></examplte> <!-- 流程控制能够,可是不能有过渡 --> <examplte v-if="ok"></examplte>
在vue中,在实例化Vue以前,他们以HTML的文本形式保存在文本编辑器中。当实例化后将经历建立
,编译
,销毁
主要三个阶段
生命周期钩子:
init
在实例化开始初始化时同步调用。此时数据观测,事件和Watcher 都还没有初始化
created
在实例建立后同步调用。此时实例已经结束解析选项,意味着已创建:数据绑定,计算属性,方法,Watcher/事件回调。可是尚未开始DOM编译,$el还不存在。
beforeCompile
在编译开始前调用。
compiled
在编译结束后调用。此时全部的指令已生效,于是数据的变化将触发DOM更新。可是不是担保$el已插入文档。
ready
在编译结束和$el第一次插入文档以后调用,入在第一次attatced钩子以后调用。注意必须是有Vue插入(如vm.$appendTo()等方法或更新)才出发ready钩子的。
// { 模板插入到文档中了;至关于window.onload }
attachedvm.$el
操做如DOM时调用。必须是→指令
或实例方法
(如$appednTo()) 插入,直接操做vm.$el
不会触发这个钩子
detached
在vm.$el
从DOM中删除时调用。必须是由指令
或实例方法删除
,直接操做vm.$el
不会触发这个钩子
beforeDestroy
在开始销毁实例时开始调用。此时实例仍然有功能。
destroyed
在实例被销毁以后调用。此时全部的绑定和实例的指令已经解绑,全部的子实例也已经被效果。若是有离开过渡,dsetroyed钩子在过渡完成以后调用。
组件格式,把一个组件的模板,样式,逻辑三要素整合在同一个文件中,即方便开发,也方便复用和维护。Vue自己支持对组件的异步加载,配合webpack的分块打包功能,能够实现组件的异步按需加载。
基于第三方组件开发
<scirpt> import Chart from 'chart.js' </scirpt>
问题
camelCase & kebab-case
HTML标签中的属性名不区分大小写。设置prop名字为camelCase形式的时候,须要装欢为keba-case形式在HTML中使用。
<!-- HTML中必须是短横线分割 --> <child my-message="hello"></child> <script type="text/javascript"> Vue.componet('child', { props: ['myMessage'], template: '<span>{{myMessage}</span>' }); </script>
字面量语法&动态语法
错误用法:
使用字面量语法传递数值。
<!-- 传递字符串 “1” --> <comp some-prop="1"></comp>
由于它是一个字面量prop,它的值是字符串“1”,而不是一实际的数字传下去。若是须要传递真实的JavaScript类型的数字,则须要使用动态语法。从而让它的值被看成JavaScript表达式计算。
<comp :some-prop="1"></comp>
组件选项问题
传入Vue构造器的多数选项也能够用Vue.extend();不过有两个特列:data
和el
.
场景:简单的吧一个对象做为data选项传给Vue.extend();
var data = { a: 1 }; var MyComponent = Vue.extend({data: data});
存在的问题:MyComponent全部的实例哦给你共享同一个data对象。
解决方式:使用一个函数做为data选项,让这个函数返回一个新对象。
var MyComponent = Vue.extend({ data: function () { return { a: 1 } } });
模板解析
Vue的模板是DOM模板,使用浏览器元素的解析器而不是本身实现一个。
DOM模板缺点:必须是有效的HTML片断。
一些HTML元素对什么元素均可以放在它里面有限制。
a 不能包含其余交互元素(如,按钮、链接)
ul和ol只能包含li
select 只能包含option和optgroup
table只能直接包含thead,tbody,tfoot,tr,caption,col,colgroup
tr只能直接包含th和td
自定义标签(包括自定义元素和特殊标签,如<component>.<template>,<partal>) 不能用在ul,select,table等对内部元素有限制的标签内。放在这些元素内部的自定义标签将被提到呀U尿素外面,于是渲染不正确。
自定义元素应当使用is特性。
<table> <tr :is="my-component"></tr> </table>
如何解决数据层级结构太深的问题
使用vm.$set()
手动定义一层数据
vm.$set('depAirprotZh', ticketInfo.flight.fromSegments[ticketInfo.flight.fromSegments.length - 1].depAirprotZh);
$set
用法:
参数:
{String} keyPath
{*} value
设置Vue市里的属性值。在多数状况下应当使用普通对象语法。如vm.a.b=123
.
这个方法只能适用:
使用keyPath动态的设置属性
设置不存在的属性。
若是keyPath不存在,将递归的建立并创建追踪。若是用它建立顶级属性,实例将被强制进入"digset循环",在此过程当中从新计算全部Watcher。
var vm = new Vue({ data: { a: { b: 1 } } }); // keypath 存在 vm.$set('a.b', 2); vm.a.b // -> 2 // keypath 不存在 vm.$set('c', 3); vm.c // -> 3
后端数据交互
配合vue-router
new Vue({ el: '#app', data: { todos: [] }, created: function () { this.$http .get() .hten(function ( data ) { this.todos = data; }) } });
配合Jquery的AJAX
new Vue({ el: '#app', data: { todos: [] }, created: function () { $.get('') .done(function ( data ) { this.todo = data; }); } });
data中没有计定义计算属性,它是如何被使用的
没有把计算数据放到$data里面去,而是经过Object.definePrototype(this, key,def) 直接定义到了实例上。
ES6中的模块
,let 和 const
export
在ES6中,一个文件就是一个模块,一个模块内部的全部变量,对于外部来讲是没法获取的,触发是哟个关键词exprot对外暴露接口,暴露的各个接口经过名字来进行区分。
const sqrt = Math.sqrt; function square ( x ) { return x * x; } function diag ( x, y ) { return sqrt(square(x) + square(y)); } // 经过export 暴露接口。使用大括号指定要暴露的接口 export {sqrt, square, diag}
import
经过import
命令加载这个模块(文件).
/** * 注意大括号中的接口名必须在lib.js模块中暴露。 */ import { square, diag } from './lib';
import
能够经过as
语法取别名
improt {myVar1 as myCustomVar1} from './lib';
import
会指定加载模块,所以有空的import
语法
// 值加载执行模块,不引用任何接口 import './lib'
import
能够总体加载模块,达到命名空间的效果。
// lib.js export var myVar1 = ...; export let myVar2 = ...; exprot const MY_COMST = ...; export function myFunc () { ... } exprot function* myGeneratorFunc () { ... } export class MyClass { ... } // mian.js import * as lib from './lib'; console.log(lib.myVar1); console.log(lib.myVar2); new lib.MyCalss();
export default
场景:即便用模块接口的人必须知道该模块export了哪些接口,有时候一个模块实际上只对外暴露一个接口,这个时候没有必要限定暴露的接口名字。
可使用export default
语法让模块调用者自定义要导入的接口名字。
// myFunc.js export defalut function () { } /** * 注意:myFunc 不能包含在`{}`里。myFunc能够替换任意变量名。 */ // main.js import MyFunc from 'myFunc'; MyFunc();
export/import在Vue.js中的使用
Vue采用export/import
进行模块化开发,文件经过exprot暴露接口,经过improt引用其它文件内容。
模块和组件的区别
Module: An implementation unit of software that provides a coherent set of responsibilities. Component: A component is a reusable building block that can be combined with other components in the same or other computers in a distributed network to form an application.
基础工具:目录结构
,本地调试
,代码部署
,热加载
,单元测试
安装: npm install vue-cli
vue-cli运行以后目录结构
目录或文件 | 说明 |
---|---|
build | webpack配置相关 |
config | webpack配置相关 |
node_modules | npm install 安装依赖代码库 |
src | 存放源码 |
-- main.js | 入口组件 |
static | 第三方静态资源 |
-- .gitkeep | 文件目录为空也能够提交到代码仓库 |
.babelrc | babel 配置文件 |
.editorconfig | 编辑器配置 |
.eslintignore | 忽略语法检查的目录设置 |
.eslintrc.js | eslint的配置文件 |
.gitignore | git 忽略文件或目录提交 |
index.html | 入口文件 |
package.json | 项目的配置文件 |
.babelrc
{ "presets": ["es2015", "stage-2"], # 预设插件 (babel转换预先须要安装的插件) // stage-2 四级 (1,2,3,4)包括了 es2015中没有的插件 "plugins": ["transform-runtime"], # 插件 "comments": false # false 表示转换成代码不生成注释 }
.editorconfig
root = true [*] charset = utf-8 # 编码 indent_style = space # 缩进风格 (基于空格做为缩进风格) indent_size = 2 # 缩进大小 end_of_line = lf # 换行符风格, lf是linux换行符风格 insert_final_newline = true # 建立文件,会自动在末尾插入新行 trim_trailing_whitespace = true # true,自动行尾多余风格
.eslintignore
build/*.js # build 文件夹底下的全部文件 config/*.js # config 文件夹底下的全部文件
.eslintrc.js
module.exports = { root: true, parser: 'babel-eslint', parserOptions: { sourceType: 'module' }, // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style // 语法规则地址 extends: 'standard', // standard 表示继承一个标准的规则,在vue-cli建立过程当中会选择. // required to lint *.vue files plugins: [ 'html' ], // add your custom rules here 'rules': { // 配置部分自定义规则 // allow paren-less arrow functions 'arrow-parens': 0, // 箭头函数前面容许不写括号 (值设置为0,表示忽略检查) // allow async-await 'generator-star-spacing': 0, // async-await 使用 // allow debugger during development 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 // 不容许在代码中有这些选项,生产环境不容许有 debugger } }
package.js
"dependencies": { # 项目生产下的依赖 }, "devDependencies": { # 编译过程当中的依赖 }
webpack打包
weback.base.conf.js
webapck基本配置
var path = require('path') var config = require('../config') var utils = require('./utils') var projectRoot = path.resolve(__dirname, '../') // 项目根目录 module.exports = { entry: { app: './src/main.js' // 入口文件 }, output: { path: config.build.assetsRoot, // 打包的根目录名字 publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, // 根目录 filename: '[name].js' // 对应 entry 的key名字 }, resolve: { // 设置在 require() 或者import 模块一些相关配置 extensions: ['', '.js', '.vue'], // 自动补全文件后缀 fallback: [path.join(__dirname, '../node_modules')], // require() 找不到模块,会充 node_modules模块中寻找 alias: { // 别名 'src': path.resolve(__dirname, '../src'), // require 的时候 使用的别名 'assets': path.resolve(__dirname, '../src/assets'), 'components': path.resolve(__dirname, '../src/components') } }, resolveLoader: { // require() 找不到模块,会充 node_modules模块中寻找 fallback: [path.join(__dirname, '../node_modules')] }, module: { preLoaders: [// preLoaders 会在loader以前对文件进行处理 // 对某种类型的文件 应用 某个loader进行处理 { test: /\.vue$/, loader: 'eslint', include: projectRoot, // 检查的文件。 只对该文件下的文件进行检查 exclude: /node_modules/ // 排除这些目录,进行该loader处理 }, { test: /\.js$/, loader: 'eslint', include: projectRoot, exclude: /node_modules/ } ], loaders: [ // 对某种类型的文件 应用 某个loader进行处理 { test: /\.vue$/, loader: 'vue' }, { test: /\.js$/, loader: 'babel', include: projectRoot, exclude: /node_modules/ }, { test: /\.json$/, loader: 'json' }, { test: /\.html$/, loader: 'vue-html' }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url', query: { limit: 10000, // 文件大小小于 10000kb 的时候生产 base64的文件 name: utils.assetsPath('img/[name].[hash:7].[ext]') // 文件名的规则 生产 } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, loader: 'url', query: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] }, eslint: { formatter: require('eslint-friendly-formatter') // 检查错误友好的提示错误信息 并提供 es6语法的官网连接 }, vue: { loaders: utils.cssLoaders() // .vue文件中CSS处理的loader } }
webpack.dev.conf.js
dev环境下的webpack配置
var config = require('../config') var webpack = require('webpack') var merge = require('webpack-merge') var utils = require('./utils') var baseWebpackConfig = require('./webpack.base.conf') var HtmlWebpackPlugin = require('html-webpack-plugin') // add hot-reload related code to entry chunks Object.keys(baseWebpackConfig.entry).forEach(function (name) { // hot relaod 相关代码 // 改变源码在浏览器不刷新的状况下,可以看到更新后的视图. baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) }) module.exports = merge(baseWebpackConfig, { module: { // 独立对 CSS预处理文件进行编译 loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) }, // eval-source-map is faster for development devtool: '#eval-source-map', plugins: [ new webpack.DefinePlugin({ // 把源码中的 `process.env` 替换成 config.dev.env 'process.env': config.dev.env }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.optimize.OccurenceOrderPlugin(), // webpack 优化插件. 对插件使用的频率 new webpack.HotModuleReplacementPlugin(), // hot realod new webpack.NoErrorsPlugin(), // 编译错误,会跳过那段代码 // https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ // 经过 filename: 'index.html', // 编译生成的文件名 template: 'index.html', // 处理的模板 inject: true // 表示打包的时候,路径自动添加到index.html中. css 的路径会自动添加到 head头部, js会默认添加到body中 }) ] })
dev-server.js
dev运行文件
var path = require('path') var express = require('express') var webpack = require('webpack') var config = require('../config') var proxyMiddleware = require('http-proxy-middleware') var webpackConfig = process.env.NODE_ENV === 'testing' ? require('./webpack.prod.conf') : require('./webpack.dev.conf') // default port where dev server listens for incoming traffic var port = process.env.PORT || config.dev.port // 端口号 // Define HTTP proxies to your custom API backend // https://github.com/chimurai/http-proxy-middleware var proxyTable = config.dev.proxyTable // 代理的接口 var app = express() var compiler = webpack(webpackConfig) // 编译webapck配置 var devMiddleware = require('webpack-dev-middleware')(compiler, { // webpack专门为express开发的中间件. publicPath: webpackConfig.output.publicPath, // 静态资源访问目录 stats: { colors: true, chunks: false } }) var hotMiddleware = require('webpack-hot-middleware')(compiler) // 访问的app文件,并无生产到项目目录中,而是在内存中,该中间件作了处理,放入内存中. // force page reload when html-webpack-plugin template changes compiler.plugin('compilation', function (compilation) { compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { hotMiddleware.publish({ action: 'reload' }) cb() }) }) // proxy api requests Object.keys(proxyTable).forEach(function (context) { // 处理代理接口 var options = proxyTable[context] if (typeof options === 'string') { options = { target: options } } app.use(proxyMiddleware(context, options)) }) // handle fallback for HTML5 history API app.use(require('connect-history-api-fallback')()) // serve webpack bundle output app.use(devMiddleware) // 使用自定义中间件 // enable hot-reload and state-preserving // compilation error display app.use(hotMiddleware) // 使用自定义中间件 // serve pure static assets var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) // 处理静态资源目录 app.use(staticPath, express.static('./static')) // 静态资源目录 module.exports = app.listen(port, function (err) { // 监听 if (err) { console.log(err) return } console.log('Listening at http://localhost:' + port + '\n') })
项目目录
`src`全部源码目录 -`main.js`入口文件 -`App.vue` 整个页面是实例文件 -`components` 组件目录 --`header` 子组件目录 ---`header.vue` 具体的组件 --`common` 公共资源 ---`js` 基础库 ---`stylus` css预处理器 ---`fonts` 字体库
数据传递
props 1. 变量名 = data --> 自定义组件的自定义属性 2. props 在child, 变量名在child 父级到子级: 父级: $broadcast 子级: evnets: { events: function () { } } 子级到父级: 父级: evnets: { events: function () {} } 子级: $dispatch
new Vue(options)
el
data
methods
components
computed
wtach
replace
init
created
beforeCompile
compiled
ready
attached
detached
beforeDestroy
destoryed
events
mixins: [mixin]
var vm = new Vue({ el: '选择器', // 挂载到页面的那个元素里,即肯定vue的做用范围,外部能够经过 vm.$el 访问,获得的是一个原生dom元素,可进行对应操做 a: '', // 自定义属性, 外部课经过vm.$options 访问 data: {}, // 实例属性,外部经过实例名, 即vm.$data调用 computed: {}, // 计算属性, 也是实例属性, 只是以方法的形式存在,并能够有逻辑运算的属性 method: {}, // 实例方法 wtach: {}, // 对data和computed的属性进行监听,当属性有变化时,自动触发,以方法的形式存在 外部经过$.watch调用 // 以上属性和方法,实例内部都经过 this调用,外部则经过对应的实例方法访问. // 在vue的生命周期过程当中,提供了一系列的钩子函数,进行自定义逻辑注入 created: function () { // 实例已经建立 }, beforeCompile: function () { // 模块编译以前 }, compiled: function () { // 模块编译以后,即模板占位符被是内容替换 }, ready: function () { // 模板插入到文档中, 至关于window.onload }, // 上面4个方法,在对象被实例化后即按顺序执行 beforeDestroy: function () { // 对象销毁以前 }, destroyed: function () { // 对象销毁以后 } // 上面2个方法需经过事件主动触发, vm.$destory(); 才执行 });
Vue.extend(options)
template
data
props
components
name
mixins: [mixin]
methods
Vue.component(id, options)
props (array | object)
templalte
methods
data