Vue.js Guide Essentials-說人話-速記版

如下內容根據Vue.js Guide Essentials部分速記。
不含動畫/mixin/SSR/路由/狀態管理等部分.css

Introduction

建議閱讀原文 https://vuejs.org/v2/guide/in...html

什麼是Vue
開始
聲明式渲染
條件與循環
處理用戶輸入
組件

The Vue Instance

建議閱讀原文 https://vuejs.org/v2/guide/in...vue

建立Vue實例
data & methods
實例生命週期及其鉤子函數
生命週期圖表

Template Syntax

模板語法 https://vuejs.org/v2/guide/sy...react

Mustache模板中插入值

html標籤內的文本:使用{{變量名}}
原始html:標籤屬性內使用v-html="變量名"
標籤內的屬性:v-bind:屬性名="變量名"
也可用JS的表達式來替換上述"變量名",但只能是單條表達式,不能是語句webpack

v-if等指令

argument:如v-bind:href中的href
modifier:如v-on:submit.prevent="onSubmit"中的.preventweb

v-bind、v-on簡寫

v-bind:href等同於:href
v-on:click="doSth"等同於@cllick="doSth"windows

Computed Properties and Watchers

https://vuejs.org/v2/guide/co...數組

Computed Properties

js內的computed函數
computed屬性會被緩存,出於性能考慮,不建議在{{}}中的表達式內執行method
computed屬性會被緩存,即便是一個函數,也並不會每次都執行
computed是根據已有變量計算出的新變量瀏覽器

Watchers

watch用來監視已有變量,執行進一步操做.緩存

Class and Style Bindings

(html標籤中的)class與style綁定 https://vuejs.org/v2/guide/cl...

class

v-bind:class內的表達式會自動和class內已有class同時存在

能夠:
<div class="static"
     v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
data: {
  isActive: true,
  hasError: false
}  
結果: <div class="static active"></div>

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

也可使用computed函數計算出的屬性值/對象爲class內的屬性值/對象作數據來源

也可使用數組來應用多個class名:

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

與其在array內使用三目運算符,不如嵌套使用object與array:

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

使用js定義組件時的class先出現,使用組件時添加的class(不管直接使用class仍是v-bind:class)後出現.

Vue.component('my-component', {
  template: '<p class="foo bar">Hi</p>'
})

1.
<my-component class="baz boo"></my-component>

結果: <p class="foo bar baz boo">Hi</p>

2.
<my-component v-bind:class="{ active: isActive }"></my-component>  
結果: <p class="foo bar active">Hi</p>

style 內聯樣式

和class很像,但必須是object

能夠:
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data: {
  activeColor: 'red',
  fontSize: 30
}
也能夠:
<div v-bind:style="styleObject"></div>
data: {
  styleObject: {
    color: 'red',
    fontSize: '13px'
  }
}  
也可使用computed  

也能夠用對象數組:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
(baseStyles/overridingStyles都是object)

使用v-bind:style會自動加上prefix
也能夠手動加:

<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>

Conditional Rendering

條件渲染 https://vuejs.org/v2/guide/co...

v-if/v-else/v-else-if

<h1 v-if="ok">Yes</h1>
也能夠配合else使用: 
<h1 v-else>No</h1>

v-if能夠和template元素結合使用,最終結果不包含template標籤:

<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-else必須緊跟v-if或v-else-if
v-else-if:

<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-if必須緊跟v-if或v-else-if

相同元素自動複用:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address">
</template>

修改loginType的值不會產生新的input元素
會自動複用以前的元素
若是想避免自動複用,給input標籤加上不一樣的key:

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>
(label標籤依然會被複用,由於沒有指定key)

v-show

只控制css的display.
不支持template元素,不支持和v-else同時使用
常常切換顯示隱藏,使用v-show
偶爾顯示,變更少,使用v-if

v-if和v-for配合使用

v-for的優先級高.(見下一節)

List Rendering

列表渲染 https://vuejs.org/v2/guide/li...

v-for遍歷array

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

v-for內部能夠訪問外部的全部變量,
還能夠獲取index:

<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})<ul id="example-2">
  <li v-for="(item, index) in items">
    {{ parentMessage }} - {{ index }} - {{ item.message }}
  </li>
</ul>
var example2 = new Vue({
  el: '#example-2',
  data: {
    parentMessage: 'Parent',
    items: [
      { message: 'Foo' },
      { message: 'Bar' }
    ]
  }
})
注意v-for內的index和parentMessage

v-for遍歷object

<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>
new Vue({
  el: '#v-for-object',
  data: {
    object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
  }
})
結果:
<ul id="v-for-object" class="demo">
  <li>John</li>
  <li>Doe</li>
  <li>30</li>
</ul>
(只有值,無論鍵名)

或者:

<div v-for="(value, key) in object">
  {{ key }}: {{ value }}
</div>
<div v-for="(value, key, index) in object">
  {{ index }}. {{ key }}: {{ value }}
</div>
(有index/鍵名/值)

內部引擎使用Object.keys()來遍歷,不保證全部瀏覽器都表現一致

key

若是數據的順序變更,vue不是調整各個子元素的順序,而是直接修改現有子元素的內容
爲了規避以上狀況,能夠給每一個子元素綁定key:

<div v-for="item in items" :key="item.id">
  <!-- content -->
</div>

探測數組更改狀況

如下的數組方法都已經被Vue封裝好,vue能夠觀察到原有數組的更改

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

替換數組:

filter()
concat()
slice()
...

以上方法不改變原有數組,直接返回新數組.
vue的使用方法以下:

example1.items = example1.items.filter(function (item) {
  return item.message.match(/Foo/)
})

數組更改警告

因爲JS的限制,如下兩種狀況沒法被vue觀察到,請使用替代方案:

  • 直接用索引設置某項的值
// Vue.set
Vue.set(example1.items, indexOfItem, newValue)
或者
// Array.prototype.splice
example1.items.splice(indexOfItem, 1, newValue)
  • 修改數組的長度
example1.items.splice(newLength)

對象更改警告

因爲JS限制,vue觀察不到動態添加根級別的屬性到已有的實例:

var vm = new Vue({
  data: {
    a: 1
  }
})
// `vm.a` is now reactive

vm.b = 2
// `vm.b` is NOT reactive

可是容許內層的object添加屬性:

var vm = new Vue({
  data: {
    userProfile: {
      name: 'Anika'
    }
  }
})

可使用
Vue.set(vm.userProfile, 'age', 27)
或者
vm.$set(this.userProfile, 'age', 27)

若是須要更新多個屬性,直接使用添加屬性後的新對象替換原有對象,
不要:

Object.assign(this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

而應該這樣:

this.userProfile = Object.assign({}, this.userProfile, {
  age: 27,
  favoriteColor: 'Vue Green'
})

篩選與排序

不對原始數據修改,僅對須要顯示的做篩選排序等.
靈活運用computed或methods:

computed:

<li v-for="n in evenNumbers">{{ n }}</li>

data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
computed: {
  evenNumbers: function () {
    return this.numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

methods(在嵌套v-for循環內尤爲有用):

<li v-for="n in even(numbers)">{{ n }}</li>

data: {
  numbers: [ 1, 2, 3, 4, 5 ]
},
methods: {
  even: function (numbers) {
    return numbers.filter(function (number) {
      return number % 2 === 0
    })
  }
}

v-for with a Range

v-for能夠直接遍歷整數:

<div>
  <span v-for="n in 10">{{ n }} </span>
</div>

v-for on a <template>

與v-if相似,能夠結合template使用

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider"></li>
  </template>
</ul>

v-for與v-if

v-for has a higher priority than v-if.

v-if將在每一個for循環內都執行
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo }}
</li>

若是想先if出結果,再for循環,請嵌套使用(也可用template):

<ul v-if="todos.length">
  <li v-for="todo in todos">
    {{ todo }}
  </li>
</ul>
<p v-else>No todos left!</p>

v-for與組件

能夠在自定義組件內使用v-for,就像其餘普通元素同樣.

<my-component v-for="item in items" :key="item.id"></my-component>
在組件內使用v-for, :key爲必須的

但仍需注意父子組件之間的數據傳遞.
(子組件的js內使用props, 標籤內使用v-bind:變量名,使用$emit與父組件通訊)

Event Handling

事件處理 https://vuejs.org/v2/guide/ev...

標籤內使用v-on:事件名="xxx"

xxx能夠是表達式(直接修改數據)

<div id="example-1">
  <button v-on:click="counter += 1">Add 1</button>
  <p>The button above has been clicked {{ counter }} times.</p>
</div>
var example1 = new Vue({
  el: '#example-1',
  data: {
    counter: 0
  }
})

也能夠是method方法名

<div id="example-2">
  <!-- `greet` is the name of a method defined below -->
  <button v-on:click="greet">Greet</button>
</div>
var example2 = new Vue({
  el: '#example-2',
  data: {
    name: 'Vue.js'
  },
  // define methods under the `methods` object
  methods: {
    greet: function (event) {
      // `this` inside methods points to the Vue instance
      alert('Hello ' + this.name + '!')
      // `event` is the native DOM event
      if (event) {
        alert(event.target.tagName)
      }
    }
  }
})

// you can invoke methods in JavaScript too
example2.greet() // => 'Hello Vue.js!'

也能夠是一段js語句,能夠選擇性地傳遞參數到method內:

<div id="example-3">
  <button v-on:click="say('hi')">Say hi</button>
  <button v-on:click="say('what')">Say what</button>
</div>
new Vue({
  el: '#example-3',
  methods: {
    say: function (message) {
      alert(message)
    }
  }
})

能夠傳遞原始的DOM event參數,使用$event:

<button v-on:click="warn('Form cannot be submitted yet.', $event)">
  Submit
</button>
// ...
methods: {
  warn: function (message, event) {
    // now we have access to the native event
    if (event) event.preventDefault()
    alert(message)
  }
}

Event Modifiers 事件修飾符

能夠多個同時使用,也能夠只使用修飾符,不指定事件handler

.stop 中止向上傳播
.prevent preventDefault
.capture 捕獲子元素內已處理的事件
.self 只管本元素的事件,不考慮子元素
.once 觸發至多一次,能夠用在組件的自定義事件中  

<!-- the submit event will no longer reload the page -->
<form v-on:submit.prevent="onSubmit"></form>

<!-- modifiers can be chained -->
<a v-on:click.stop.prevent="doThat"></a>

<!-- just the modifier -->
<form v-on:submit.prevent></form>

修飾符是有順序的.
Therefore using @click.prevent.self will prevent all clicks while @click.self.prevent will only prevent clicks on the element itself.

按鍵修飾符

<input v-on:keyup.13="submit">
<input v-on:keyup.enter="submit">
<input @keyup.enter="submit">

完整的按鍵修飾符:

.enter
.tab
.delete (captures both 「Delete」 and 「Backspace」 keys)
.esc
.space
.up
.down
.left
.right

自定義按鍵修飾符:

// enable `v-on:keyup.f1`
Vue.config.keyCodes.f1 = 112

自動按鍵修飾符

能夠根據KeyboardEvent.key的名稱,轉換爲小寫-小寫的形式,做爲按鍵修飾符.
如: .page-down

<input @keyup.page-down="onPageDown">
In the above example, the handler will only be called if $event.key === 'PageDown'.

系統按鍵修飾符

.ctrl
.alt
.shift
.meta
Note: On Macintosh keyboards, meta is the command key (⌘). On Windows keyboards, meta is the windows key (⊞). On Sun Microsystems keyboards, meta is marked as a solid diamond (◆). On certain keyboards, specifically MIT and Lisp machine keyboards and successors, such as the Knight keyboard, space-cadet keyboard, meta is labeled 「META」. On Symbolics keyboards, meta is labeled 「META」 or 「Meta」.

.exact

單獨按某個鍵,而不是組合按鍵中的其中一個鍵

<!-- this will fire even if Alt or Shift is also pressed -->
<button @click.ctrl="onClick">A</button>

<!-- this will only fire when Ctrl and no other keys are pressed -->
<button @click.ctrl.exact="onCtrlClick">A</button>

<!-- this will only fire when no system modifiers are pressed -->
<button @click.exact="onClick">A</button>

鼠標按鈕修飾符

.left
.right
.middle

Form Input Bindings

表單輸入綁定 https://vuejs.org/v2/guide/fo...
input(輸入框、單選、多選)、textarea、select單選多選 等

基本用法

v-model,將忽略任何標籤上的初始值,只把vue實例的data做爲數據來源

input text

textarea

input checkbox

單選一 一個checkbox綁定到一個v-model,data爲Boolean
多選多 多個checkbox綁定到同一個v-model,data爲數組

input radio(多選一 圓按鈕)

多選一 多個input radio綁定到同一個v-model,data爲字符串,結果爲input標籤內的value

select

單選 建議第一項爲一個disabled的option
多選,添加multiple屬性

數據綁定

radio/select options的v-model爲字符串,checkbox爲布爾值
能夠把v-model與自定義的value值作綁定,而不是瀏覽器默認的value值.

<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'


<input type="radio" v-model="pick" v-bind:value="a">
// when checked:
vm.pick === vm.a


<select v-model="selected">
  <!-- inline object literal -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>
// when selected:
typeof vm.selected // => 'object'
vm.selected.number // => 123

修飾符

<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg" >
轉換爲數字類型
<input v-model.number="age" type="number">
去空格
<input v-model.trim="msg">

Components

組件 https://vuejs.org/v2/guide/co...

使用組件

https://vuejs.org/v2/guide/co...

全局註冊、局部註冊

data必須是一個函數

父子組件的關係: props down, events up
父組件經過prop屬性傳遞給子組件;子組件經過觸發事件,把數據傳遞給父組件

Props

https://vuejs.org/v2/guide/co...

使用props傳遞數據

在子組件的js聲明中,添加props(和data同級),props才能從父組件傳遞到子組件。
同時,須要在父組件標籤中添加這個屬性,該屬性才能傳遞到子組件內。

camelCase-vs-kebab-case

html標籤內不區分大小寫,因此使用鏈接橫槓-,js的props內使用駝峯式命名法(首字母小寫)

動態屬性

經過v-bind:子組件數據名稱=父組件數據名稱
也能夠v-bind=對象名

todo: {
  text: 'Learn Vue',
  isComplete: false
}

<todo-item v-bind="todo"></todo-item>

等同於

<todo-item
  v-bind:text="todo.text"
  v-bind:is-complete="todo.isComplete"
></todo-item>

標籤中的屬性字面量與v-bind:xxx的動態變量

直接使用屬性,是字面量;v-bind:xx是表達式。
所以,直接使用屬性,數據類型都是字符串;v-bind的在通過表達式運算以後,能夠是數字類型(等等)

單向數據流

父組件的數據經過props傳遞給子組件,子組件經過computed或data來進行數據處理。
不要在子組件直接改變父組件的數據。
把父組件傳遞的數據當作子組件的初始值。
js中的對象和數組傳遞的是引用值,子組件若是修改,會影響父組件

prop驗證

能夠在子組件的js內,定義父組件須要傳遞給子組件的props名稱、類型、是否必須等

無prop的屬性

https://vuejs.org/v2/guide/co...
(子組件的js內)未定義某個prop,父組件直接在標籤上傳入某個prop
一般被用在class、style上

自定義事件

https://vuejs.org/v2/guide/co...
$on/$emit和瀏覽器原生的
EventTarget API
沒有關係

在父組件的上下文環境中,使用v-on來監聽子組件觸發($emit)的事件

<div id="counter-event-example">
  <p>{{ total }}</p>
  <button-counter v-on:increment="incrementTotal"></button-counter>
  <button-counter v-on:increment="incrementTotal"></button-counter>
</div>
Vue.component('button-counter', {
  template: '<button v-on:click="incrementCounter">{{ counter }}</button>',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    incrementCounter: function () {
      this.counter += 1
      this.$emit('increment')
    }
  },
})

new Vue({
  el: '#counter-event-example',
  data: {
    total: 0
  },
  methods: {
    incrementTotal: function () {
      this.total += 1
    }
  }
})

使用.native修飾符去監聽原生事件

使用.sync修飾符

<comp :foo.sync="bar"></comp>
實質爲:
<comp :foo="bar" @update:foo="val => bar = val"></comp>

在子組件的js內,須要觸發update:foo事件來更新foo的值

this.$emit('update:foo', newValue)

表單輸入與自定義事件

https://vuejs.org/v2/guide/co...

<input v-model="something">
實質爲:
<input
  v-bind:value="something"
  v-on:input="something = $event.target.value">

若是想讓自定義組件與v-model協做,自定義組件須要:

  • accept a value prop
  • 觸發 input 事件,並傳入新值

自定義組件的v-model

在js中添加model字段

Vue.component('my-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean,
    // this allows using the `value` prop for a different purpose
    value: String
  },
  // ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>

以上等同於:

<my-checkbox
  :checked="foo"
  @change="val => { foo = val }"
  value="some value">
</my-checkbox>

非父子組件之間的通訊

使用一箇中間Vue實例來傳遞消息,或使用Vuex.

var bus = new Vue()
// in component A's method
bus.$emit('id-selected', 1)
// in component B's created hook
bus.$on('id-selected', function (id) {
  // ...
})

內容分發與slot

https://vuejs.org/v2/guide/co...

單slot

用實際使用某個組件時寫入到組件標籤內的內容,
去替換組件原有的模板中的slot的內容.
(而後再將組件內的全部內容合併到父級元素內)

若是實際使用組件時,組件標籤內沒有內容,
則顯示組件原有的模板中的slot內容.
(而後再將組件內的全部內容合併到父級元素內)

具備名字的slot

<div class="parent" id='parent' >
    <my-comp>
      content at parent
      <div slot="footer">
        <h2>
          content at parent's footer slot
        </h2>
      </div>
    </my-comp>
  </div>

  <p>
  <h2>h2 inside p   (wrong!!!)</h2>
  </p>


  <script>
    
    ;(function () {
      // register
      Vue.component('my-comp', {
        template:
            `<div>
              content at my component. <br><br>
              <slot>content at my-comp's slot</slot>
              <pre>
                <slot name="footer">content at my-comp's footer slot</slot>
              </pre>
            </div>`
      })
      var parent = new Vue({
        el:'#parent'
      })
      
    })();
    
    
  </script>

動態組件

https://vuejs.org/v2/guide/co...

var vm = new Vue({
  el: '#example',
  data: {
    currentView: 'home'
  },
  components: {
    home: { /* ... */ },
    posts: { /* ... */ },
    archive: { /* ... */ }
  }
})
<component v-bind:is="currentView">
  <!-- component changes when vm.currentView changes! -->
</component>

If you prefer, you can also bind directly to component objects:
var Home = {
  template: '<p>Welcome home!</p>'
}

var vm = new Vue({
  el: '#example',
  data: {
    currentView: Home
  }
})

keep-alive

<keep-alive>
  <component :is="currentView">
    <!-- inactive components will be cached! -->
  </component>
</keep-alive>

雜項

https://vuejs.org/v2/guide/co...

編寫可複用組件

Props/Events/Slots 結合使用

引用子組件

直接用js訪問子組件.
須要在使用子組件時,標籤內添加ref="xxx"

var parent = new Vue({ el: '#parent' })
// 訪問子組件實例
var child = parent.$refs.profile

異步組件

結合webpack的import()

高級異步組件

const AsyncComp = () => ({
  // The component to load. Should be a Promise
  component: import('./MyComp.vue'),
  // A component to use while the async component is loading
  loading: LoadingComp,
  // A component to use if the load fails
  error: ErrorComp,
  // Delay before showing the loading component. Default: 200ms.
  delay: 200,
  // The error component will be displayed if a timeout is
  // provided and exceeded. Default: Infinity.
  timeout: 3000
})

組件命名約定

(使用JS)聲明組件時, PascalCase,
(標籤內)使用組件時, <kebab-case>

遞歸組件

https://vuejs.org/v2/guide/co...

組件之間的相互引用

添加beforeCreate 函數

beforeCreate: function () {
  this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue')
}

內聯模板

模板的標籤內添加inline-template

X-Templates

<script type="text/x-template" id="hello-world-template">
  <p>Hello hello hello</p>
</script>

Vue.component('hello-world', {
  template: '#hello-world-template'
})

v-once

很長很長的,只渲染一次的內容,好比,用戶協議.

相關文章
相關標籤/搜索