Vue.js學習筆記

 

第一個demo

Hello Vue!
關鍵詞:模板語法、聲明式javascript

這裏有個小bug,JSFiddle Hello World例子中,並無爲new Vue賦值變量,因而教程中接下來講的,「修改app.message」就無法實現,認真看教程中代碼能夠看到它爲其賦值命名爲app,下一個例子命名爲app-2,命名後就能夠在控制檯採用「名稱.屬性」的形式訪問修改內容了。php

第二個demo

新指令:v-bind
用法css

  • html——v-bind:title="message"
  • js——data:{message:'內容'}

新指令:v-if
用法:根據值的真假決定是否渲染DOM內容
原理:Vue能夠綁定DOM結構到數據html


新指令:v-for
用法vue

  • html——<li v-for="todo in todos">{{todo.text}}</li>
  • js——data:{todos:[{text:"內容1"},{text:"內容2"},{text:"內容3"}]}

原理:v-for是一個包裝過的for in循環,對應的data內須要有一個數組java


新指令:v-on
用法python

  • html——綁定事件----v-on:click="事件名字"
  • js——methods:{事件名字:function(){處理內容}}

新指令:v-model
用法:webpack

  • html——<input v-model="message">
  • js——data:{message:"hello vue"}

原理:v-model可實現表單輸入和應用狀態的雙向綁定,修改表單內容,message對應值也會修改。git

組件化應用構建

  • 註冊組件
Vue.component('todo-item',{ template:'<li>這是一個待辦項</li>' }) 
  • 使用
<ol>
    <todo-item></todo-item> </ol> 

可是這樣實現,會爲每一個元素綁定相同文本,Vue能夠將數據從父做用域傳到子組件。web

  • 註冊組件
Vue.component('todo-item', { props: ['todo'], template: '<li>{{ todo.text }}</li>' }) 
  • 建立元素並v-bind綁定數據到一個對象
<div id="app-7">
  <ol>
    <todo-item v-for="item in groceryList" v-bind:todo="item"></todo-item>
  </ol>
</div>

 

  • 建立對象
var app7 = new Vue({
  el: '#app-7',
  data: {
    groceryList: [
      { text: '蔬菜' },
      { text: '奶酪' },
      { text: '隨便其餘什麼人吃的東西' }
    ]
  }
})

 

  • props是做爲一個接口存在的。
  • Vue組件很是相似於自定義元素,可是有一些純自定義元素不具有的重要功能,包括跨組件數據流,自定義事件通訊和構建工具集成。

Vue實例

  • Vue 構造器
  • Vue.extend({})能夠擴展Vue構造器
  • 每一個Vue實例都會代理其data對象裏面的全部屬性,即實例.屬性===data.屬性
  • 實例引用內部屬性和方法須要加前綴$
vm.$el===document.getElementById('exzample'); 
  • 實例聲明週期與鉤子
    created是實例被建立後調用,還有mounted、updated、destroyed,鉤子的this指向調用它的實例

模板語法

  • 文本:雙大括號的文本插值(默認是響應式的,對應屬性的值變化,此處內容會更新)
<span>Message:{{ msg}}</span> 

也能夠經過v-once執行一次性插值,再也不更新內容,可是這會影響這個節點的全部數據綁定

<span v-once>This will never change:{{message}}</span> 
  • 純HTML:用v-html能夠輸出真正的html
<div id="app-8" v-html='rawHtml'>   </div>
var app8=new Vue({
        el:'#app-8',
        data:{
            rawHtml:'<li>純html</li>'
        }
    })
//輸出:● 純html

  

可是要注意只對可信內容使用html插值,否則容易致使xss攻擊

  • 屬性:html屬性不能用雙大括號語法,須要用v-bind。
<div id="app-2"> <span v-bind:title="message">懸停幾秒看信息</span> </div> 
  • 全部的數據綁定均可以用js表達式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>

  

然而,語句和流控制是不行滴,三元表達式是能夠的

{{var a = 1 }} {{if(ok){return message}}} 
  • 指令:帶有v-前綴的特殊屬性,它的值預期是單一js表達式,指定的職責是,當表達式的值改變時相應的將某些行爲應用到DOM上。
  • 部分指令接收一個參數,在指令後以冒號指明,好比v-bind:href="url"
    還好比v-on:click="方法名"綁定一個事件
  • 修飾符,以半角句號指明的特殊後綴,指出一個指令應該以特殊方式綁定,.prevent 修飾符告訴 v-on 指令對於觸發的事件調用 event.preventDefault():
<form v-on:submit.prevent="onSubmit"></form> 
  • 過濾器:大括號語法和v-bind表達式,用於文本轉換
<div id="app-9">{{message|format}}</div> var app9=new Vue({ el:'#app-9', data:{ message:'hello,Filters!' }, filters:{ format:function(value){ value=value.toLowerCase() return value.charAt(0).toUpperCase()+value.slice(1) } } }) 

過濾器能夠串聯,能夠接受參數

  • 縮寫:v-bind縮寫爲空,後接冒號
<a v-bind:href="url"></a> <a :href="url"></a> 

v-on縮寫爲@,並省略了後面的冒號

<a v-on:click="doSomething"></a> <a @click="doSomething></a> 

計算屬性

  • 聲明一個計算屬性,其後的函數,將會用做調用屬性時的getter
    computed:{內容}——computed是關鍵字
  • computed計算屬性 vs methods函數調用:
    計算屬性基於依賴進行緩存,只要message不變,屢次訪問都是返回以前的結果,而函數調用是隻要發生從新渲染就會執行該函數——例如,在計算緩存裏返回Date.now(),再也不更新,由於Date.now()不是響應式依賴。
  • computed vs watch
    watch用來觀測,可是有些狀況用computed更方便。
  • computed不止有getter,還有setter,須要顯式設置:
var app11=new Vue({
        el:'#app-11',
        data:{
            firstName:'Foo',
            lastName:'Bar'
        },
        computed:{
            fullName:{
                get:function(){
                    return this.firstName+' '+this.lastName
                },
                set:function(newValue){
                    var names = newValue.split(' ')
                    this.firstName=names[0]
                    this.lastName=names[names.length-1]
                }   
            }
            
        }
    })

  

class和style綁定

對class的加強綁定:

  • 傳入一個對象:
<div id="app-01" v-bind:class="{active:isActive}"></div>
var app01=new Vue({
        el:'#app-01',
        data:{
            isActive:true
        }
    })
//div class="active"

  

  • v-bind:class可與普通class屬性共存,並能夠傳入更多屬性來動態切換:
<div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }"> </div> 
  • 還能夠綁定爲一個對象:
<div id="app-02" v-bind:class='classObject'></div>
var app02=new Vue({
        el:'#app-02',
        data:{
            classObject:{
            active:true,
            'text-danger':false
            }
        }
        
    })

  

  • 還能夠結合計算屬性,加入函數
computed: {
  classObject: function () { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal', } } } 

總結:只要冒號後的數據形式爲‘名稱:布爾值’就能夠

  • 能夠傳入數組
    數組語法涉及邏輯判斷不多,能夠理解爲對象語法的組合版。
<div v-bind:class="[activeClass, errorClass]"> data: { activeClass: 'active', errorClass: 'text-danger' } <div v-bind:class="[{ active: isActive }, errorClass]"> 
  • 能夠用在組件上
<my-component v-bind:class="{ active: isActive }"></my-component> 

和內置元素的使用差很少

對style樣式加強綁定:
因爲默認格式裏就包括一對引號,要注意單雙引號的區分,否則會出錯

<div id='app-03' v-bind:style='{color:activeColor,fontSize:fontSize + "px"}'>
<p>1111</p>
</div>
var app03=new Vue({
        el:'#app-03',
        data:{
            activeColor:'red',
            fontSize:30
        }
    })

  

條件渲染

  • v-if/v-else
<div id="app-04"> <p v-if="ok">Yes</p> <p v-else>No</p> </div> var app04=new Vue({ el:'#app-04', data:{ ok:false } }) 
  • template能夠做爲一個包裝元素,包裹多個須要同一個v-if的元素
<div id="app-04"> <template v-if="ok"> <h1>Title</h1> <p>Para</p> </template> <p v-else>No</p> </div> 
  • 還有一個v-else-if做爲鏈式使用判斷
  • template包裝起來,用v-if和v-else判斷的組件,默認是複用的,不想複用,給各自添加一個不一樣名稱的key就能夠了。
    複用的以下:
<div id="app-05">
<template v-if="loginType==='username'">
    <label for="">Username</label>
    <input placeholder="Enter your username">
</template> 
<template v-else>
    <label for="">Email</label>
    <input placeholder="Enter your email address">
</template>
<button v-on:click="toggle">Toggle login type</button>
</div>
var app05=new Vue({
        el:'#app-05',
        data:{
            loginType:'username'
        },
        methods:{
            toggle:function(){
                this.loginType==='username'?this.loginType='email':this.loginType='username'
            }
        }

    })

  

不復用的以下:

<div id="app-05">
<template v-if="loginType==='username'">
    <label>Username</label>
    <input placeholder="Enter your username" key="username">
</template> 
<template v-else>
    <label>Email</label>
    <input placeholder="Enter your email address" key="email">
</template>
<button v-on:click="toggle">Toggle login type</button>
</div>

  

  • v-show始終都會渲染,簡單的切換display屬性,不支持template語法,也不支持v-else
<h1 v-show='ok'>222</h1> 

v-show vs v-if
v-show適合頻繁切換,v-if適合條件不太改變的狀況

列表渲染

  • 基本用法:v-for = "item in items",items是源數組,item是數組元素迭代的別名
<ul id="app-06">
    <li v-for="item in items">{{item.message}}</li>
</ul>
var app06=new Vue({
        el:'#app-06',
        data:{
            items:[
            {message:'Foo'},
            {message:'Bar'}
            ]
        }
    })

  

  • v-for支持索引參數,可是是從0開始滴(改成{{index+1}}就是從1開始了),而且擁有對父做用域的徹底訪問權限,能夠引用其餘屬性,好比例子中的parentMessage
<ul id="app-06"> <li v-for="(item,index) in items">{{parentMessage}}-{{index}}-{{item.message}}</li> </ul> 
  • 還能夠用of替代in做爲分隔符,更接近js迭代器
  • 支持template組合語句單元
<ul id="app-07"> <template v-for="(item,index) in items"> <span>組合列表{{index+1}}</span> <li>{{item.message}}</li> </template> </ul> 
  • 對象迭代
    v-for = "value in object"——object是一個擁有多個屬性的對象,再也不是數組。
    不一樣於數組迭代,對象迭代是三個參數,分別爲迭代內容,迭代鍵值和參數:(item,key ,index)順序固定
<ul id="app-08"> <li v-for="(item,key,index) in object"> {{item}}-{{key}}-{{index}} </li> </ul> 
  • v-for也可作簡單的數字循環:
<ul id='app-09'> <li v-for="n in 10">{{n}}</li> </ul> 

可是一樣須要創建Vue對象,

var app09=new Vue({ el:'#app-09' }) 
  • ‘就地複用’的選擇:與v-if相同,添加惟一key屬性值能夠不復用,v-for中最好綁定一個惟一id
<ul id="app-10" > <li v-for="(item,index) in items" :key='item.id=index+3'>{{item.message}}-{{index}}-{{item.id}}</li> </ul> 

這裏我綁了元素的index在id上

  • 包含一組觀察數組的變異方法:
  • push()——數組末端添加新項(返回新長度)
  • pop()——刪除數組最後一項(返回元素值)
  • shift()——刪除數組第一項(返回元素值)
  • unshift()——數組頭部添加新項(返回新長度)
  • splice()——添加或刪除項目
  • sort()
  • reverse()
  • 包含幾個非變異數組方法(變異是指改變原數組):
  • filter()
  • concat()
  • slice()
  • 數組操做方法的侷限:
  • 不能經過索引值直接設置一個項:
vm.items[indexOfItem] = newValue
  • 可是能夠用set方法設置:
Vue.set(example1.items,indexOfItem,newValue) 
  • 或者用萬能的splice:
example1.items.splice(indexOfItem,1,newValue) 

注意這裏的第二個參數爲"1",表示原地替換原元素

  • 不能直接修改數組長度:
vm.items.length = newLength

可是依舊能夠用萬能的splice:

example1.items.splice(newLength) 第二個參數爲刪除個數,不填第二個參數時表示刪除到末尾 

此處翻閱了犀牛書和高程,高程中沒提到splice()省略第二個參數的狀況,犀牛書提到了,省略第二個參數,從起始點到結尾的全部元素都將被刪除。查了ecma-262的文檔,原文是:

5 If the number of actual arguments is 0, then a. Let insertCount be 0. b. Let actualDeleteCount be 0. 6 Else if the number of actual arguments is 1, then a. Let insertCount be 0. b. Let actualDeleteCount be len ‑ actualStart. 
  • 顯示過濾、排序結果
  • 使用計算屬性computed
<ul id="app-11">
    <li v-for="n in evenNumbers">{{n}}</li>
</ul>
var app11=new Vue({
        el:'#app-11',
        data:{
            numbers:[1,2,3,4,5]
        },
        computed:{
            evenNumbers:function(){
                return this.numbers.filter(function(number){
                    return number%2 === 0
                })
            }
        }
    })

  

  • 使用方法,methods——區別很小,引用時須要傳入參數
<ul id="app-11"> <li v-for="n in evenNumbers(numbers)">{{n}}</li> </ul> var app11=new Vue({ el:'#app-11', data:{ numbers:[1,2,3,4,5] }, methods:{ evenNumbers:function(){ return this.numbers.filter(function(number){ return number%2 === 0 }) } } }) 

事件處理器

  • 最簡單的把處理代碼寫在v-on:click裏:
<div id="app-12"> <button v-on:click="counter+=1">增長1</button> <p>這個按鈕被點擊了{{counter}}次</p> </div> var app12=new Vue({ el:"#app-12", data:{ counter:0 } }) 
  • 命名一個方法,把方法名寫在v-on:click後
  • 能夠傳參數
<div id="app-13"> <button v-on:click="say('hi')">1</button> <button v-on:click="say('what')">2</button> </div> var app13=new Vue({ el:'#app-13', data:{ message:'new event!' }, methods:{ say:function(m){ alert(m) } } }) 
  • 能夠訪問原生DOM事件,用特殊變量$event傳入
<div id="app-14"> <button v-on:click="mod('event is modified',$event)">submit</button> </div> var app14=new Vue({ el:'#app-14', methods:{ mod:function(message,e){ if(e)e.preventDefault() alert(message) } } }) 

代碼中點擊button會觸發一個click事件,把event做爲參數傳入,就能夠對這個事件進行操做

  • 事件修飾符
    從方法中拆分出了事件處理過程給指令,表達更直觀。
  • .stop——阻止冒泡
  • .prevent——?
  • .capture——捕獲事件
  • .self——該元素自己(而不是子元素)時觸發回調
  • .once——點擊事件只會觸發一次
  • 按鍵修飾符:用於監聽鍵盤事件
<input type="text" id="app-1" v-on:keyup.13="submit()"> var app1=new Vue({ el:'#app-1', methods:{ submit:function(){ alert('success') } } }) 

keyup.13是"enter"
還有別名:

<input type="text" v-on:keyup.13="submit"> <input type="text" v-on:keyup.enter="submit"> <input type="text" @keyup.enter="submit"> 
  • .enter
  • .tab
  • .delete
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right
  • .ctrl
  • .alt
  • .shift
  • .meta
  • 還能夠自定義別名:
Vue.config.keyCodes.f2=113

表單控件綁定

v-model本質上是語法糖,監聽輸入事件以更新數據

  • 基礎用法:
<div id="app-2"> <input type="text" v-model="message" placeholder="'edit me"> <p>Message is:{{message}}</p> </div> var app2=new Vue({ el:'#app-2', data:{ message:'' } }) 

多行文本同理

  • 單選框很方便
<div id="app-3"> <input type="checkbox" id="chechbox" v-model="checked"> <label for="checkbox">{{checked}}</label> </div> var app3=new Vue({ el:'#app-3', data:{ checked:false } }) 

這裏,checked預設值若是設爲空,則開始時label沒有內容,若是設爲true,則選框會默認選上,因此最好只設爲false

  • 複選框可共用v-model
<div id="app-4"> <input type="checkbox" value="Jack" v-model="checkedNames" id="jack"> <label for="jack">jack</label> <input type="checkbox" value="John" v-model="checkedNames" id="john"> <label for="john">john</label> <input type="checkbox" value="Mike" v-model="checkedNames" id="mike" > <label for="mike">mike</label> <br> <span>checked names: {{ checkedNames }}</span> </div> var app4=new Vue({ el:'#app-4', data:{ checkedNames:[] } }) 
  • 單選按鈕
  • 單選列表
<div id="app-6"> <select name="" id="" v-model="selected"> <option>A</option> <option>B</option> <option>C</option> </select> <span>selected:{{selected}}</span> </div> var app06=new Vue({ el:'#app-6', data:{ selected:"" } }) 

此處遇到一小問題,創建option時,emmet的補全加了屬性value='',若是不改動的話,默認option的值是爲空的,選中無效,須要刪除這個屬性或者顯式填值

  • 多選列表,在select處添加屬性,multiple="multiple"就能夠了。多選時按住ctrl或command鍵才能夠多選
  • 動態選項值
<div id="app-6"> <select v-model="selected"> <option v-for="option in options" v-bind:value="option.value">{{option.text}}</option> </select> <span>selected:{{selected}}</span> </div> var app06=new Vue({ el:'#app-6', data:{ selected:'A', options:[ {text:'One',value:'A'}, {text:'Two',value:'B'}, {text:'Tree',value:'C'} ] } }) 

此例子將選項內容與選項值區分紅兩組數據,而selected顯示的是value的內容,同上一個小問題相同,option不顯式設置值時,option標籤內容即爲值,顯式設置後,value值會覆蓋標籤內容被髮送。

  • 動態value值
    v-model綁定的value一般是靜態字符串,經過v-bind能夠動態綁定變量到value上,語法是v-bind:true-value/v-bind:false-value
<div id="app-7"> <input id="bindvalue" type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value='b'> <label for="bindvalue">{{toggle}}</label> </div> var app07=new Vue({ el:'#app-7', data:{ toggle:'false', a:'true', b:'false' } }) 

例子中綁定了true-value到a變量,false-value到b變量
單選框同理:

<input type="radio" v-model='pick' v-bind:value="a"> 
  • 修飾符
  • .lazy——默認狀況下v-model載input事件中同步輸入框的值與數據,添加一個.lazy修飾符後,轉變爲在change事件中同步,問題是,change事件是神馬?存疑
<input v-model.lazy="msg"> 
  • .number自動將輸入值轉爲Number類型
<input v-model.number='age' type='number'> 

這個例子玄機不少:
輸入字母e/E狀況特殊,會被理解爲指數標誌,不一樣設定效果不一樣:
1. 只設置type爲number:字母輸入無效;e後爲有效數字時會正常顯示,好比:

輸入:123abc456,
框內顯示爲:123456,值顯示爲123456
、、、
輸入:123e12,
框內顯示爲:123e12  值顯示爲:123e12

可是超過必定數值會顯示爲空:

(很大很大一個數字)顯示爲:
123e1234 值顯示爲:

然而負指數會正確顯示:

123e-1234 值顯示爲 123e-1234
2. 只設置v-model爲number時:
輸入:123abc456,
框內顯示爲123abc456,失去焦點時更新爲123,
值顯示爲123
、、、
輸入:abc123,
框內顯示爲abc123,失去焦點沒變化,
值顯示爲abc123,說明斷定失效啦
、、、
123e12 值顯示爲:123000000000000
——同時輸入框內會被更新成123000000000000

指數e超過必定數值會顯示爲Infinity

123e1234值顯示爲:Infinity ——同時輸入框內會被更新成Infinity 

在一個範圍內的負指數會被格式化後顯示,
超過必定值的負指數會被顯示爲0:

123e-123 值顯示爲:1.23e-121 123e-1234 值顯示爲:0 ——同時輸入框內會被更新 
3. 設置type爲number而且v-model爲number時: 
輸入123abc456,
框內顯示爲:123456,值顯示爲123456
、、、
輸入abc123,
框內顯示爲:123,值顯示爲123
、、、
123e12 值顯示爲:123000000000000
——同時輸入框內會被更新成123000000000000
指數大於20位會轉化成指數形式

超過必定數值顯示爲空:

123e1234 值顯示爲:

在一個範圍內的負指數會被格式化後顯示,
超過必定值的負指數會被顯示爲0:

123e-123 值顯示爲:1.23e-121 123e-1234 值顯示爲:0 ——同時輸入框內會被更新 

總結:控制數字輸入的主要依賴type="number",v-model.number是將輸入值轉化爲Number類型,可是表現不太穩定。

  • .trim自動過濾用戶輸入的首尾空格:
空空abc空空def空空 ——> abc空空def 

組件

  • 基礎語法:
<div id="app-01"> <my-component></my-component> </div> Vue.component('my-component',{ template:'<div>A custom component!</div>' }) var app01=new Vue({ el:'#app-01' }) 

要確保,先註冊組件,再初始化實例,調換先後順序會出錯

  • 局部註冊:把組件用components註冊在實例中,注意components爲複數形式,好處是限制了做用域
<div id="app-01"> <my-component></my-component> </div> var app01=new Vue({ el:'#app-01', components:{ 'my-component':{ template:'<div>A custom component!</div>' } } }) 

注意此處至關於先實例再在實例中註冊組件,所以能夠判斷,註冊組件行爲不能落後於實例化,可是能夠包含在實例的同時進行。

  • DOM模板解析——當把模板加載到一些已存在的元素上時,可能會受到HTML的一些限制,由於像一些ul/ol/table/select限制了能被它包裹的元素,而一些如option的元素只能出如今某些元素內部,所以,有時自定義組件會失效而出錯:
<table>
  <my-row>...</my-row> </table> 

須要使用特殊的is屬性:

<table id="app-01"> <tr is="my-component"></tr> </table> 

這至關於把組件假裝成一個tr ,查看瀏覽器文檔結構解析爲:

<table id="app-01"> <tbody> <div>A custom component</div>——(組件內容) </tbody> </table> 

tbody問題
此處出現的tbody是html解析自動補全的,tbody功能爲,劃分表格結構,默認狀況下是一個tbody,也可手動創建多個並行的tbody,這影響表格分別渲染及切分(很長的表格換頁的時候斷在哪裏就是切分)

  • 限制不適用狀況沒看懂(存疑):
    • <script type="text/x-template">----這個解決了,後面有解釋
    • JavaScript內聯模版字符串
    • .vue 組件
  • 組件關聯構造器的data必須是函數,不然會報錯,深層次的緣由是,每一個模板都會引用data,若是data是定值,則每一個模板引用的都是同一個,若是data是函數,則返回不一樣,每一個模板纔會區別開
<div id="app-02"> <simple-counter></simple-counter> <simple-counter></simple-counter> <simple-counter></simple-counter> </div> 若是是: var data={counter:0} var app02=new Vue({ el:'#app-02', components:{ 'simple-counter':{ template:'<button v-on:click="counter +=1">{{counter}}</button>', data:function(){ return data } } } 則修改一個模板,其餘模板數字也被修改,由於data的返回值是data自身,而全部模板都會引用data,都有修改權。 改一下: var app02=new Vue({ el:'#app-02', components:{ 'simple-counter':{ template:'<button v-on:click="counter +=1">{{counter}}</button>', data:function(){ return {counter:0} } } } 每一個模板能夠有獨立的值了,由於data做爲一個函數返回的是不一樣的counter,不會被共用 

模板內部的data與外部是衝突的

構成組件
<div id="app-03"> <child message="hello"></child> <div>{{value}}</div> </div> var app03=new Vue({ el:'#app-03', components:{ 'child':{ template:'<span>{{message}}</span>', props:['message'] } }, data:{ value:'yyy' } }) 

此例子中,props請求的message經過組件元素傳入,即特性傳入,props與外部的data不衝突

  • 特性命名問題:
  • 矛盾點一:html的特性不區分大小寫
  • 矛盾點二:Vue中除了模板命名,其餘命名不容許出現小橫槓 ‘-’
    因而當兩個單詞串聯成一個名字時,怎麼區分呢?
    vue貌似作了一個命名自動轉換,在js文件內,命名爲駝峯式,camerCase,進入html文件,自動轉換成短橫線隔開式,kebab-case,對應的是同一個變量
props:['myMessage']——js內 <child-11 my-message="hello"></child-11>——html內 
  • 也能夠用v-bind動態綁定prop到一個model
<div id="app-03"> <input type="text" v-model='parentMsg'> <child-11 v-bind:my-message="parentMsg"></child-11> </div> var app03=new Vue({ el:'#app-03', components:{ 'child-11':{ template:'<span>{{myMessage}}</span>', props:['myMessage'] } }, data:{ parentMsg:'' } }) 
  • 字面量語法vs動態語法:
<comp some-prop='1'></comp> 因爲這是一個字面prop,傳遞了一個字符串'1',它的值是字符串‘1’而不是number <comp v-bind:some-prop='1'></comp> 這樣會把值當作一個javascript表達式計算,纔是number (存疑) - prop是單向綁定:父組件屬性變化時,將傳到給子組件,但不會反過來。同時,每次父組件更新時,子組件的全部prop都會更新爲最新值,這意味着,不該該在子組件內部改變prop。可是還要用怎麼辦呢? - 定義一個局部變量,用prop初始化 - 定義一個計算屬性,處理prop值 然而,js中,對象和數組是引用類型,指向同一個內存空間,若是prop是對象或者數組,在子組件內部改變也會影響父組件的狀態。 - Prop驗證 

<div id="app-04">
<child prop-c="111"></child>

<child prop-c="333" prop-d="222"></child>
</div>
var app04=new Vue({
el:'#app-04',
components:{
'child':{
template:'<span>{{propC}}-{{propD}}-{{propE}}</span>',
props:{
propC:{
type:String,
required:true
},
propD:[String,Number],
propE:{
type:[String,Number],
default:100
}
}
}
}
})

有幾種驗證:
 - 指定類型驗證:

單個的,propA:Number;
多個的,propB:[String,Number]

- 是否必須存在的驗證:

propC:{
type:String,
required:true
}

- 帶默認值的驗證:

propD:{
type:Number,
default:100
}

默認值能夠是函數:

propE:{
type:Object,
default:function(){
return { message:'hello'}

- 還能夠自定義驗證函數:

propF:{
validator:function(value){
return value>0
}
這個驗證失敗時是控制檯報錯

- type的類型是如下原生構造器: - String - Number - Boolean - Function - Object - Array #####自定義事件 

<div id="app-05">
<p>{{total}}</p>
<button-counter v-on:increment="incrementTotal"></button-counter>
<button-counter v-on:increment="incrementTotal"></button-counter>
</div>
var app05=new Vue({
el:'#app-05',
components:{
'button-counter':{
template:'<button v-on:click="increment">{{counter}}</button>',
data:function(){
return{
counter:0
}
},
methods:{
increment:function(){
this.counter+=1
this.$emit('increment')
}
}
}
},
data:{
total:0
},
methods:{
incrementTotal:function(){
this.total+=1
}
}
})

這個例子中,建立了父元素和內部的子組件,子組件包含一個點擊事件,v-on:click=‘increment’,點擊後改變counter數值,同時爲了上傳事件,在函數increment內部自定義了一個事件,並在點擊時觸發此事件,$emit,也叫increment,並在子元素上綁定了這個事件,v-on:increment,而後對此在父元素上綁定了一個函數,incrementTotal,從而達到計算總數的效果。 我以爲這個名字區分一下比較好,子組件的方法沒必要和觸發事件同一個名字,因此改一下: 

<div id="app-05">
<p>{{total}}</p>
<button-counter v-on:user-defined="incrementTotal"></button-counter>
<button-counter v-on:user-defined="incrementTotal"></button-counter>
</div>
var app05=new Vue({
el:'#app-05',
components:{
'button-counter':{
template:'<button v-on:click="increment">{{counter}}</button>',
data:function(){
return{
counter:0
}
},
methods:{
increment:function(){
this.counter+=1
this.$emit('user-defined')
}
}
}
},
data:{
total:0
},
methods:{
incrementTotal:function(){
this.total+=1
}
}
})

- 給組件綁定原生事件
用.native修飾v-on 

<new-component v-on:click.native="doSomeThing"></new-component>

- v-on與$on的不一樣: v-on能夠被父組件用來監聽子組件的事件 (存疑):$on的用法 - v-model的使用: - ref與$.refs——註冊引用信息和使用: - 在元素上註冊:<p ref="a">hello</p> 使用註冊:vm.$refs.a就是p這個DOM節點 - 在組件上註冊:<input ref="b"> 使用註冊:this.$refs.b就是指向了組件實例,this.$refs.b.value指向的是組件input.value - mounted ——生命週期鉤子,當el被新建立的vm.$el替換,並掛載到實例上以後調用該鉤子 - NumberObject.toFixed(num)——把Number四捨五入爲指定小數位數的數字 

<script src="https://cdn.rawgit.com/chrisvfritz/5f0a639590d6e648933416f90ba7ae4e/raw/98739fb8ac6779cb2da11aaa9ab6032e52f3be00/currency-validator.js"></script>
//載入一個驗證插件
<div id="app-07">
<currency-input label="Price" v-model="price"></currency-input>
<currency-input label="Shipping" v-model="shipping"></currency-input>
<currency-input label="Handling" v-model="handling"></currency-input>
<currency-input label="Discount" v-model="discount"></currency-input>
//此處有一個合計
<p>Total: ${{total}}</p>
</div>
//組件部分
Vue.component('currency-input',{
template:'<div>
//若是有label,則顯示,不然不顯示
<label v-if="label">{{label}}</label>
$<input ref="input" v-bind:value="value" v-on:input="updateValue($event.target.value)"
v-on:focus="selectAll" v-on:blur="formatValue"></div>',
props:{
//對參數進行驗證
value:{
type:Number,
default:0
},
label:{
type:String,
default:''
}
},
//生命週期鉤子,當組件被掛載到實例時會觸發
mounted:function(){
this.formatValue()
},
methods:{
updateValue:function(value){
var result=currencyValidator.parse(value,this.value)
if(result.warning){
this.$refs.input.value=result.value
}
this.$emit('input',result.value)
},
formatValue:function(){
this.$refs.input.value =currencyValidator.format(this.value)
},
//作setTimeout是因爲safari此處有bug,不考慮兼容的話沒必要如此
selectAll:function(event){
setTimeout(function(){
event.target.select()
},0)
}
}
})

- 非父子組件間的通訊(簡單場景)——建立一個空的Vue實例做爲鏈接:

var bus = new Vue()
//在A組件內
bus.$emit('id-selected', 1)
//在B組件內
bus.$on('id-selected', function (id) {
// ...
})

- slot 內容分發
 - 單個slot:子組件只有一個沒有名字的slot時,父組件的整個內容片段會插入到slot所在的DOM位置
 - 具名slot:

子模板
<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">這裏多是一個頁面標題</h1>
<p>主要內容的一個段落。</p>
<p>另外一個主要段落。</p>
<p slot="footer">這裏有一些聯繫信息</p>
</app-layout>
渲染結果
<div class="container">
<header>
<h1>這裏多是一個頁面標題</h1>
</header>
<main>
<p>主要內容的一個段落。</p>
<p>另外一個主要段落。</p>
</main>
<footer>
<p>這裏有一些聯繫信息</p>
</footer>
</div>

- 做用域插槽:子組件中把數據傳遞到插槽slot,父元素用一個template scope="props" 獲取數據,而後就可使用了 

Vue.component('child',{
template:'<div><slot text="hello from child"></slot></div>'
})
var app03=new Vue({
el:'#app-03',
components:{
'parent-component':{
template:'<div>
<child>
<template scope="props">
<span>hello from parent</span>
<span>{{props.text}}</span>
</template>
</child></div>'
}
}
})
//顯示爲:
hello from parent hello from child

- 更復雜的列表組件的例子:

//須要把mylist傳遞進parent-list
<parent-list id="app-04" v-bind:mylist="mylist"></parent-list>
Vue.component('child-list',{
props:['mylist'],
template:'<ul><slot name="item" v-for="item in mylist" v-bind:text="item.text"></slot></ul>'
})
var app04=new Vue({
el:'#app-04',
data:{
mylist:[
{text:'蔬菜'},
{text:'水果'},
{text:'肉'}
]
},
components:{
'parent-list':{
props:['mylist'],
//此處也須要把mylist傳遞進child-list
template:'<child-list v-bind:mylist="mylist">
<template slot="item" scope="props">
<li>{{props.text}}</li>
</template>
</child-list>'
}
}
})
顯示爲:

  • 蔬菜
  • 水果
- 渲染一個元組件爲動態組件,根據is的值來決定渲染哪一個組件 

<component id="app-06" v-bind:is="currentView"></component>
var app06=new Vue({
el:'#app-06',
data:{
currentView:'posts'
},
components:{
'home':{
template:'<span>home</span>'
},
'posts':{
template:'<span>posts</span>'
},
'archive':{
template:'<span>archive</span>'
}
}
})
//輸入爲posts

- keep-alive保留狀態或避免從新渲染

<keep-alive><component id="app-06" v-bind:is="currentView"></component></keep-alive>

- 可複用組件,三個接口:
 - props
 - events
 - slots

<my-component
:foo="baz"
:bar="qux"
@event-a="doThis"
@event-b="doThat"

<img slot="icon" scr="...">
<p slot="main-text">Hello!</p>
</my-component>

- 子組件索引:使用ref指定一個索引id 

<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({el:'#parent'})
var child = parent.$refs.profile

當ref與v-for一塊兒使用時,ref是一個數組或對象,包含相應的子組件,是非響應式的,應避免在模板或計算屬性中使用 - 異步組件,接受一個工廠函數,能夠動態解析組件的定義: 
  • 能夠搭配webpack的代碼分割功能
  • 可使用webpack2 +es2015返回一個promise resolve函數
  • 組件命名約定,三種均可以:kebab-case,camelCase,TitleCase
    可是,html模板中,只能使用kebab-case
    字符串模板中,三種均可以
  • 遞歸組件,組件能夠遞歸的調用本身
    (這裏的雷是,不能在實例內部建立組件,由於遞歸時會查找不到子組件,須要定義全局組件)
<div id="app-07"> <recursion-component :count="0"></recursion-component> </div> Vue.component('recursion-component',{ props:['count'], name:'count', template:'<div><span>{{count}}</span><recursion-component :count="count+1" v-if="count<10"></recursion-component></div>' }) var app07=new Vue({ el:'#app-07' }) //輸出是:0 1 2 3 4 5 6 7 8 9 10 
  • 組件間的循環引用——註冊爲全局組件時沒有問題,可是使用webpack或者browerify用requiring/importing組件的話,會報錯,須要用生命週期鉤子中註冊它的優先級:
beforeCreate:function(){ this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue') } 

此處(存疑,之後用了webpack再說)
文件目錄樹的例子:

<div id="app-08"> <tree-folder :folder="folder"></tree-folder> </div> Vue.component('tree-folder',{ template:'<p><span>{{folder.name}}</span><tree-folder-contents :children="folder.children"/></p>', props:['folder'] }) Vue.component('tree-folder-contents',{ template:'<ul><li v-for="child in children">\ <tree-folder v-if="child.children" :folder="child"/>\ <span v-else>{{child.name}}</span>\ </li></ul>', props:['children'] }) var app08=new Vue({ el:'#app-08', data:{ folder:{ name:'總目錄', children:[ {name:"二層目錄1"}, {name:"二層目錄2", children:[ {name:"三層目錄1"}, {name:"三層目錄1"} ] }, {name:'二層目錄3'} ] } } }) //輸出: 總目錄 - 二層目錄1 - 二層目錄2 - 三層目錄1 - 三層目錄2 - 二層目錄3 
  • 內聯模板:一個組件有inline-template屬性時,組件會把它的內容當作它的模板,而不是當作分發內容。應對於很簡單的模板,由於有做用域問題
<parent-com><span>啦啦啦</span></parent-com> \\js部分 Vue.component('parent-com',{ template:'<div><child-com><span>this is part of parents</span></child-com></div>' }) \\默認狀況下,「啦啦啦」做爲分發內容,不會顯示,而是顯示this is part of parents. \\若是改成: <parent-com inline-template><span>啦啦啦</span></parent-com> \\則顯示爲「啦啦啦」,原設定的template被覆蓋了 
  • 另外一種定義模板的方式:x-template
<div id="app-10"> <hello-world></hello-world> </div> \\先單獨一個js,類型爲type="text/x-template",而且須要有id <script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script> \\而後在另外一個js裏建立組件,只不過模板能夠直接引用這個id: Vue.component('hello-world', { template: '#hello-world-template' }) \\別忘了建立實例(掩面) var app10=new Vue({ el:'#app-10' }) 
  • 對低開銷的靜態組件使用v-once只渲染一次,下次時直接應用緩存
Vue.component('terms-of-service', {
  template: '\
    <div v-once>\ <h1>Terms of Service</h1>\ ... a lot of static content ...\ </div>\ ' })
相關文章
相關標籤/搜索