元件定義
// 全域性定義
Vue.component('my-lists', {
// options
})
複製程式碼
定義後,可以在template
模版中使用<my-list></mylist>
,此時會將元件中定義的內容顯示出來。
<template>
<div>
<my-list></mylist>
</div>
</template>
複製程式碼
通過例子來看一下
<body>
<div id='app'>
<my-list></my-list>
</div>
</body>
<script>
Vue.component('my-list', {
template: `
<ul>
<li>上海</li>
<li>北京</li>
<li>南京</li>
</ul>
`
})
new Vue({
el: '#app'
})
</script>
複製程式碼
頁面會顯示出我們定義的my-list
的元件內容,``
這個符號是ES6中的模版字串,想詳細瞭解的話,可以看MDN上關於模版字串的說明。
如果不需要全域性定義的話,那可以在Vue例項中區域性定義
var myList = {
template: `
<ul>
<li>上海</li>
<li>北京</li>
<li>南京</li>
</ul>
`
}
new Vue({
el: '#app', // 掛載
components: {
'my-list': myList
}
})
複製程式碼
元件內的data
上面是簡單的元件,如果我們想自己通過變數,來控制列表的展示,這個時候,我們元件內部定義data
。我們來重新寫my-list
元件:
var citys = ['上海', '北京', '廣州']
Vue.component('my-list', {
template: `
<ul>
<li v-for='(item, index) in citys' :key='index'>{{item}}</li>
</ul>
`,
data () {
return {
citys: citys
}
}
})
new Vue({
el: '#app'
})
複製程式碼
有一點要注意,data
必須是一個函式,將值通過函式返回。如果是一個變數:
var citys = ['上海', '北京', '廣州']
Vue.component('my-list', {
template: `
<ul>
<li v-for='(item, index) in citys' :key='index'>{{item}}</li>
</ul>
`,
data: {
citys: citys
}
})
複製程式碼
會導致一個問題,多個相同元件同時使用時,它們的data
是共享的,會出現相互影響的情況。類似於淺拷貝的這種情況
var a = {name: 'a'}
var b = a
var c = a
console.log(b.name, c.name) // a a
console.log(b.name, c.name) // a a
b.name = 'b'
console.log(b.name) // b
console.log(c.name) // b
// b是copy a的引用,所以b改變了的同時會影響a
// 元件內的data同理,所以將data的值以函式返回,以建立不同的物件,而不是共享一個
var a = function () {
return {
name: 'a'
}
}
var b = a() // b是新物件
var c = a() // c也是新物件
b.name = 1
console.log(c.name) // a
複製程式碼
父子元件的通訊
- 父元件通過傳遞
Props
給子元件 - 子元件獲取到父元件傳遞的值,執行一些列操作後,通過
emit
觸發事件,告訴父元件發生了什麼 - 父元件可以見通過
v-on
/@
監聽這個事件
以上述的my-list
為例子,實現當點選城市名稱時,會在下方顯示點選的城市:
<body>
<div id='app'>
<my-list
:citys='citys'
@select='getCity'></my-list>
<p>{{selCity}}</p>
</div>
</body>
<script>
Vue.component('my-list', {
template: `
<ul>
<li
v-for='(item, index) in citys'
:key='index'
@click='select(item)'>{{item}}</li>
</ul>
`,
props: ['citys'],
methods: {
select (city) {
this.$emit('select', city)
}
}
})
new Vue({
el: '#app',
data () {
return {
citys: ['上海', '北京', '廣州'],
selCity: ''
}
},
methods: {
getCity (city) {
this.selCity = city
}
}
})
</script>
複製程式碼
:citys
動態繫結props
的使用者,:
是v-bind的縮寫
;如果傳遞的是一個靜態的值,則可以直接寫成citys="['上海','北京']"
@select
父元件監聽子元件觸發的事件this.$emit('select', city)
;@
是v-on
的縮寫;如果子元件觸發了select
,會響應父元件的'getCity'函式
我們需要注意的是,父子元件通訊是單向的,即父元件傳遞給子元件的props
發生變化時,子元件也會接收到這種變化,但是如果子元件改變props
的值時,不會反饋給父元件,防止修改了父元件的狀態,導致整個的資料流難以理解,如果修改了,Vue也會發出警告。
props
對於子元件來說應該是隻讀的。有兩種情況下,我們會想改變props
:
- props傳遞進來後,我們需要對props進行處理,然後輸出到頁面上,這種情況下,可以通過
computed
來計算處理後的變數
computed: {
newCitys () {
this.citys.filter((ele) => {
return ele !== '上海'
})
}
}
複製程式碼
- 作為一個初始值,後續需要對其進行修改,計算等;這種情況下,可以將
props
賦值給自身的屬性
data () {
return {
initCitys: this.citys
}
}
複製程式碼
如果我們想修改props
的值,並將變化反饋給父元件,除了$emit
觸發事件 + 父元件監聽事件這種方式外,還有一種較為簡單的方式,通過sync
操作符
// 父元件
<child-component :name.sync='name'></child>
// 子元件想要能夠修改name,可以這麼做
this.$emit('update:name', 'newVal')
複製程式碼
上述我們是直接傳遞props
,我們可以在子元件中通過定義props
的格式來對props
進行簡單的驗證,以下一段驗證程式碼來自官網,允許偷個懶= _=||
Vue.component('example', {
props: {
// 基礎型別檢測 (`null` 指允許任何型別)
propA: Number,
// 可能是多種型別
propB: [String, Number],
// 必傳且是字串
propC: {
type: String,
required: true
},
// 數值且有預設值
propD: {
type: Number,
default: 100
},
// 陣列/物件的預設值應當由一個工廠函式返回
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 自定義驗證函式
propF: {
validator: function (value) {
return value > 10
}
}
}
})
複製程式碼
多個同級元件間的通訊
在複雜專案中,可能會出現多個同級的元件需要通訊,而僅僅是簡單的父子元件通訊,這個時候怎麼去做呢?
通過新建一個Vue例項,作為事件匯流排
var emitEvent = new Vue()
// 在不同的元件中,通過觸發事件,監聽事件來實現通訊
emitEvent.$emit('event-name', val)
emitEvent.$on('event-name', funciton (val) {
})
複製程式碼
統一狀態管理,可以在專案中使用Vuex
Vuex
是一個專門為Vue.js
開發狀態管理軟體。
Vuex中有幾個核心的概念
-
State 儲存狀態,類似於data屬性
-
Getter 從
state
中派生出一些屬性,類似於computed -
Mutation 更改
state
的屬性,state
屬性是無法直接通過賦值進行更改的,需要通過Mutation
定義的函式來進行賦值,提交的是state
-
Actions
Mutation
必須是同步的函式,所以在Actions中處理非同步的操作,並且提交的是Mutation
-
Module 當專案很大的時候,需要根據不同的功能分割成不同的模組,每次需要的時候,只需要引用需要的模組即可
比如一個專案中使用Vuex,首先安裝Vuex npm install vuex --save
,通過腳手架vue-cli
,一般預設自帶Vuex
Vuex.store的目錄結構可以是這樣的
store
- index.js // 統一模組的index
- modules
- a.js // 模組 a
- b.js // 模組 b
複製程式碼
store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import a from './modules/a'
import b from './modules/b'
Vue.use(Vuex)
export default new Vuex.Store({
modules: {
a,
b
}
})
複製程式碼
store/modules/a.js
export default {
namespaced: true, // 必要的
state: {
data: null
},
mutations: {
setData(state, data) {
state.data = data
}
},
actions: {
getData (context, cb) {
// 假設執行的從服務端獲取的資料
http.post(url, {name: 'b'}, function (res) {
// 提交mutation操作
context.commit('setData', res)
// 如果有回撥函式的話
typeof cb === 'funciton' && cb(res)
})
}
}
}
複製程式碼
store/modules.b.js 類似於a,在此就不舉例子了。
在元件中如何是使用呢?
首先匯入Vuex提供的方法
// components/a.vue
// 首先,確定需要哪些功能
// 如果只需要state中的資料
import { mapState } from 'vuex'
// 如果只需要state中的資料 和 mutations操作
import { mapState, mapMutations } from 'vuex'
// 如果還對Actions有需求
import { mapState, mapMutations, mapActions } from 'vuex'
// 需要什麼匯入什麼即可
// 小tips: 可以先寫 from 'vuex',再寫{}中的,編輯器會自動不全
複製程式碼
然後匯入我們在Store中定義的屬性和方法
# 使用 a 模組,並且把a模組中的data賦值給aData
computed: {
...mapState('a', {
aData: state => state.data
})
...mapGetters('a', {
xxx: state => state.xxx
})
}
# 匯入方法
methods: {
...mapMutations('a', [
'setData'
])
...mapActions('a', [
'getData'
])
}
複製程式碼
使用屬性和方法
// 屬性和方法通過this呼叫
this.aData
// 重新賦值
this.setData('aaa')
// 傳入回撥函式
this.getData(function (res) {
console.log(res)
})
複製程式碼
上面的程式碼中我們使用...
Javascript的擴充套件操作符和 aData: state => state.data
的箭頭函式,如果對這兩項有不瞭解的,可以查閱連結
感謝,如果有什麼寫的不好的地方,請聯絡作者,比心~