如下內容根據Vue.js Guide Essentials部分速記。
不含動畫/mixin/SSR/路由/狀態管理等部分.css
建議閱讀原文 https://vuejs.org/v2/guide/in...html
什麼是Vue
開始
聲明式渲染
條件與循環
處理用戶輸入
組件
建議閱讀原文 https://vuejs.org/v2/guide/in...vue
建立Vue實例
data & methods
實例生命週期及其鉤子函數
生命週期圖表
模板語法 https://vuejs.org/v2/guide/sy...react
html標籤內的文本:使用{{變量名}}
原始html:標籤屬性內使用v-html="變量名"
標籤內的屬性:v-bind:屬性名="變量名"
也可用JS的表達式來替換上述"變量名",但只能是單條表達式,不能是語句webpack
argument:如v-bind:href中的href
modifier:如v-on:submit.prevent="onSubmit"中的.preventweb
v-bind:href等同於:href
v-on:click="doSth"等同於@cllick="doSth"windows
https://vuejs.org/v2/guide/co...數組
js內的computed函數
computed屬性會被緩存,出於性能考慮,不建議在{{}}中的表達式內執行method
computed屬性會被緩存,即便是一個函數,也並不會每次都執行
computed是根據已有變量計算出的新變量瀏覽器
watch用來監視已有變量,執行進一步操做.緩存
(html標籤中的)class與style綁定 https://vuejs.org/v2/guide/cl...
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>
和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>
條件渲染 https://vuejs.org/v2/guide/co...
<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)
只控制css的display.
不支持template元素,不支持和v-else同時使用
常常切換顯示隱藏,使用v-show
偶爾顯示,變更少,使用v-if
v-for的優先級高.(見下一節)
列表渲染 https://vuejs.org/v2/guide/li...
<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
<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()來遍歷,不保證全部瀏覽器都表現一致
若是數據的順序變更,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能夠直接遍歷整數:
<div> <span v-for="n in 10">{{ n }} </span> </div>
與v-if相似,能夠結合template使用
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider"></li> </template> </ul>
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,就像其餘普通元素同樣.
<my-component v-for="item in items" :key="item.id"></my-component> 在組件內使用v-for, :key爲必須的
但仍需注意父子組件之間的數據傳遞.
(子組件的js內使用props, 標籤內使用v-bind:變量名,使用$emit與父組件通訊)
事件處理 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) } }
能夠多個同時使用,也能夠只使用修飾符,不指定事件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」.
單獨按某個鍵,而不是組合按鍵中的其中一個鍵
<!-- 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
表單輸入綁定 https://vuejs.org/v2/guide/fo...
input(輸入框、單選、多選)、textarea、select單選多選 等
v-model,將忽略任何標籤上的初始值,只把vue實例的data做爲數據來源
單選一 一個checkbox綁定到一個v-model,data爲Boolean
多選多 多個checkbox綁定到同一個v-model,data爲數組
多選一 多個input radio綁定到同一個v-model,data爲字符串,結果爲input標籤內的value
單選 建議第一項爲一個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">
組件 https://vuejs.org/v2/guide/co...
https://vuejs.org/v2/guide/co...
全局註冊、局部註冊
data必須是一個函數
父子組件的關係: props down, events up
父組件經過prop把屬性傳遞給子組件;子組件經過觸發事件,把數據傳遞給父組件
https://vuejs.org/v2/guide/co...
在子組件的js聲明中,添加props(和data同級),props才能從父組件傳遞到子組件。
同時,須要在父組件標籤中添加這個屬性,該屬性才能傳遞到子組件內。
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:xx是表達式。
所以,直接使用屬性,數據類型都是字符串;v-bind的在通過表達式運算以後,能夠是數字類型(等等)
父組件的數據經過props傳遞給子組件,子組件經過computed或data來進行數據處理。
不要在子組件直接改變父組件的數據。
把父組件傳遞的數據當作子組件的初始值。
js中的對象和數組傳遞的是引用值,子組件若是修改,會影響父組件
能夠在子組件的js內,定義父組件須要傳遞給子組件的props名稱、類型、是否必須等
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 } } })
<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協做,自定義組件須要:
value
propinput
事件,並傳入新值在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) { // ... })
https://vuejs.org/v2/guide/co...
用實際使用某個組件時寫入到組件標籤內的內容,
去替換組件原有的模板中的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> <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
<script type="text/x-template" id="hello-world-template"> <p>Hello hello hello</p> </script> Vue.component('hello-world', { template: '#hello-world-template' })
很長很長的,只渲染一次的內容,好比,用戶協議.