Vue.js入門學(xué)習(xí)

Vue.js 是一套構(gòu)建用戶界面的漸進式框架。與其他重量級框架不同的是,Vue 采用自底向上增量開發(fā)的設(shè)計。Vue 的核心庫只關(guān)注視圖層,它不僅易于上手,還便于與第三方庫或既有項目整合。另一方面,當(dāng)與單文件組件和 Vue 生態(tài)系統(tǒng)支持的庫結(jié)合使用時,Vue 也完全能夠為復(fù)雜的單頁應(yīng)用程序提供驅(qū)動。

構(gòu)造器

每個 Vue.js 應(yīng)用都是通過構(gòu)造函數(shù)Vue創(chuàng)建一個Vue 的根實例啟動的:

var vm = new Vue({
  // 選項
})

在實例化 Vue 時,需要傳入一個選項對象,它可以包含數(shù)據(jù)、模板、掛載元素、方法、生命周期鉤子等選項。

可以擴展Vue構(gòu)造器,從而用預(yù)定義選項創(chuàng)建可復(fù)用的組件構(gòu)造器:

var MyComponent = Vue.extend({
  // 擴展選項
})
// 所有的 `MyComponent` 實例都將以預(yù)定義的擴展選項被創(chuàng)建
var myComponentInstance = new MyComponent()

屬性與方法

每個 Vue 實例都會代理其data對象里所有的屬性:

var data = { a: 1 }
var vm = new Vue({
  data: data
})
vm.a === data.a // -> true
// 設(shè)置屬性也會影響到原始數(shù)據(jù)
vm.a = 2
data.a // -> 2
// ... 反之亦然
data.a = 3
vm.a // -> 3

注意只有這些被代理的屬性是響應(yīng)的。如果在實例創(chuàng)建之后添加新的屬性到實例上,它不會觸發(fā)視圖更新。

除了 data 屬性, Vue 實例暴露了一些有用的實例屬性與方法。這些屬性與方法都有前綴$,以便與代理的 data 屬性區(qū)分。例如:

var data = { a: 1 }
var vm = new Vue({
  el: '#example',
  data: data
})
vm.$data === data // -> true
vm.$el === document.getElementById('example') // -> true
// $watch 是一個實例方法
vm.$watch('a', function (newVal, oldVal) {
  // 這個回調(diào)將在 `vm.a`  改變后調(diào)用
})

注意,不要在實例屬性或者回調(diào)函數(shù)中(如vm.$watch('a', newVal => this.myMethod()))使用箭頭函數(shù)。因為箭頭函數(shù)綁定父級上下文,所以 this 不會像預(yù)想的一樣是Vue實例,而是this.myMethod未被定義。

下圖說明了實例的生命周期:


lifecycle.png

下面我們來看下語法:

1.模板語法

Vue.js 使用了基于 HTML 的模板語法,允許開發(fā)者聲明式地將 DOM 綁定至底層 Vue 實例的數(shù)據(jù)。所有 Vue.js 的模板都是合法的 HTML ,所以能被遵循規(guī)范的瀏覽器和 HTML 解析器解析。

文本

數(shù)據(jù)綁定最常見的形式就是使用 “Mustache” 語法(雙大括號)的文本插值:
<span>Message: {{ msg }}</span>
Mustache 標(biāo)簽將會被替代為對應(yīng)數(shù)據(jù)對象上 msg 屬性的值。無論何時,綁定的數(shù)據(jù)對象上 msg 屬性發(fā)生了改變,插值處的內(nèi)容都會更新。
通過使用v-once指令,你也能執(zhí)行一次性地插值,當(dāng)數(shù)據(jù)改變時,插值處的內(nèi)容不會更新。但請留心這會影響到該節(jié)點上所有的數(shù)據(jù)綁定:
<span v-once>This will never change: {{ msg }}</span>

純 HTML

雙大括號會將數(shù)據(jù)解釋為純文本,而非 HTML 。為了輸出真正的 HTML ,你需要使用v-html指令:
<div v-html="rawHtml"></div>
這個 div 的內(nèi)容將會被替換成為屬性值rawHtml,直接作為 HTML —— 數(shù)據(jù)綁定會被忽略。

屬性

Mustache 不能在 HTML 屬性中使用,應(yīng)使用 v-bind 指令:
<div v-bind:id="dynamicId"></div>
這對布爾值的屬性也有效 —— 如果條件被求值為 false 的話該屬性會被移除:
<button v-bind:disabled="isButtonDisabled">Button</button>

使用 JavaScript 表達式

迄今為止,在我們的模板中,我們一直都只綁定簡單的屬性鍵值。但實際上,對于所有的數(shù)據(jù)綁定, Vue.js 都提供了完全的 JavaScript 表達式支持。

{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'list-' + id"></div>

2.指令

指令(Directives)是帶有v-前綴的特殊屬性。指令屬性的值預(yù)期是單一 JavaScript 表達式(除了 v-for)。指令的職責(zé)就是當(dāng)其表達式的值改變時相應(yīng)地將某些行為應(yīng)用到 DOM 上。舉個??:
<p v-if="seen">Now you see me</p>
這里,v-if指令將根據(jù)表達式 seen 的值的真假來移除/插入 <p> 元素。

參數(shù)

一些指令能接受一個“參數(shù)”,在指令后以冒號指明。例如,v-bind指令被用來響應(yīng)地更新 HTML 屬性:
<a v-bind:href="url"></a>
在這里href是參數(shù),告知v-bind指令將該元素的href屬性與表達式url的值綁定。
另一個例子是v-on指令,它用于監(jiān)聽DOM事件:
<a v-on:click="doSomething">
在這里參數(shù)是監(jiān)聽的事件名。

修飾符

修飾符(Modifiers)是以半角句號.指明的特殊后綴,用于指出一個指令應(yīng)該以特殊方式綁定。例如,.prevent修飾符告訴v-on指令對于觸發(fā)的事件調(diào)用 event.preventDefault():
<form v-on:submit.prevent="onSubmit"></form>

3.過濾器

Vue.js 允許你自定義過濾器,可被用作一些常見的文本格式化。過濾器可以用在兩個地方:mustache 插值和v-bind表達式。過濾器應(yīng)該被添加在 JavaScript 表達式的尾部,由“管道”符指示:

<!-- in mustaches -->
{{ message | capitalize }}
<!-- in v-bind -->
<div v-bind:id="rawId | formatId"></div>

4.縮寫

v-前綴在模板中是作為一個標(biāo)示 Vue 特殊屬性的明顯標(biāo)識。當(dāng)你使用 Vue.js 為現(xiàn)有的標(biāo)記添加動態(tài)行為時,它會很有用,但對于一些經(jīng)常使用的指令來說有點繁瑣。同時,當(dāng)搭建 Vue.js 管理所有模板的 SPA 時,v- 前綴也變得沒那么重要了。因此,Vue.js 為兩個最為常用的指令提供了特別的縮寫:

v-bind縮寫

<!-- 完整語法 -->
<a v-bind:href="url"></a>
<!-- 縮寫 -->
<a :href="url"></a>

v-on縮寫

<!-- 完整語法 -->
<a v-on:click="doSomething"></a>
<!-- 縮寫 -->
<a @click="doSomething"></a>

計算屬性

計算屬性 vs Methods

<p>Reversed message: "{{ reversedMessage() }}"</p>

// in component
methods: {
  reversedMessage: function () {
    return this.message.split('').reverse().join('')
  }
}

我們可以將同一函數(shù)定義為一個 method 而不是一個計算屬性。對于最終的結(jié)果,兩種方式確實是相同的。然而,不同的是計算屬性是基于它們的依賴進行緩存的。計算屬性只有在它的相關(guān)依賴發(fā)生改變時才會重新求值。這就意味著只要 message 還沒有發(fā)生改變,多次訪問 reversedMessage 計算屬性會立即返回之前的計算結(jié)果,而不必再次執(zhí)行函數(shù)

觀察 Watchers

雖然計算屬性在大多數(shù)情況下更合適,但有時也需要一個自定義的watcher。這是為什么 Vue 提供一個更通用的方法通過watch選項,來響應(yīng)數(shù)據(jù)的變化。當(dāng)你想要在數(shù)據(jù)變化響應(yīng)時,執(zhí)行異步操作或開銷較大的操作,這是很有用的。
例如:

<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>
<!-- Since there is already a rich ecosystem of ajax libraries    -->
<!-- and collections of general-purpose utility methods, Vue core -->
<!-- is able to remain small by not reinventing them. This also   -->
<!-- gives you the freedom to just use what you're familiar with. -->
<script src="https://unpkg.com/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://unpkg.com/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 question 發(fā)生改變,這個函數(shù)就會運行
    question: function (newQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.getAnswer()
    }
  },
  methods: {
    // _.debounce 是一個通過 lodash 限制操作頻率的函數(shù)。
    // 在這個例子中,我們希望限制訪問yesno.wtf/api的頻率
    // ajax請求直到用戶輸入完畢才會發(fā)出
    // 學(xué)習(xí)更多關(guān)于 _.debounce function (and its cousin
    // _.throttle), 參考: https://lodash.com/docs#debounce
    getAnswer: _.debounce(
      function () {
        if (this.question.indexOf('?') === -1) {
          this.answer = 'Questions usually contain a question mark. ;-)'
          return
        }
        this.answer = 'Thinking...'
        var vm = this
        axios.get('https://yesno.wtf/api')
          .then(function (response) {
            vm.answer = _.capitalize(response.data.answer)
          })
          .catch(function (error) {
            vm.answer = 'Error! Could not reach the API. ' + error
          })
      },
      // 這是我們?yōu)橛脩敉V馆斎氲却暮撩霐?shù)
      500
    )
  }
})
</script>

Class 與 Style 綁定

綁定 HTML Class

對象語法

我們可以傳給v-bind:class一個對象,以動態(tài)地切換 class 。
<div v-bind:class="{ active: isActive }"></div>

上面的語法表示 classactive的更新將取決于數(shù)據(jù)屬性isActive是否為真值 。
我們也可以在對象中傳入更多屬性用來動態(tài)切換多個 class 。此外,v-bind:class指令可以與普通的 class 屬性共存。如下模板:

<div class="static"
     v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>

如下 data:

data: {
  isActive: true,
  hasError: false
}

渲染為:

<div class="static active"></div>

當(dāng)isActive或者hasError變化時,class 列表將相應(yīng)地更新。例如,如果hasError的值為true, class列表將變?yōu)?code>"static active text-danger"。
你也可以直接綁定數(shù)據(jù)里的一個對象:

<div v-bind:class="classObject"></div>
data: {
  classObject: {
    active: true,
    'text-danger': false
  }
}

渲染的結(jié)果和上面一樣。我們也可以在這里綁定返回對象的計算屬性。這是一個常用且強大的模式:

<div v-bind:class="classObject"></div>
data: {
  isActive: true,
  error: null
},
computed: {
  classObject: function () {
    return {
      active: this.isActive && !this.error,
      'text-danger': this.error && this.error.type === 'fatal',
    }
  }
}

數(shù)組語法

我們可以把一個數(shù)組傳給 v-bind:class ,以應(yīng)用一個 class 列表:

<div v-bind:class="[activeClass, errorClass]">
data: {
  activeClass: 'active',
  errorClass: 'text-danger'
}

渲染為:

<div class="active text-danger"></div>

如果你也想根據(jù)條件切換列表中的 class ,可以用三元表達式:

<div v-bind:class="[isActive ? activeClass : '', errorClass]">

不過,當(dāng)有多個條件 class 時這樣寫有些繁瑣??梢栽跀?shù)組語法中使用對象語法:

<div v-bind:class="[{ active: isActive }, errorClass]">

綁定內(nèi)聯(lián)樣式

對象語法

v-bind:style的對象語法十分直觀——看著非常像 CSS ,其實它是一個 JavaScript 對象。 CSS 屬性名可以用駝峰式 (camelCase) 或 (配合引號的) 短橫分隔命名 (kebab-case):

<div v-bind:style="styleObject"></div>
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}

數(shù)組語法

v-bind:style的數(shù)組語法可以將多個樣式對象應(yīng)用到一個元素上:
<div v-bind:style="[baseStyles, overridingStyles]">

自動添加前綴

當(dāng)v-bind:style使用需要特定前綴的 CSS 屬性時,如transform,Vue.js 會自動偵測并添加相應(yīng)的前綴。

條件渲染

v-if指令實現(xiàn)條件塊:

<h1 v-if="ok">Yes</h1>

也可以用v-else添加一個 “else” 塊:

<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>

v-else-if

2.1.0 新增
v-else-if,顧名思義,充當(dāng)v-if的“else-if 塊”??梢枣?zhǔn)降厥褂枚啻危?/p>

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

類似于v-else,v-else-if必須緊跟在v-if或者v-else-if元素之后。

v-show

另一個用于根據(jù)條件展示元素的選項是v-show指令。用法大致一樣:
<h1 v-show="ok">Hello!</h1>
不同的是帶有 v-show 的元素始終會被渲染并保留在 DOM 中。v-show是簡單地切換元素的 CSS 屬性 display 。

列表渲染

v-for

我們用v-for指令根據(jù)一組數(shù)組的選項列表進行渲染。v-for指令需要以item in items形式的特殊語法,items是源數(shù)據(jù)數(shù)組并且item是數(shù)組元素迭代的別名。

基本用法
<ul id="example-1">
  <li v-for="item in items">
    {{ item.message }}
  </li>
</ul>
var example1 = new Vue({
  el: '#example-1',
  data: {
    items: [
      {message: 'Foo' },
      {message: 'Bar' }
    ]
  }
})
結(jié)果:
Foo
Bar

key

當(dāng) Vue.js 用v-for正在更新已渲染過的元素列表時,它默認(rèn)用 “就地復(fù)用” 策略。如果數(shù)據(jù)項的順序被改變,Vue將不是移動 DOM 元素來匹配數(shù)據(jù)項的順序, 而是簡單復(fù)用此處每個元素,并且確保它在特定索引下顯示已被渲染過的每個元素。這個類似 Vue 1.x 的 track-by="$index" 。
建議盡可能使用v-for來提供key,除非迭代 DOM 內(nèi)容足夠簡單,或者你是故意要依賴于默認(rèn)行為來獲得性能提升。

事件處理器

監(jiān)聽事件

可以用v-on指令監(jiān)聽 DOM 事件來觸發(fā)一些 JavaScript 代碼。
示例:

<div id="example-1">
  <button v-on:click="counter += 1">增加 1</button>
  <p>這個按鈕被點擊了 {{ counter }} 次。</p>
</div>
var example1 = new Vue({
  el: '#example-1',
  data: {
    counter: 0
  }
})

方法事件處理器

許多事件處理的邏輯都很復(fù)雜,所以直接把 JavaScript 代碼寫在v-on指令中是不可行的。因此v-on可以接收一個定義的方法來調(diào)用。
示例:

<div id="example-2">
  <!-- `greet` 是在下面定義的方法名 -->
  <button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // 在 `methods` 對象中定義方法
  methods: {
    greet: function (event) {
      // `this` 在方法里指當(dāng)前 Vue 實例
      alert('Hello ' + this.name + '!')
      // `event` 是原生 DOM 事件
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})
// 也可以用 JavaScript 直接調(diào)用方法
example2.greet() // -> 'Hello Vue.js!'
<!-- 阻止單擊事件冒泡 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重載頁面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修飾符可以串聯(lián)  -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修飾符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件偵聽器時使用事件捕獲模式 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只當(dāng)事件在該元素本身(比如不是子元素)觸發(fā)時觸發(fā)回調(diào) -->
<div v-on:click.self="doThat">...</div>

你可以用v-model指令在表單控件元素上創(chuàng)建雙向數(shù)據(jù)綁定。它會根據(jù)控件類型自動選取正確的方法來更新元素。盡管有些神奇,但v-model本質(zhì)上不過是語法糖,它負責(zé)監(jiān)聽用戶的輸入事件以更新數(shù)據(jù),并特別處理一些極端的例子。

使用組件

注冊

之前說過,我們可以通過以下方式創(chuàng)建一個 Vue 實例:

new Vue({
  el: '#some-element',
  // 選項
})

要注冊一個全局組件,你可以使用Vue.component(tagName, options)。例如:

Vue.component('my-component', {
  // 選項
})

組件在注冊之后,便可以在父實例的模塊中以自定義元素<my-component></my-component>的形式使用。要確保在初始化根實例之前注冊了組件:

<div id="example">
  <my-component></my-component>
</div>
// 注冊
Vue.component('my-component', {
  template: '<div>A custom component!</div>'
})
// 創(chuàng)建根實例
new Vue({
  el: '#example'
})
渲染為:
<div id="example">
  <div>A custom component!</div>
</div>

局部注冊

不必在全局注冊每個組件。通過使用組件實例選項注冊,可以使組件僅在另一個實例/組件的作用域中可用:

var Child = {
  template: '<div>A custom component!</div>'
}
new Vue({
  // ...
  components: {
    // <my-component> 將只在父模板可用
    'my-component': Child
  }
})

構(gòu)成組件

組件意味著協(xié)同工作,通常父子組件會是這樣的關(guān)系:組件 A 在它的模版中使用了組件 B。它們之間必然需要相互通信:父組件要給子組件傳遞數(shù)據(jù),子組件需要將它內(nèi)部發(fā)生的事情告知給父組件。然而,在一個良好定義的接口中盡可能將父子組件解耦是很重要的。這保證了每個組件可以在相對隔離的環(huán)境中書寫和理解,也大幅提高了組件的可維護性和可重用性。
在 Vue 中,父子組件的關(guān)系可以總結(jié)為 props down, events up。父組件通過 props 向下傳遞數(shù)據(jù)給子組件,子組件通過 events 給父組件發(fā)送消息??纯此鼈兪窃趺垂ぷ鞯?。

props-events.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容