Vue.js起手式+Vue小做品實戰

本文是小羊根據Vue.js文檔進行解讀的第一篇文章,主要內容涵蓋Vue.js的基礎部分的知識的,文章順序基本按照官方文檔的順序,每一個知識點現附上代碼,而後根據代碼給予我的的一些理解,最後還放上在線編輯的代碼以供練習和測試之用;
在最後,我參考SegmentFault上的一篇技博,對Vue進行初入的實戰,目的是將新鮮學到的知識當即派上用場;css

若是你仍是前端的小白,相信這篇文章可能會對產生一些幫助和引發思想的碰撞,由於你們的學習歷程是類似的,遇到的困惑也有必定的共通性,若是文章出現謬誤之處,歡迎各位童鞋及時指正;html

Vue.js

1. Vue.js是什麼

Vue.js(讀音 /vjuː/, 相似於 view) 是一套構建用戶界面的 漸進式框架。與其餘重量級框架不一樣的是Vue 的核心庫只關注視圖層。
Vue.js 的目標是經過儘量簡單的 API 實現響應的數據綁定組合的視圖組件前端

Vue.js是一種MVVM框架,其中html是view層,js是model層,經過vue.js(使用v-model這個指令)完成中間的底層邏輯,實現綁定的效果。改變其中的任何一層,另一層都會改變;vue

MVVM

2.Vue的基本語法

2.1 Vue構造函數開啓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()接口去實現;後端


2.2 Vue實例的屬性和方法

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

【demo】

【TIP】
Vue實例所代理data對象上的屬性只有在實例建立的同時進行初始化才具備響應式更新,若在實例建立以後添加是不會觸發視圖更新的;


2.3數據綁定操做

綁定文本和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
  }
})

【demo】

使用過濾器來格式化數據

<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)
    }
  }
})

【demo】

條件指令控制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形式,從而數據的遍歷操做;

【demo】

事件綁定指令能夠實現事件監聽

<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接口用於統必定義函數;

【demo】

小結

本章涉及Vue的基礎的數據綁定操做,內容包括:

  • {{message}}實現文本數據的綁定,而且文本數據可使用JS表達式和過濾器進行進一步處理;
    - v-html="hi"實現HTML數據的綁定;

  • v-bind:href="url"實現屬性數據的綁定;

  • v-if="seen"v-for="item in items"指令實現流程控制;

  • v-on:click="method"指令實現事件監聽


2.4計算屬性

使用計算屬性完成一些數據計算操做

<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
      }
    }
  }
})

2.5Class與Style的綁定

綁定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對象中設置isActivehasError的布爾值;也能夠直接傳一個對象給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要先設定

【demo】

綁定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傳入多個樣式對象

【demo】

2.6條件渲染和列表渲染

前面簡單介紹了一下v-ifv-forv-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-ifv-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;

【demo】

列表渲染

<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塊中,咱們擁有對父做用域屬性的徹底訪問權限;

【demo】


2.7 事件監聽

簡單的事件監聽——直接在指令上處理數據

<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

【demo】


2.8 表單控件綁定

文本控件

<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:[],
  },
})

【demo】


2.9 組件

組件能夠擴展 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 的值到父組件的數據中。每當父組件的數據變化時,該變化也會傳導給子組件,注意這種綁定方式是單向綁定;

【demo】

父組件是使用 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形式;

【demo】


2.10 vue-resource插件

使用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'} }

3. 實戰之Vue小做品

Hello Vue.js

【Hello Vue.js】

上面的Vue小做品是小羊仿照SegmentFault的一篇技博的練手之做,建議各位對照源碼親手練習一次,以便初步熟悉Vue的使用;


參考資料:

相關文章
相關標籤/搜索