先介紹一下什麼是組件把:
建立組件的兩種方式:html
// 組件就是vue的一個拓展實例 let component=Vue.extend({ data(){ return{ //與vue實例中的data不一樣,子組件的data必須是一個方法,必須有返回值,且返回值是對象。 //這樣作可使組件中的數據獨立。 //須要共享數據時可把return的對象聲明全局變量 } } template:'<div></div>'// 模板 這個組件的html元素 // }) //註冊組件 Vue.component('hehe',component)
(簡寫)vue
Vue.component('組件名',{ template:''// 模板 })
new Vue({ el:'#app', data:{ test:11 }, components:{ one:{ template:'<h1>這裏是局部組件 </h1>' } } })
須要注意的是子組件的命名沒法識別駝峯命名法,當組件作爲標籤使用的時候須要用「-」和小寫字母替換該大寫字母。vuex
<div> <one-data></one-data> </div> new Vue({ el:'#app', data:{ test:11 }, components:{ oneData:{ template:'<h1>這裏是局部組件 </h1>' } } })
一、父子屬性傳值
子組件不能直接使用父級data的內容,也不能直接修改父組件傳遞的值,但能夠經過設置props屬性來得到自身屬性值。
原理:npm
代碼實現:(實現過程當中踩過的坑)
1.template標籤內必須有且只有一個根元素
2.子組件標籤內要經過v-bind的方式綁定父級的data的值
3.子組件經過props定義的自身屬性值(test)獲取父組件的data中的內容(父組件:{{name}} ;子組件:{{test}})app
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <script src="base/vue.js"></script> </head> <body> <div> {{name}} <son :test='name'></son> </div> <!--實現功能較複雜時,會單獨寫個template標籤,經過id與子組件中的template相關聯,不然字符串拼接會很麻煩--> <template> <div>{{test}}</div> </template> </body> <script> new Vue({ el:'#myApp', data:{ name:'加油鴨!' }, components:{ son:{ template:'#tp',//相似於 el props:['test'] } } }) </script> </html>
(全局組件無固定父子關係,該組件標籤放在哪一個標籤內就是哪一個標籤的子組件)異步
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>父向子傳值</title> <script src="base/vue.js"></script> </head> <body> <div> <!--c1就是myApp的子組件--> <c1></c1> </div> <template> <div> <h4>我是c1,是父級</h4> <button @click="change">點我c2變</button> {{state}} <hr> <!--寫在c1的template內,就是c1的子組件--> <c2 :changed='state'></c2> </div> </template> <template> <div> 我是c2,是子級 <div v-show='changed'><h1>我是div</h1></div> </div> </template> </body> <script> Vue.component("c1",{ template:'#tp1', data(){ return { state:true } }, methods:{ change(){ this.state=!this.state } } }) Vue.component("c2",{ template:'#tp2', props:['changed'] }) let vm=new Vue({ el:'#myApp' }) </script> </html>
二、子父事件傳值
子組件不能直接修改父組件傳遞的值,可間接經過事件修改函數
原理ui
代碼實現:(點擊子組件按鈕,父組件div顯示和隱藏)
代碼中有一些思路註釋:this
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>子向父傳值</title> <script src="base/vue.js"></script> </head> <body> <div> <c1></c1> </div> <template> <div> <h4>我是c1,是父級</h4> <div v-show='state'><h1>我是div</h1></div> <hr> <!--c2自定義了一個changed事件處理父組件的函數change--> <c2 @changed='change'></c2> </div> </template> <template> <div> 我是c2,是子級 <!--子組件點擊按鈕,父組件顯示隱藏,固然有點擊事件啦, 因此給button加點擊事件觸發一個函數,發現c2沒有設置methods, 因此去c2的實例中加一個methods並設置函數sclick, 再經過sclick函數把其自定義事件changed拋出, changed裏面就是c1的處理函數--> <button @click="sclick">點我c1變</button> </div> </template> </body> <script> Vue.component("c1",{ template:'#tp1', data(){ return { state:true } }, methods:{ change(){ this.state=!this.state } } }) Vue.component("c2",{ template:'#tp2', methods:{ sclick(){ this.$emit('changed') } } }) let vm=new Vue({ el:'#myApp' }) </script> </html>
三、非父子傳值spa
原理
(1)公有的父元素做爲橋接-----結合父子屬性傳值和子父事件傳值來實現(適用於親兄弟)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>兄弟傳值</title> <script src="base/vue.js"></script> </head> <body> <div> 我是父級 {{state}} <hr> <!--c1和c2都是div的子組件--> <!--子父事件傳值--> <c1 @emit='change'></c1> <hr> <!--父子屬性傳值--> <c2 :test='state'></c2> </div> <template> <div> 我是c1,是c2的兄弟 <!--間接經過父級改變了兄弟級的值--> <button @click='emit'>點我個人兄弟和父級都會發生改變</button> </div> </template> <template> <div>我是c2,是c1的兄弟 <p>{{test}}</p> </div> </template> </body> <script> Vue.component('c1',{ template:'#tp1', methods:{ emit(){ this.$emit('emit') } } }) Vue.component('c2',{ template:'#tp2', props:["test"] }) new Vue({ el:'#myApp', data:{ state:false }, methods:{ change(){ this.state=!this.state } } }) </script> </html>
(2)公共汽車傳值(聲明一個公共實例做爲過濾)
修改誰的值就去觸發誰的方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>兄弟之間經過公共汽車傳值</title> <script src="base/vue.js"></script> </head> <body> <div> <father></father> </div> <template> <div>我是父組件 <hr> <son1></son1> <hr> <son2></son2> </div> </template> <template> <div>{{name}} <!--點擊事件觸發一下sclick函數,至關於把拋出的change函數觸發了--> <button @click='sclick'>點我</button> </div> </template> <template> <div>{{name}}</div> </template> </body> <script> let Bus=new Vue(); new Vue({ el:'#myApp', components:{ father:{ template:'#father', components:{ son1:{ template:'#son1', data(){ return{ name:'我是子組件1' } }, methods:{ sclick(){ //觸發test事件,再傳一個參數給change函數中的val //name值就從「我是子組件2」經過點擊事件變成了"加油鴨!!!!" Bus.$emit('test',"加油鴨!!!!") } } }, son2:{ template:'#son2', data(){ return{ name:'我是子組件2' } }, methods:{ change(val){ this.name=val } }, mounted(){ //只要mounted執行了,說明組件已經準備就緒 //註冊一個函數,函數名叫test,處理函數就是methods中的change函數 //簡單來講,只要想辦法觸發test事件就至關於執行了change函數 Bus.$on('test',this.change) } } } } } }) </script> </html>
(3)vuex(集中式的數據狀態管理器)
簡單來講,就是用來管理全局變量的,無論哪裏進行修改,頁面都會隨之變化。好比咱們手機端的選擇所在區域,假設你選了北京,跳到其餘頁面仍是顯示的北京就能夠用vuex來實現。
解決的問題:
幫助咱們管理共享狀態。
vuex的相關配置步驟:
npm install vuex --save-dev
Vue.use(Vuex)
var store=new Vuex.Store({ state:{ }, mutations:{ }, actions:{ }, getters:{ } })
new Vue({ el: '#app', router, store, components: { App}, template: '<App/>', })
vuex中的模塊:
import Vuex from 'vuex' Vue.use(Vuex) let store=new Vuex.Store({ state:{ name:1, } }) export default store; //通常咱們會新建一個store文件夾, //在該文件夾的js文件中經過暴露出store, //再經過在main.js中引入該文件的方式來使用vuex
在組件中咱們只須要經過{{this.$store.state.name}}
就能夠渲染name的值
寫一個組件:
<template> <div> {{msg}} {{this.$store.state.name}} <hr> </div> </template> <script> export default { name:'List', data(){ return { msg:'list', } } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
有木有以爲{{this.$store.state.name}}太長了,可不能夠直接寫{{name}}:
<template> <div> {{msg}} {{name}} <hr> </div> </template> <script> export default { name:'List', data(){ return { msg:'list', } }, computed:{ name(){ return this.$store.state.name } } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
有小夥伴會說了,這樣也不簡單呀,那這樣呢?
<template> <div> {{msg}} {{name}} <hr> </div> </template> <script> import {mapState} from 'vuex' export default { name:'List', data(){ return { msg:'list', } }, //可不能夠不用拓展操做符?能夠呀 //computed:mapState(['name']) //但是這樣你若是還有其餘的方法要在computed中操做就無法操做了 computed:{ ...mapState(['name']) } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
若是遇到須要更名的狀況,可經過對象的形式:
{{_name}} //改後的名字進行頁面渲染 ...mapState({_name:"name"})
後面的方法基本思路同樣,接下來就都用簡寫形式啦!
2. mutations:修改狀態
import Vuex from 'vuex' Vue.use(Vuex) let store=new Vuex.Store({ state:{ name:1, }, mutations:{ CHANGE_NUM(state,name){ state.name=name } }, }) export default store;
咱們來作一個小效果,點擊按鈕改變狀態值從1變爲888
<template> <div> <div @click='CHANGE_NUM(888)'>change</div> {{msg}} {{_name}} <hr> </div> </template> <script> import {mapState,mapMutations} from 'vuex' export default { name:'List', data(){ return { msg:'list', } }, methods:{ //非簡寫形式,點擊事件的調用方法換爲getName //getName(){ // this.$store.commit('CHANGE_NUM',888) // } ...mapMutations(['CHANGE_NUM']), }, computed:{ ...mapState({_name:'name'}) } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
3. actions:專門用來作異步操做
經過計時器模擬一個異步操做,並經過commit觸發mutations
import Vuex from 'vuex' Vue.use(Vuex) let store=new Vuex.Store({ state:{ name:1, }, mutations:{ CHANGE_NUM(state,name){ state.name=name } }, actions:{ //邏輯處理及異步請求 getNumApi({commit},params){ setTimeout(()=>{ commit('CHANGE_NUM',params) },2000) } } }) export default store;
再來實現一個點擊按鈕改變值的效果:
<template> <div> <div @click='getNumApi("xixi")'>change</div> {{msg}} {{_name}} <hr> </div> </template> <script> import {mapState,mapActions} from 'vuex' export default { name:'List', data(){ return { msg:'list', } }, methods:{ //非簡寫的寫法:(經過dispatch觸發相應的action) //emitActions(params){ // this.$store.dispatch('getNumApi',params) // } ...mapActions(['getNumApi']) }, computed:{ ...mapState({_name:'name'}) } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
2秒後name值改變了
4. getters:相似於計算屬性computed,裏面進行一些計算操做
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) let store=new Vuex.Store({ state:{ name:1 }, mutations:{ CHANGE_NUM(state,name){ state.name=name } }, getters:{ double(state){ return state.name*2 } }, actions:{ //邏輯處理及異步請求 getNumApi({commit},params){ setTimeout(()=>{ commit('CHANGE_NUM',params) },2000) } } }) export default store;
再來作點擊事件:
<template> <div> <div @click='getNumApi("xixi")'>change</div> {{msg}} {{_name}} {{double}} <hr> </div> </template> <script> import {mapState,mapMutations,mapActions,mapGetters} from 'vuex' export default { name:'List', data(){ return { msg:'list', } }, methods:{ ...mapActions(['getNumApi']) }, computed:{ ...mapState({_name:'name'}), ...mapGetters(['double']) } } </script> <style> #list div{ width: 50px; height: 50px; background: red; } </style>
因爲字符串不能進行乘法操做,因此打印結果是NaN
5. modules:模塊
在實際開發中,咱們會把以上四個模塊,分別寫在四個js文件中,在經過引入、暴露的形式寫在一個index.js文件下。
import actions from './actions' import state from './state' import mutations from './mutations' import getters from './getters' export default { state, mutations, getters, actions }
再把這5個文件放在store文件夾下的shopcar文件夾下(名字隨意),在再store文件夾下,新建一個index.js文件,並經過modules的形式展示:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) import shopcar from './shopcar' let store=new Vuex.Store({ modules:{ shopcar:shopcar } }) export default store
來源:https://blog.csdn.net/weixin_43747906/article/details/84981199