文章目錄
Vue基礎知識講解
這是一份我給公司後端同事培訓Vue的培訓第一節課技術文檔,旨在帶領他們入門Vue的開發世界,釋放更多的前端資源。現開放出來以求業界各位的技術指點或補充,感謝~
以下文檔配合代碼一起演示和講解效果更佳。代碼地址:Vue-coe-test代碼地址
創建第一個vue實例
使用以下命令行創建一個vue項目
$ npm install -g vue-cli
$ vue init webpack vue-coe-test
$ cd vue-coe-test
$ npm install
$ npm run dev
掛載點,模板,實例
### // App.vue
<div id="app"></div>
//main.js
new Vue({
el: '#app',
router,
components: { App },
template: '<h1>{{ msg }}</h1>',
data () {
return {
msg: 'Hello,my first Vue.js App'
}
}
})
- 掛載點就是Vue實例裏面el屬性對應的dom節點。
- 模板就是掛載點裏面的內容,也可以寫在實例的template中。
- 實例就是new的時候指定一個dom節點,一個模板內容,一個data屬性,vue會自動生成一段動態的數據放在掛載點中。
基本的數據表達式:
- {{ data }}
- v-text
- v-html
<h1>{{ msg }}</h1>
<div v-text="text"></div>
<div v-html="text"></div>
data () {
return {
msg: 'Welcome to Your Vue.js App',
text: '<div style="color: red">I am red</div>'
}
},
Vue中的屬性綁定和雙向數據綁定
<div v-bind:title="title" v-bind:class="[{ active: isActive }, 'title']">阿彌陀佛,麼麼噠</div>
data () {
return {
title: '大冰的暢銷書'
}
}
現在演示的都是單向綁定,那雙向綁定是什麼呢?
數據雙向綁定是指數據可以決定頁面的展示,頁面的操作也可以改變數據。
<input type="text" v-model="title">
data () {
return {
title: '大冰的暢銷書'
}
},
vue中常用指令
指令 (Directives) 是帶有 v- 前綴的特殊特性。指令特性的值預期是單個 JavaScript 表達式 (v-for 是例外情況,稍後我們再討論)。指令的職責是,當表達式的值改變時,將其產生的連帶影響,響應式地作用於 DOM。
v-bind
動態地綁定一個或多個特性,或一個組件 prop 到表達式。
<a v-bind:href="url">...</a>
<!-- 縮寫 -->
<a :href="url">...</a>
在這裏 href 是參數,告知 v-bind 指令將該元素的 href 特性與表達式 url 的值綁定。
<!-- class 綁定 -->
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
data: {
isActive: true,
errorClass: 'text-danger'
}
這裏的class是響應的,是根據data裏的值來顯示對應class的,當然你也可以加上指定的class。
v-show, v-if, v-for
v-if 是“真正”的條件渲染,因爲它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷燬和重建。
v-if 也是惰性的:如果在初始渲染時條件爲假,則什麼也不做——直到條件第一次變爲真時,纔會開始渲染條件塊。
相比之下,v-show 就簡單得多——不管初始條件是什麼,元素總是會被渲染,並且只是簡單地基於 CSS 進行切換。
一般來說,v-if 有更高的切換開銷,而 v-show 有更高的初始渲染開銷。因此,如果需要非常頻繁地切換,則使用 v-show 較好;如果在運行時條件很少改變,則使用 v-if 較好。
- 示例(更多用法參考官方文檔)
HTML
<!-- vue -->
<div>
<h2>問:猩猩最討厭什麼線?</h2>
<div>
<button :class="[{active: item.active}, 'js-button btn-answer']" v-for="item, index in btns" @click="clickHandle(index)">{{item.text}}</button>
</div>
<div class="js-answer"></div>
<div v-show="show">
<div v-if="answer == 0">
bingo!平行線沒有相交(香蕉)
</div>
<div v-else-if="answer == 1">
你怕是個假猩猩吧
</div>
<div v-else>
你怕是個假猩猩吧
</div>
</div>
</div>
<!-- twig -->
{% set items = ['A、平行線', 'B、線段', 'C、交叉線'] %}
{% for item in items %}
<button class="js-button btn-answer"
{{ item }}
</button>
{% endfor %}
<div class="js-answer"></div>
data
data () {
return {
show: false,
answer: 0,
btns: [
{
key: 0,
text: 'A、平行線',
active: false
},
{
key: 1,
text: 'B、線段',
active: false
},
{
key: 2,
text: 'C、交叉線',
active: false
}]
}
},
js
<!-- jquery -->
mounted() {
$('.js-button').click(function(e) {
let index = $(e.target).index();
let answerText = '';
index ? (answerText = '你怕是個假猩猩吧') : (answerText = 'bingo!平行線沒有相交(香蕉)')
$('.js-answer').text(answerText);
$(this).addClass('active').siblings().removeClass('active');
})
}
<!-- vue -->
methods: {
clickHandle(index) {
this.show = true;
this.answer = index;
this.btns.forEach( item=> {
if (item.key == index) {
item.active = true;
} else {
item.active = false;
}
})
}
}
v-on
綁定事件監聽器。事件類型由參數指定。
表達式可以是一個方法的名字或一個內聯語句,如果沒有修飾符也可以省略。
<!-- 方法處理器 -->
<button v-on:click="doThis"></button>
<!-- 縮寫 -->
<button @click="doThis"></button>
<!-- 內聯語句 -->
<button v-on:click="doThat('hello', $event)"></button>
<!-- 在子組件上監聽自定義事件 (當子組件觸發“my-event”時將調用事件處理器) -->
<my-component @my-event="handleThis"></my-component>
vue實例中方法和事件
數據傳輸方法
$emit
與$on
來進行組件之間的數據傳輸
-
1.父組件到子組件通信
-
2.子組件到父組件的通信
-
3.兄弟組件之間的通信
vm.$on( event, callback )
監聽當前實例上的自定義事件。事件可以由vm.$emit觸發。回調函數會接收所有傳入事件觸發函數的額外參數。
vm.$emit( eventName, […args] )
觸發當前實例上的事件。附加參數都會傳給監聽器回調。
vm.$emit('test', 'hi')
vm.$on('test', function (msg) {
console.log(msg) // hi
})
父子通信,子父通信,兄弟通信
代碼演示
- 父子通信
第一種:父組件給子組件傳子,使用props
<!-- 父組件 -->
<child :sonMsg="msg"></child>
// js
import child from './children.vue';
export default {
components: {
child
}
}
<!-- 子組件 -->
// html
<div class="children-text">{{sonMsg}}</div>
// js
export default {
props: {
sonMsg: {
type: String,
default: '父組件數據的默認值'
}
}
}
第二種:使用$refs
傳輸數據
<!-- 父組件 -->
// html
<input type="button" @click="parentEnvet" value="父組件觸發" />
<child ref="childcomp"></child>
// js
import child from './children.vue';
export default {
components: {
child
},
methods: {
parentEnvet() {
// 注意:這裏的childFn是子組件裏已存在的方法
this.$refs.childcomp.childFn();
// 或者這樣寫:this.$refs['childcomp'].childFn();
}
}
}
<!-- 子組件 -->
// js
methods: {
childFn() {
// do somethings
}
}
第三種:使用$emit 和 $on
傳輸數據(包括子父通信)
<!-- 父組件 -->
// html
<div class="parent-box">
<div class="mb20" v-text="vals"></div>
</div>
<div class="children-box">
<child @showMsg="msgFromChild" :sonMsg="msg">
</child>
</div>
// js
<script>
import child from './children.vue';
export default {
components: {
item
},
data () {
return {
vals: '我會展示子組件傳給我的數據',
msg: '我是父組件的數據,將傳給子組件~'
}
},
methods: {
// 接受子組件的數據
msgFromChild(data) {
this.vals = data;
}
}
}
</script>
<!-- 子組件 -->
// html
<div>
<div class="children-text">{{parentMsg}}</div>
<button @click="send">子組件觸發</button>
</div>
// js
<script>
export default {
props: {
parentMsg: {
type: String,
default: '父組件數據的默認值'
}
},
data () {
return {
msg: '我真的是太帥了'
}
},
methods: {
send() {
// 給父組件傳遞數據
this.$emit('showMsg', this.msg)
}
}
}
</script>
- 非父子組件進行通信
思考:瞭解了父子通信後,你認爲非父子組件之間的通信應該是怎樣的呢?
非父子組件之間傳值,需要定義個公共的實例文件bus.js,作爲中間倉庫來傳值,不然路由組件之間達不到傳值的效果。
1.建立公共的實例文件,內容如下:
// src/util/bus.js
import Vue from 'vue'
export default new Vue();
2.分別在非父子組件內引入該公共實例文件(假如命名爲Bus)
A組件在方法裏使用Bus.$emit('fnName', data)
傳送數據
// 組件A
<template>
<div>
<h3>我現在要跟B組件打個招呼</h3>
<input type="text" @change="saiHi" v-model="text"/>
</div>
</template>
<script>
import Bus from '../util/bus.js';
export default {
data () {
return {
text: '你好,我是小豬佩奇A'
}
},
methods: {
saiHi() {
Bus.$emit('saiHi', this.text);
}
}
}
</script>
B組件(常在created,mounted生命週期裏)使用Bus.$on('fnName', (data) => {xxx})
接收數據
// 組件B
<template>
<div>
<div class="message-text" v-for="msg in msgs" v-text="msg.text"></div>
</div>
</template>
<script>
import Bus from '../util/bus.js';
export default {
data () {
return {
msgs: [{
text: 'hello'
}],
}
},
mounted() {
Bus.$on('saiHi', (data) => {
this.msgs.push({text: data});
})
},
}
</script>
Vue中計算屬性computed和監聽屬性函數watch
定義
**計算屬性:**基於它們的依賴進行緩存的。只在相關依賴發生改變時它們纔會重新求值。
**偵聽屬性:**當需要在數據變化時執行異步或開銷較大的操作時,這個方式是最有用的。通常更好的做法是使用計算屬性而不是命令式的 watch 回調
computed和watch比較
<div id="demo">{{ fullName }}</div>
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar',
fullName: 'Foo Bar'
},
watch: {
firstName: function (val) {
this.fullName = val + ' ' + this.lastName
},
lastName: function (val) {
this.fullName = this.firstName + ' ' + val
}
}
})
fullName屬性依賴於firstName和lastName,這裏有個缺點就是,無論firstName或lastName其中的任何一個發生改變時,都要調用不同的監聽函數來更新fullName屬性。但是當我們使用計算屬性時,代碼就會變得更加簡潔。
var vm = new Vue({
el: '#demo',
data: {
firstName: 'Foo',
lastName: 'Bar'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName
}
}
})
這時,我們只要監聽fullName屬性就行,至於firstName或lastName屬性的任何改變,我們都可以通過fullName的getter()方法得到最終的fullName值。
另外需要注意的是,計算屬性默認只有 getter ,不能通過this.xxx = 'xxx'
這種方式去賦值,不過在需要時你也可以提供一個 setter,允許同時設置getter()、setter()方法。如下:
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
}
-
相同點:
首先它們都是以Vue的依賴追蹤機制爲基礎的,它們的共同點是:都是希望在依賴數據發生改變的時候,被依賴的數據根據預先定義好的函數,發生“自動”的變化。 -
不同點:
watch和computed各自處理的數據關係場景不同
(1) watch擅長處理的場景:一個數據影響多個數據。適合監控場景,某【一個】變量改變時需要做什麼操作;類似於onchange,適合耗時操作,如網絡請求等。
(2) computed擅長處理的場景:一個數據受多個數據影響。某【一些】變量發生變化時,影響的【單個】結果對應地發生改變。
生命週期
-
創建前/後**(beforeCreated/created)**: 在beforeCreated階段,vue實例的掛載元素
$el
和數據對象data都爲undefined,還未初始化。在created階段,vue實例的數據對象data有了,$el
還沒有。 -
載入前/後**(beforeMount/mounted)**:在beforeMount階段,vue實例的$el和data都初始化了,但還是掛載之前爲虛擬的dom節點,data.message還未替換。在mounted階段,vue實例掛載完成,data.message成功渲染。
-
更新前/後**(beforeUpdate/updated)**:當data變化時,會觸發beforeUpdate和updated方法。
-
銷燬前/後**(beforeDestory/destroyed)**:在執行destroy方法後,對data的改變不會再觸發周期函數,說明此時vue實例已經解除了事件監聽以及和dom的綁定,但是dom結構依然存在
相關鏈接
[1]. 我的掘金
[2]. github相關演示代碼