3-3-01-Vue.js 组件状态管理

Vue.js 组件状态管理

Vue 中最核心的两个功能分别是数据驱动和组件化。组件化可以提高开发效率和代码的可维护性。

new Vue({
  // state
  data () {
    return {
      count: 0
    }
  },
  //view
  template: `
    <div>{{ count }}</div>
  `,
  // actions
  methods: {
    increment () {
      this.count++
    }
  }
})

状态管理

  • state, 数据驱动的数据源
  • view,以声明方式将 state 映射到视图
  • actions,响应在 view 上的用户输入导致的状态变化

在这里插入图片描述

组件间通信方式

  • 父组件给子组件传值
  • 子组件给父组件传值
  • 不相关组件之间传值

在这里插入图片描述

父组件给子组件传值

  • 子组件通过 props 接收数据
  • 父组件中给子组件通过相应属性传值
<child title="hello"></child>

<script>
import child from @/component/child.vue
export default {
  component: {
    child
  }
}
</script>
export default {
  // props: ['title']
  props: {
    title: String
  }
}

子组件给父组件传值

<template>
  <div>
    <h1 :style="{ fontSize: hFontSize + 'em' }">Event Up Parent</h1>

    这里的文字不需要变化

    <child :fontSize="hFontSize" @enlargeText="enlargeText"></child>
    <child :fontSize="hFontSize" @enlargeText="enlargeText"></child>
    <child :fontSize="hFontSize" @enlargeText="hFontSize += $event"></child>

  </div>
</template>

<script>
import child from './02-Child'
export default {
  components: {
    child
  },
  data () {
    return {
      hFontSize: 1
    }
  },
  methods: {
    enlargeText (size) {
      this.hFontSize += size
      console.log(this.hFontSize)
    }
  }
}
</script>
<template>
  <div>
    <h1 :style="{ fontSize: fontSize + 'em' }">Event Up Child</h1>
    <button @click="handler">文字增大</button>
  </div>
</template>

<script>
export default {
  props: {
    fontSize: Number
  },
  methods: {
    handler () {
      this.$emit('enlargeText', 0.1)
    }
  }
}
</script>

不相关组件传值

需要创建一个 Vue 实例作为事件总线或者事件中心

import Vue from 'vue'
export default new Vue()
<template>
  <div>
    <h1>Event Bus Sibling01</h1>
    <div class="number" @click="sub">-</div>
    <input type="text" style="width:30px; text-align:center" :value="value">
    <div class="number" @click="add">+</div>
  </div>
</template>

<script>
import eventbus from './eventbus'

export default {
  props: {
    num: Number
  },
  created () {
    this.value = this.num
  },
  data () {
    return {
      value: -1
    }
  },
  methods: {
    sub () {
      if (this.value > 1) {
        this.value--
        eventbus.$emit('numchange', this.value)
      }
    },
    add () {
      this.value++
      eventbus.$emit('numchange', this.value)
    }
  }
}
</script>

<style>
.number {
  display: inline-block;
  cursor: pointer;
  width: 20px;
  text-align: center;
}
</style>
<template>
  <div>
    <h1>Event Bus Sibling02</h1>
    <div>{{ msg }}</div>
  </div>
</template>

<script>
import eventbus from './eventbus'

export default {
  data () {
    return {
      msg: ''
    }
  },
  created () {
    eventbus.$on('numchange', value => {
      this.msg = `您选择了${value}件商品`
    })
  }
}
</script>

其他常见方式

  • $root
  • $parent
  • $children
  • refs

ref 的作用

  • 在普通的 html 标签上使用 ref ,获取到的是 DOM
  • 在组件上使用 ref ,获取到的是组件实例
<template>
  <div>
    <h1>ref Parent</h1>
    <child ref='c'></child>
  </div>
</template>

<script>
import child from './04-Child'
export default {
  components: {
    child
  },
  mounted () {
    this.$refs.c.focus()
    this.$refs.c.value = 'hello input'
  }
}
</script>

<template>
  <div>
    <h1>ref Child</h1>
    <input ref="input" type="text" v-model="value">
  </div>
</template>

<script>
export default {
  data () {
    return {
      value: ''
    }
  },
  methods: {
    focus () {
      this.$refs.input.focus()
    }
  }
}
</script>

ref 传值这种方式要慎用!容易造成状态管理混乱

简易的状态管理方案

如果多个组件之间需要共享状态或者说数据,使用前面演示的方式,虽然都可以实现,但是比较麻烦,而且多个组件之间互相传值,很难跟踪到数据的变化,容易造成数据的混乱,出现问题难以定位。

  • 问题
    • 多个视图依赖同一个状态
    • 来自不同视图的行为需要变更同一状态

为了解决这些问题,可以把不同组件之间依赖的共同的状态抽取出来,存储到一个全局对象中,并且将来使用的时候保证他是响应式的。这个对象创建之后,任何组件都可以获取或修改全局对象中的状态。

// store
export default {
  debug: true,
  state: {
    user: {
      name: 'xiaodong',
      age: 18,
      sex: '男'
    }
  },
  setUserNameAction (name) {
    if (this.debug) {
      console.log('setUserNameAction triggered:', name)
    }
    this.state.user.name = name
  }
}
<!-- ComponentA -->
<template>
  <div>
    <h1>ComponentA</h1>
    user name: {{ sharedState.user.name }}
    <button @click="change">Change Info</button>
  </div>
</template>

<script>
import store from './store'
export default {
  data () {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  methods: {
    change () {
      store.setUserNameAction('componentA')
    }
  }
}
</script>
<!-- ComponentB -->
<template>
  <div>
    <h1>ComponentB</h1>
    user name: {{ sharedState.user.name }}
    <button @click="change">Change Info</button>
  </div>
</template>

<script>
import store from './store'
export default {
  data () {
    return {
      privateState: {},
      sharedState: store.state
    }
  },
  methods: {
    change () {
      store.setUserNameAction('componentB')
    }
  }
}
</script>
©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页