本文是小羊根据Vue.js文档进行解读的第一篇文章,主要内容涵盖Vue.js的基础部分的知识的,文章顺序基本按照官方文档的顺序,每一个知识点现附上代码,而后根据代码给予我的的一些理解,最后还放上在线编辑的代码以供练习和测试之用;
在最后,我参考SegmentFault上的一篇技博,对Vue进行初入的实战,目的是将新鲜学到的知识当即派上用场;css
若是你仍是前端的小白,相信这篇文章可能会对产生一些帮助和引发思想的碰撞,由于你们的学习历程是类似的,遇到的困惑也有必定的共通性,若是文章出现谬误之处,欢迎各位童鞋及时指正;html
Vue.js(读音 /vjuː/, 相似于 view) 是一套构建用户界面的 渐进式框架。与其余重量级框架不一样的是Vue 的核心库只关注视图层。
Vue.js 的目标是经过尽量简单的 API 实现响应的数据绑定和组合的视图组件。前端
Vue.js是一种MVVM框架,其中html是view层,js是model层,经过vue.js(使用v-model这个指令)完成中间的底层逻辑,实现绑定的效果。改变其中的任何一层,另一层都会改变;vue
经过构造函数Vue建立一个Vue的根实例jquery
<div id='#el'></div> --- var vm = new Vue({ //options el:'#el', data:{}, methods:{} }) --- //扩展Vue构造器 var MyComponent = Vue.extend({ //扩展选项 }) var vm = new MyComponent({})
解读:ajax
使用Vue构造函数建立一个Vue实例,而后经过Vue实例的el
接口实现和HTML元素的挂载;json
构造函数Vue须要传入一个选项对象,可包含挂载元素、数据、方法和生命周期钩子等;segmentfault
构造函数Vue能够经过extend
方法实现扩展,从而能够用预约义的选项建立可复用的组件构造函数,可是构建组件的经常使用方法是使用Vue.component()
接口去实现;后端
Vue实例将代理data对象的全部属性,也就是说部署在data对象上的全部属性和方法都将直接成为Vue实例的属性和方法api
<div id="app">{{message}} <button v-on:click="sayHello">click me</button> </div> --- var app = new Vue({ el:'#app', data:{ message:'hello world!', sayHello:function(){ console.log(1) } } }) --- //若是想要获取到app这一实例中选项的对象,Vue提供$进行获取 app.$el === document.getElementById('app')//true app.$data.message//hello world
【TIP】
Vue实例所代理data对象上的属性只有在实例建立的同时进行初始化才具备响应式更新,若在实例建立以后添加是不会触发视图更新的;
绑定文本和HTML
<div id = "app"> {{msg}} <div v-html="hi"></div> </div> --- var app = new Vue({ el: '#app', data:{ msg: 'hello world!', hi:'<h1>hi</h1>' } })
解读:
HTML部分实现数据的动态绑定,这个数据是vue实例的属性值;
JS部分的语法能够从jQuery角度去理解,至关于建立一个Vue实例,这个实例指向#app,并在Vue提供的固定接口data上定义Vue实例的属性;
使用{{message}}
的mustache语法只能将数据解释为纯文本,为了输出HTML,可使用v-html
指令;
绑定数据在元素的属性
<div id="app" v-bind:title='message' v-bind:style='red' v-once> {{message}} </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', red: 'color:red' } })
解读:
定义在Vue实例的data接口上的数据的绑定灵活的,能够绑定在DOM节点内部,也能够绑在属性上;
绑定数据到节点属性上时,须要使用v-bind
指令,这个元素节点的 title属性和 Vue 实例的 message属性绑定到一块儿,从而创建数据与该属性值的绑定,也可使用v-bind:href="url"
的缩写方式:href="url"
;
v-once
指令可以让你执行一次性的插值,当数据改变时,插值处的内容不会更新;
【demo】
使用JS表达式处理数据
<div id='#app'> <p v-once>{{num + 10 }}</p> <p v-if='seen'>{{message + 'jirengu'}}</p> </div> --- var app = new Vue({ el: '#app', data:{ num:10, message: 'hello world!', seen:true } })
使用过滤器来格式化数据
<div id="app" > <p v-if='seen'>{{message | capitalize}}</p> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', seen:true, }, filters:{ capitalize:function(value){ if(!value) return '' value = value.toString() return value.charAt(0).toUpperCase() + value.slice(1) } } })
条件指令控制DOM元素的显示操做
<div id="app" > <p v-if='seen'>{{message}}</p> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', seen:true } })
解读:
v-if
指令能够绑定一个属性值为布尔型的属性,当值为真时,元素将显示,反之则消失;
循环指令实现数据的遍历
<div id="app"> <ol> <li v-for='item in items'> {{ item.text }} </li> </ol> </div> --- var app = new Vue({ el: '#app', data:{ items:[ {text:'Vue'}, {text:'React'}, {text:'Angular'} ] } })
解读:
v-for
能够绑定数组型数据进行绑定,并使用item in items
形式,从而数据的遍历操做;
事件绑定指令能够实现事件监听
<div id='app'> <p>{{message}}</p> <button v-on:click='reverseMessage'>reverseMesssage</button> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!' }, methods:{ reverseMessage:function(){ this.message = this.message.split('').reverse().join('') } } })
解读:
v-on
指令用于监听事件操做,click="reverseMessage"
定义点击事件后执行的回调函数;
v-on
指令也能够采用缩写方式:@click="method"
在Vue实例中,提供methods接口用于统必定义函数;
小结
本章涉及Vue的基础的数据绑定操做,内容包括:
{{message}}
实现文本数据的绑定,而且文本数据可使用JS表达式和过滤器进行进一步处理;
- v-html="hi"
实现HTML数据的绑定;
v-bind:href="url"
实现属性数据的绑定;
v-if="seen"
和v-for="item in items"
指令实现流程控制;
v-on:click="method"
指令实现事件监听
使用计算属性完成一些数据计算操做
<div id="app" > <p>Original message : {{message}}</p> <p>Reversed message : {{ReversedMessage}}</p> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', }, computed:{ ReversedMessage:function(){ return this.message.split('').reverse().join('') } } })
解读:
Vue实例提供computed
对象,咱们能够在对象内部定义须要进行计算的属性ReverseMessage
,而提供的函数将做为属性的getter,即获取器;
上述的代码使得app.ReverseMessage
依赖于app.message
;
与先前直接在{{message.split('').reverse().join('') }}
使用表达式相比,它让模板太重而且难以维护代码;
计算属性 VS Methods
<div id="app" > <p>Original message : {{message}}</p> <p>Reversed message : {{ReversedMessage}}</p> <p>Reversed message:{{reversedMessage()}}</p> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', }, computed:{ ReversedMessage:function(){ return this.message.split('').reverse().join('') } }, methods:{ reversedMessage:function(){ return this.message.split('').reverse().join('') } } })
解读:
经过Vue实例的methods接口,咱们在模板中调用reversedMessage
函数一样实现需求;
methods与computed方法的区别在于:computed的数据依赖于app.message
,只要message
未变,则访问ReverseMessage
计算属性将当即返回以前的计算结果,而methods则每次从新渲染时老是执行函数;
若是有缓存须要,请使用computed方法,不然使用methods替代;
计算属性的setter
Vue实例的computed
对象默认只有getter,若是你要设置数据,能够提供一个setter,即设置器;
<div id="app" > <p>Hi,I'm{{fullName}}</p> </div> --- var app = new Vue({ el: '#app', data:{ message: 'hello world!', name:'Teren' }, computed:{ fullName:{ get:function(){ return this.name }, set:function(value){ this.name = value } } } })
绑定Class
<div id="app" > <!-- 直接绑定对象的内容 --> <p class='static' v-bind:class="{active:isActive,error:hasError}">Hello world!</p> <!-- 绑定对象 --> <p v-bind:class="classObj">こんにちは </p> <p v-bind:class='style' >你好</p> <!-- 绑定数组 --> <p v-bind:class="[staticClass,activeClass,errorClass]"> Olá</p> <button @click='changeColor'>click me</button> </div> --- //css .static{ width: 200px; height: 100px; background: #ccc; } .active{ color:red; } .error{ font-weight: 800; } --- var app = new Vue({ el: '#app', data:{ isActive:true, hasError:true, classObj:{ static:true, active:true, error:true, }, staticClass:'static', activeClass:'active', errorClass:'error', }, computed:{ style:function(){ return { active: this.isActive, static:true, error:this.hasError } } }, methods:{ changeColor:function(){ this.isActive = !this.isActive } } })
解读:
经过v-bind:class="{}"
或v-bind:class=[]
方式为模板绑定class
经过v-bind:class="{active:isActive,error:hasError}"
绑定class,首先要在css中设置.active
和,error
,而后在Vue实例的data对象中设置isActive
和hasError
的布尔值;也能够直接传一个对象给class,即v-bind:class="classObj
,再在data对象上直接赋值:
data:{ classObj:{ static:true, active:true, error:true, }
你也能够经过传递数组的方式为class赋值v-bind:class="[staticClass,activeClass,errorClass]"
,此时你要在data对象上为数组的元素的属性赋值:
data:{ staticClass:'static', activeClass:'active', errorClass:'error', }
【TIP】不管是哪一种方式,前提都是css中的class要先设定
绑定style
<div id="app" > <p v-bind:style='styleObj'>Hello World!</p> <p v-bind:style='[styleObj,bgObj]'>你好</p> </div> --- var app = new Vue({ el: '#app', data:{ styleObj:{ fontWeight:800, color:'red' }, bgObj:{ width:'100px', height:'80px', background:'#ccc' } }, })
解读:
绑定style到模板的方法有两种,一是v-bind:style="styleObj"
,而后在data对象上定义styleObj;而是能够经过数组方式为style传入多个样式对象
前面简单介绍了一下v-if
、v-for
和v-on
指令,下面的部分将详细介绍以上3个指令;
条件渲染
<div id="app" > <p v-if='ok'>Hello World!</p> <p v-else>Hello Universal</p> <template v-if='motto'> <h1>Steve Jobs</h1> <p>motto:stay hungry ! stay foolish</p> </template> <p v-show='ok'>Show Me</p> </div> --- var app = new Vue({ el: '#app', data:{ ok:true, motto:true, }, })
解读:
经过v-if
和v-else
指令实现条件渲染,其中v-if="value"
的valuey
要在data对象中赋布尔值,v-if
支持<template>
语法
v-show="value"
是另外一种条件渲染的方法;
【TIP】 v-if和v-show的区别
v-if是真实的条件渲染,当进行条件切换时,它会销毁和重建条件块的内容,而且它支持<template>
语法;
v-show的条件切换时基于css的display属性,因此不会销毁和重建条件块的内容;
当你频繁须要切换条件时,推荐使用v-show;不然使用v-if;
列表渲染
<div id="app" > <ol> <li v-for='car in cars'> {{car.name}} </li> </ol> <ul> <li v-for='(food,index) in foods'> {{index}}---{{food}}---{{delicious}} </li> </ul> <ul> <li v-for='(value,key,index) in object'> {{index}}.{{key}}.{{value}} </li> </ul> <div> <span v-for='n in 10' style="margin-left:5px">{{n}}</span> </div> <span v-for='n in evenNumbers' style="margin-left:5px">{{n}}</span> </div> <!-- <div> <span v-for='n in odd(counts)' style="margin-left:5px">{{n}}</span> </div> --> </div> --- var app = new Vue({ el: '#app', data:{ delicious:'delicious', cars:[ {name:'Benz'}, {name:'BMW'} ], foods:[ 'tomato', 'potato', 'ice cream' ], object :{ name:'Benz', age:'18' }, numbers:[1,2,3,4,5,6,7,8,9,10], counts:[1,2,3,4,5] }, computed:{ evenNumbers:function(){ return this.numbers.filter(function(number){ return number%2 === 0 }) } }, methods:{ odd:function(counts){ return counts.filter(function(count){ return count%2 === 1; }) } } })
解读:
v-for
指令可以让咱们循环渲染列表型数据,数据放在data对象中,类型能够以下:
data:{ //数字数组 numbers:[1,2,3,4,5,6,7,8,9,10], counts:[1,2,3,4,5] //字符串数组 foods:[ 'tomato', 'potato', 'ice cream' ], //对象数组 cars:[ {name:'Benz'}, {name:'BMW'} ], //对象 object :{ name:'Benz', age:'18' }, }
根据不一样类型的数据,v-for
指令在模板中具体采用的语法以下:
//数据为数字数组 <div> <span v-for="n in numbers">{{n}}</span> </div> --- //数据为字符数组 <ul> <ol v-for='food in foods'>{{food}}</ol> </ul> --- //数据为对象 <ul> <ol v-for="value in object">{{value}}</ol> </ul> //或者 <ul> <ol v-for="(value,key,index) in object">{{index}}.{{key}}.{{value}}</ol> </ul> --- //数据为对象数组 <ul> <ol v-for="car in cars">{{car.name}}</ol> </ul>
在 v-for块中,咱们拥有对父做用域属性的彻底访问权限;
简单的事件监听——直接在指令上处理数据
<div id="#app"> <p v-on:click="counter+=1">{{counter}}</p> </div> --- var app = new Vue({ el: "#app", data:{ counter: 0, } })
复杂的事件监听——在methods对象定义回调函数
<div id="#app"> <p v-on:click="greet">{{vue}</p> </div> --- var app = new Vue({ el: "#app", data:{ vue:"hello Vue.js" }, methods:{ greet:function(event){ console.log(this.vue) } } })
事件修饰符——调用事件对象函数的快捷方式
<div v-on:click.prevent="greet">1</div>//等价于event.preventDefault() <div v-on:click.stop="greet">2</div>//等价于event.stopPropagation() <div v-on:click.capture="greet">3</div>//等价于事件回调函数采用捕获阶段监听事件 <div v-on:click.self="greet">4</div>//等价于event.target
按键修饰符——按键事件的快捷方式
常见按键别名包括: - enter - tab - delete - esc - space - up - down - left - right
文本控件
<div id="app"> <p>{{message}}</p> <input type="text" v-model='message'> </div> --- var app = new Vue({ el:'#app', data:{ message:'Hello World!' }, })
解读:
经过v-model
指令能够实现数据的双向绑定,即View层的数据变化能够直接改变Model层的数据,而Model层的数据改变也能够直接反映在View层;
上述代码v-model="message"
使得input的value属性和message属性绑定,在输入框输入值,即改变value同时也改变message;
单选控件
<input id="man" value="man" type="radio" v-model='picked'> <label for="man">Man</label> <br> <input id="woman" value="woman" type="radio" v-model='picked'> <label for="woman">Woman</label> <div style="margin-left:10px">{{picked}}</div> --- var app = new Vue({ el:'#app', data:{ message:'Hello World!', picked:'man' }, })
解读:
v-model
指令绑定data对象的picked属性,该属性默认指向type='radio'的input的value;
复选框
<input type="checkbox" id="Benz" v-model='checked' value='Benz'> <label for="Benz">Benz</label> <input type="checkbox" id="BMW" v-model='checked' value="BMW"> <label for="BMW">BMW</label> <div>Checked Name:{{checked}}</div> --- var app = new Vue({ el:'#app', data:{ message:'Hello World!', picked:'man', selected:"A", checked:[], }, })
组件能够扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素;
经过Vue.component()接口将大型应用拆分为各个组件,从而使代码更好具备维护性、复用性以及可读性
注册组件
<div id="app"> <my-component></my-component> </div> --- Vue.component('my-component',{ template:'<div>my-first-component</div>' }) var app = new Vue({ el:'#app', data:{ } })
解读:
注册行为必须在建立实例以前;
component的template接口定义组件的html元素;
局部注册组件
<div id="app"> <my-component> <heading></heading> </my-component> </div> --- Vue.component('my-component',{ template:'<div>my-first-component</div>' }) var Child = { template: '<h3>Hello World</h3>' } var app = new Vue({ el:'#app', components:{ 'my-component':Child } })
解读:
能够定义一个子组件,在实例的components
接口中将子组件挂载到父组件上,子组件只在父组件的做用域下有效;
特殊DOM模板将会限制组件的渲染
像这些包含固定样式的元素 <ul>, <ol>, <table>, <select>
,
自定义组件中使用这些受限制的元素时会致使渲染失败;
通的方案是使用特殊的 is属性:
<table> <tr is="my-component"> </table>
建立组件的data对象必须是函数
<counter></counter> <counter></counter> <counter></counter> --- Vue.component('counter',{ template:'<button @click="count+=1">{{count}}</button>', data:function(){ return { count: 0 } } })
解读:
在组件当中定义的数据count
必须以函数的形式返回;
使用Props实现父组件向子组件传递数据
<child some-text='hello'></child> <br> <child v-bind:some-text='message'> </child> --- Vue.component('child',{ template:'<div>{{someText}}</div>', props:['someText'] }) var app = new Vue({ el:'#app', components:{ 'my-component':Child }, data:{ message:"你好" } })
解读:
组件实例的做用域是孤立的。这意味着不能而且不该该在子组件的模板内直接引用父组件的数据。可使用 props 把数据传给子组件;
能够用 v-bind动态绑定 props 的值到父组件的数据中。每当父组件的数据变化时,该变化也会传导给子组件,注意这种绑定方式是单向绑定;
父组件是使用 props 传递数据给子组件,但若是子组件要把数据传递回去则使用自定义事件!
<div id="app"> <p>{{total}}</p> <button-counter v-on:increment='incrementTotal'></button-counter> <button-counter @increment='incrementTotal'></button-counter> </div> --- Vue.component('button-counter',{ template:'<button v-on:click="increment">{{counter}}</button>', data:function(){ return { counter:0 } }, methods:{ increment:function(){ this.counter +=1; this.$emit('increment') } } }) var app = new Vue({ el:'#app', data:{ total:0 }, methods:{ incrementTotal:function(){ this.total += 1; } } })
解读:
父组件能够经过监听子组件的自定义事件,从而改变父组件的数据;
子组件每点击一次,触发increment函数,该函数在执行过程当中经过$emit('increment')
发出increment
事件;
button
控件同时监听increment
事件,每次发出该事件就改变父组件的total
值;
【demo】
使用Slots分发内容
内容分发指的是混合父组件的内容与子组件本身的模板;
<div id="app"> <h1>I'm the parent title</h1> <my-component> <p>This is some original content</p> <p>This is some more original content</p> </my-component> <hr> </div> --- Vue.component('my-component',{ template:"<div><h2>I'm the child title</h2><slot>若是没有分发内容则显示我。</slot></div>" }) var app = new Vue({ el:'#app', data:{ }. })
解读:
若是子组件模板一个<slot>
都不包含,则父组件内容将会被丢弃;
当子组件模板只有一个没有属性的 slot 时,父组件整个内容片断将插入到 slot 所在的 DOM 位置,并替换掉 slot 标签自己;
只有在宿主元素为空,且没有要插入的内容时才显示备用内容;
//子组件app-layout模板 <div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> //父组件模板 <app-layout> <h1 slot="header">Here might be a page title</h1> <p>A paragraph for the main content.</p> <p>And another one.</p> <p slot="footer">Here's some contact info</p> </app-layout> //渲染结果 <div class="container"> <header> <h1>Here might be a page title</h1> </header> <main> <p>A paragraph for the main content.</p> <p>And another one.</p> </main> <footer> <p>Here's some contact info</p> </footer> </div>
解读:
具名slot
至关于给slot
设置标识符,只要在父组件的元素上设置<div slot="name"></div>
就能够把该元素插入子组件定义的模板;
【TIP】关于组件的命名规范
当注册组件(或者 props)时,可使用 kebab-case ,camelCase ,或 TitleCase
// 在组件定义中 components: { // 使用 camelCase 形式注册 'kebab-cased-component': { /* ... */ }, 'camelCasedComponent': { /* ... */ }, 'TitleCasedComponent': { /* ... */ } }
在 HTML 模版中,请使用 kebab-case 形式:
<kebab-cased-component></kebab-cased-component> <camel-cased-component></camel-cased-component> <title-cased-component></title-cased-component>
为了记忆方便,建议统一使用kebab-case形式;
使用vue-rescource实现先后端的通讯
在vue实例中新增ready对象,当页面完成加载时发出请求
new Vue({ el: '#app', ready: function() { this.$http.get('book.json', function(data) { this.$set('books', data); }).error(function(data, status, request) { console.log('fail' + status + "," + request); }) //post方法:this.$http.post(url,postdata,function callback) }, data: { .... books:'' }, .....
【TIP】
这个$http请求和jquery的ajax仍是有点区别,这里的post的data默认不是以form data的形式,而是request payload。解决起来也很简单:在vue实例中添加headers字段:
http: { headers: {'Content-Type': 'application/x-www-form-urlencoded'} }
上面的Vue小做品是小羊仿照SegmentFault的一篇技博的练手之做,建议各位对照源码亲手练习一次,以便初步熟悉Vue的使用;
参考资料: