本文是小羊根據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的使用;
參考資料: