组件传值

394 阅读2分钟

1. 父传子

// 子组件代码:
// 子组件中使用props属性接受父组件传来的值,可以直接在template中使用
// props可以直接在setup中使用吗?有什么问题?如何变成响应式
// 可以直接使用;setup可接受props,context,其中由于props是响应式数据,不能直接解构赋值(props 传递过来的值不能直接使用的时候,可以通过toRefs进行处理);context不是响应式数据,可以直接解构赋值
// 解构赋值会失去响应式,使用toRefs来转换为响应式 
<template>
  <div>
    <h2>{{message}}</h2>
  </div>
</template>

<script>
import {
  defineComponent
} from 'vue'

export default defineComponent({
  name: 'Children',
  components: {},
  props: {
    message: {
      type: String,
      default: ''
    },
    toData: {
       type: Object,
       default: () => {
           return {}
       }
  },
  setup (props, {attrs}) {
    // toRef 可以把props接受的对象中的value 转换为 响应式
    const useData = toRef(props.toData, 'a')
    console.log('a', useData.value)  // 11
    useData.value++
    console.log('is a ', getA.value) // 12
    // toRefs 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 [`ref`](https://v3.cn.vuejs.org/api/refs-api.html#ref)
    const { toData } = toRefs(props)
    console.log('toData', toData.value)  // {a: 12, b: '22', c: '33'}
    return {
    }
  }
})
</script>

// 父组件代码:
// 父组件传值的时候使用 v-bind 绑定子组件中预留的变量名
// 当父组件的传值是数组或者对象时,子组件中不仅能够直接修改,还不会报错,在子组件中改变这个对象或数组本身将会影响到父组件的状态。
<template>
  <div class="Parent">
    <h1>This is an about page</h1>
    <Children :message="messText" :toData="currentData"></Children>
  </div>
</template>
<script>
import Children from '@/components/Children.vue'
export default ({
  name: 'Parent',
  components: {
    Children
  },
  setup () {
    const messText = 'this is children'
    const currentData = reactive({
        a: '11',
        b: '22',
        c: '33'
    })
    return {
      messText,
      currentData
    }
  }
})
</script>

2. 子传父

// 子组件代码:
// 使用$emit触发自定义事件;$emit(自定义事件,需要传递的数据)
<template>
  <div>
    <button @click="setData">传递到父组件</button>
  </div>
</template>

<script>
import {
  defineComponent,
  getCurrentInstance
} from 'vue'

export default defineComponent({
  name: 'Children',
  components: {},
  props: {
  },
  // 声明自定义事件
  emits: ['getData', 'msg'],
  setup (props, {emit}) {
    // proxy相当于 this
    const { proxy } = getCurrentInstance()
    // click事件
    const setData = () => {
        // 触发定义事件
        // this.$emit()
        // proxy.$emit('getData', '想要传递的数据')
        emit('getData', '想要传递的数据')
    }
    return {
      setData
    }
  }
})
</script>

// 父组件代码:
// 使用自定义事件
<template>
  <div class="Parent">
    <Children @getData="isGetData"></Children>
  </div>
</template>

<script>
import Children from '@/views/Children.vue'
export default {
  name: 'Parent',
  components: {
    Children
  },
  setup () {
    const isGetData = (data) => {
      console.log('isGetData', data)
    }
    return {
      isGetData
    }
  }
}
</script>

3.子组件修改父组件传来的值

  • 子父组件最常用的通信方式就是通过props进行数据传递,props值只能在父组件中更新并传递给子组件。props是只读的,不能修改,这样做是为了保证数据单向流通。但想要在子组件中修改父组件中的值,该如何做? 子组件接受父组件传来的message并且想要修改,可以通过$emit触发自定义事件来修改该值
// 子组件
<template>
  <div>
    TestSyncChild-------{{ message }}
    <my-button @click="handleClick">
      修改
    </my-button>
  </div>
</template>

<script>
    props: {
        message: {
          type: String,
          default: ''
        }
      },
      emits: ['update:message'],
      setup () {

        const { proxy } = getCurrentInstance()

        const handleClick = () => {
          proxy.$emit('update:message', '12321')
          console.log('emit', proxy)
        }

        return {
          handleClick
        }
      }
  </script>
  
  
// 父组件
  <div>
    <TestSyncChild
      :message="message"
      @update:message="modifyData"
    />
  </div>
  import TestSyncChild from '@/modules/Test/testSyncChild.vue'
  
  <script>
      export default defineComponent({
      name: 'Xx',
      components: {
        TestSyncChild
      },
      props: {},
      setup () {
      // Vuex store
        const store = useStore()

        // this
        const { ctx } = getCurrentInstance()
        console.log(ctx)

        const message = ref('000')
        console.log('mes', message)
        const modifyData = (data) => {
          message.value = data
        }

        return {
          message,
          modifyData
        }
      }
    })
</script>
  • 可以通过sync修饰符简写 (2.x写法) sync 修饰符的作用就是实现父子组件数据的双向绑定,简化功能逻辑代码
    sync 修饰符可以实现多个参数的数据双向绑定
<TestSyncChild
      :message="message"
      @update:message="modifyData"
/>

// 使用 `.sync` 修饰符来缩写
<TestSyncChild
     :message.sync="message"
/>

// 实现多个参数的数据双向绑定
<info :a.sync="value1" :b.sync="value2" :c.sync="value2" :d.sync="value2"></info>
// 简写:
<info v-bind.sync="obj"></info>
<script> 
    data() { 
        obj: {a: '', b: '', c: '', d: ''} 
    }  
</script>
  • 通过向v-model 传递一个参数 (3.x写法) 自定义组件上的 v-model 相当于传递了 message prop 并接收抛出的 update:message 事件
    现在可以在同一个组件上使用多个 v-model 绑定
    <TestSyncChild
      v-model:message="message"
    />