前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Vue】数据通信——我们从组件通信说起

【Vue】数据通信——我们从组件通信说起

作者头像
DDGarfield
发布2022-06-23 18:04:51
2.9K0
发布2022-06-23 18:04:51
举报
文章被收录于专栏:加菲的博客加菲的博客

vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要。我们Vue数据通信就从组件通信开始说起。

1.写在前面

Vue崇尚或者说机制就是单向数据流。

2.父子组件

Vue崇尚的是单向数据流,包括父子组件之间的传值,值的修改:

  • 父组件向子组件传值一定是通过属性props
  • 子组件修改父组件值一定是通过事件
    • 以参数的形式 this.$emit("eventName",value) 通过事件,提交给父组件,然后在父组件绑定事件

2.1 父组件→子组件

父组件向子组件传值,便是在父组件调用子组件时,用:冒号传递属性值,在子组件中用props接收值。

示例:向子组件传递数字,由子组件自行处理UI逻辑。

父组件
代码语言:javascript
复制
 <count-to ref="countTo" :end-val="endVal"></count-to>
 //omit import component code 
 //omit 
 <script>
     export default {
         //omit other code
          data () {
            return {
              endVal: 100
            }
          },
 </script>
  • :end-val—父组件传值
  • endVal—值
子组件
代码语言:javascript
复制
<template>
 <!--omit component code-->
</template>
<script>
    export default {
        props: {
            endVal: {
                type: Number,
                required: true
            },
        }
    }
</script>
  • propsendVal 接收父组件的传值

2.2 子组件→父组件

子组件向父组件传值,便是在子组件中使用*this.$emit("eventName",value)*向父组件传递值

子组件

示例:子组件传递值,并由父组件获取且作其他处理。

代码语言:javascript
复制
<script>
export default {
    methods: {
        getCount () {
            return this.$refs.number.innerText
        },
        emitEndEvent () {
            setTimeout(() => {
                this.$nextTick(() => {
                    this.$emit('on-animation-end', Number(this.getCount()))
                })
            }, this.duration * 1000 + 5)
        }
    },
    mounted () {
        this.$nextTick(() => {
            setTimeout(() => {
                this.counter.start()
                this.emitEndEvent()  //DOM变化
            }, this.delay)
        })
    }
}
</script>

★this.$nextTick,是将回调函数延迟在下一次dom更新数据后调用 setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。 ”

  • this.$emit('on-animation-end', Number(this.getCount())):触发on-animation-end事件,及传递值
父组件
代码语言:javascript
复制
//omit other code
 <count-to ref="countTo" :end-val="endVal" @on-animation-end="handleEnd"></count-to>
<script>
export default {
  data () {
    return {
      endVal: 100
    }
  },
  methods: {
    handleEnd (endVal) {
      console.log('end -> ', endVal)
    }
  }
}
</script>   
  • @on-animation-end—父组件中绑定子组件事件
  • endVal—接收子组件传递的值

2.3 v-model

v-model其实是一个语法糖,实质还是走的子组件向父组件传递值的套路,只是这里指定一下调用this.$emit的是子组件的@input事件:

代码语言:javascript
复制
<input @input="handleInput" :value="value">
<script>
export default{
    props:{
        value:{
            type:[String,Number],
            default:''
        }
    },
    methods:{
        handleInupt(event){
            const value=event.target.value
            this.$emit("input",value)
        }
    }
}
</script>

然后在父组件中定义@input事件,在事件中处理子组件传递的值

代码语言:javascript
复制
<child :value="inputValue" @input="handleInput"></child>
<script>
export default{
    data(){
      return {
          inputValue:''
      }  
    },
    methods:{
        handleInupt(val){
            this.inputValue=val
        }
    }
}
</script>

所以:

  • 改变父组件的值,子组件会因为父组件中的:value改变,
  • 向子组件输入值,父组件会因为事件触发,改变值

v-model

代码语言:javascript
复制
<!--父组件-->
<child v-model="value">
代码语言:javascript
复制
<!--子组件-->
<script>
export default{
    props:{
        value:{
            type:[String,Number],
            default:''
        }
    }
}
</script>

当然这里子组件改变值的事件是input事件,但是像checkbox改变值的事件是change,而v-mode默认会利用名为valueprop和名为input事件,此时就需要做出调整:

代码语言:javascript
复制
<input type="checkbox" v-bind:checked="checked" v-on:change="$emit('change',$event.target.checked)">
<script>
    export default{
        model:{
            prop:'checked',
            event:'change'
        },
        props:{
            checked:Boolean
        }
    }
</script>

使用mode选项改变默认的v-model的绑定属性与抛出事件。此时父组件就可以直接使用v-model绑定从而改变的checkbox的值。

3.兄弟组件

回顾了父子组件的传值,那么兄弟组件呢?其实也很简单,运用上面父子组件之间传值的机制,把父组件作为媒介即可。通俗一点:

  • 通过A组件触发事件改变父组件值
  • 改变的这个值作为兄弟B组件的值

体会一下,就不赘述示例了。

4.bus

跨文件的组件之间又怎么传值呢?又没有父组件作为媒介。

4.1 定义总线bus

new一个Vue实例

代码语言:javascript
复制
import Vue from 'vue'
const Bus=new Vue()
export default Bus

4.2 全局引入总线bus

Vue的原型对象上添加上面定义的bus,一般使用$符号

代码语言:javascript
复制
//main.js
import Vue from 'vue'
import App from './App.vue'
import Bus from './bus'
import router from './router'
Vue.prototype.$bus=Bus

new Vue({
    router,
}).$mount('#app')

★原型对象上添加的属性,通过new会传递给对象实例。JavaScript对象实例中取一个属性值,会像俄罗斯套娃一样找__prop__,前端童鞋称为原型链,一直找到根儿上的Object.prototype,如果在根儿上都没有找到,那么这个属性就是undefined

所以整个上面那样为原型对象添加bus后,整个项目中的vue实例,都能访问这个bus,当然这个bus可以以$bus获取,获取的是另一个vue实例,专用于通信的实例。

4.3 使用bus

4.3.1 定义事件方法

像子组件向父组件一样,定义事件方法,只是现在我们使用的是$bus属性取到的Vue实例:

代码语言:javascript
复制
this.$bus.$emit('on-click','hi')
  • emit触发bus实例事件
4.3.2 取值
代码语言:javascript
复制
this.$bus.$on('on-click',msg=>{
    console.log=msg
})
  • 使用on对bus的Vue实例的事件绑定监听

5.Vuex

Vuex是什么?官方给的定义:Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。太抽象了,太官方了,并不能帮助我们理解记忆。博主给定义:Vuex就是一个集中管理数据并作为通信中介的工具

5.1 引入Vuex

代码语言:javascript
复制
import Vue from 'vue' //引入vue
import Vuex from 'vuex' //引入vuex

Vue.use(Vuex) //Vuex作为插件加载

5.2 Store

代码语言:javascript
复制
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//创建vuex实例
export default new Vuex.Store({
    //strict:
    //state:
    //getters:
    //mutations:
    //actions:
    //modules:
    //plugins:
})
代码语言:javascript
复制
constructor(options: StoreOptions<S>);

export interface StoreOptions<S> {
  state?: S | (() => S);
  getters?: GetterTree<S, S>;
  actions?: ActionTree<S, S>;
  mutations?: MutationTree<S>;
  modules?: ModuleTree<S>;
  plugins?: Plugin<S>[];
  strict?: boolean;
  devtools?: boolean;
}

从上面的定义可以看出Store构造方法中有:

  • state
  • getters
  • actions
  • mutations
  • modules:模块
  • plugins
  • strict
  • devtool

5.3 state

看下这个图吧,着重看一下Vuex的范围。按单向数据流:数据流总是 ActionsMutationsState,但是我们使用时也不一定总是全部使用,灵活一点。state作为vuex数据的终点,称为根状态,定义的值称为状态值。这些状态值便可以在各个组件中使用:

5.3.1 定义state

state就是一个json对象,键值对集合

代码语言:javascript
复制
const state={
    projectName:"test"
}
5.3.2 取值

一般都在组件中的计算属性中获得state值

方法一:this.$store.state

代码语言:javascript
复制
export default {
    computed:{
        projectName(){
            this.$store.state.projectName
        }
    }
}

方法二:vuex工具函数mapState

代码语言:javascript
复制
import {mapState} from 'vuex' //es6解构赋值

export default {
    computed:{
        ...mapState({
            projectName:state=>state.appName
        })
    }
}

5.4 getter

5.4.1 定义getter

相当于state的计算属性,它依然是一个json对象

代码语言:javascript
复制
const getters={
    projectNameWithVersion:(state)=>{
        return state.projectName+'v1.0.0'
    }
}

state代表当前目录同级的state,通过state获取state定义的值

5.4.2 取值

跟state取值方式类似

方法一:this.$store.getters

代码语言:javascript
复制
export default {
    computed:{
        projectNameWithVersion(){
            this.$store.getters.projectNameWithVersion
        }
    }
}

方法二:vuex工具函数mapGetters

代码语言:javascript
复制
import { mapGetters } from 'vuex'

export default {
    computed:{
        ...mapGetters([
            'projectNameWithVersion'
        ]),
    }
}

5.5 mutation

如果操作没有异步操作,那么我们也是可以不走action,可以在组件中通过commit mutation 提交state的改变

另外,当我们在组件中,需要修改一个state状态值,不可以通过赋值的方式,在组件中直接修改state状态值,而是通过commit,提交一个mutation,或者dispatch一个action才能修改。帮助我们梳理数据改变,提供一个清晰的数据流。如果强行赋值修改,严格模式下,便会报错:

5.5.1 定义mutation
代码语言:javascript
复制
const mutations={
    Set_projname(state,params){
        state.projectName=params.pjname
    }
}
  • state代表当前目录同级的state,通过state获取state定义的值
  • params为组件commit的对象
5.5.2 调用mutation

方法一:commit

代码语言:javascript
复制
this.$store.commit('set_pjname',{
    pjname:"testnew"
})

方法二:vuex工具函数mapMutations

代码语言:javascript
复制
import { mapMutations } from 'vuex'
export default {
    methods:{
        ...mapMutations([
   'Set_projname'
        ])  
    },
}

调用

代码语言:javascript
复制
this.Set_pjname("testnew")
5.5.3 增加state值

可以使用vue.set增加state中没有定义的值

代码语言:javascript
复制
import vue from 'vue'
const mutations={
    Set_pjname(state,params){
        state.projectName=params.pjname
    },
    SET_VERSION(state){
        vue.set(state,"version","v2.0")
    }
}

5.6 action

mutation只能做同步操作,而异步操作就需要action作异步操作,这就是前后端开发的边界,请求接口。

5.6.1 定义action
代码语言:javascript
复制
const actions={
    updateProjectName({commit}){
        //omit request api
        commit('Set_projname',res.info.projname)
    }
}
  • 参数中取到commit
  • 调用commit一个mutation
5.6.2 获取action
代码语言:javascript
复制
import {mapActions} from 'vuex'

export default {
    methods:{
        ...mapActions([
   'updateProjectName'
        ])  
    },
}
5.6.3 触发action

使用dispatch触发上面取到的action

代码语言:javascript
复制
this.$store.dispatch("updateProjectName","testNew")

5.7 模块

代码语言:javascript
复制
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//创建vuex实例
export default new Vuex.Store({
    //strict:
    //state:
    //getters:
    //mutations:
    //actions:
    //modules:  //模块
    //plugins:
})

项目大的时候,可以拆分成模块,模块还可以继续包含模块:

代码语言:javascript
复制
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)
//创建vuex实例
export default new Vuex.Store({
    //strict:
    //state:
    //getters:
    //mutations:
    //actions:
    modules:{
        m1,
        m2
    }
    //plugins:
})

每一个模块又可以全包含或者部分包含state getters mutations actions

代码语言:javascript
复制
const state = {
  userName: 'Lison'
}
const getters = {
  firstLetter: (state) => {
    return state.userName.substr(0, 1)
  }
}
const mutations = {
  SET_USER_NAME (state, params) {
    state.userName = params
  }
}
const actions = {
  updateUserName ({ commit, state, rootState, dispatch }) {
    // rootState.appName
    dispatch('xxx', '')
  },
  xxx () {
    //
  }
}

export default {
  getters,
  state,
  mutations,
  actions,
  modules: {
    //
  }
}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-04-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 加菲的博客 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1.写在前面
  • 2.父子组件
    • 2.1 父组件→子组件
      • 父组件
      • 子组件
    • 2.2 子组件→父组件
      • 子组件
      • 父组件
    • 2.3 v-model
    • 3.兄弟组件
    • 4.bus
      • 4.1 定义总线bus
        • 4.2 全局引入总线bus
          • 4.3 使用bus
            • 4.3.1 定义事件方法
            • 4.3.2 取值
        • 5.Vuex
          • 5.1 引入Vuex
            • 5.2 Store
              • 5.3 state
                • 5.3.1 定义state
                • 5.3.2 取值
              • 5.4 getter
                • 5.4.1 定义getter
                • 5.4.2 取值
              • 5.5 mutation
                • 5.5.1 定义mutation
                • 5.5.2 调用mutation
                • 5.5.3 增加state值
              • 5.6 action
                • 5.6.1 定义action
                • 5.6.2 获取action
                • 5.6.3 触发action
              • 5.7 模块
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档