Vue3中props传参(多种数据类型传参方式)

在Vue3中,`props`接收的`type`类型有以下几种:

  1. String:字符串类型

  2. Number:数字类型

  3. Boolean:布尔类型

  4. Array:数组类型

  5. Object:对象类型

  6. Date:日期类型

  7. Function:函数类型

  8. Symbol:符号类型

  9. [Custom Types]:自定义类型

你也可以使用数组形式来表示多种类型的组合,

比如`[String, Number]`表示接收字符串或数字类型的值。

另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。

注意:以上是常见的`type`类型列表,你也可以自定义其它类型。

`props` 还有两个参数:

default: 默认值

required: 是否必传, true必传,false 非必传

开启必传时 若不传则警告[Vue warn]: Missing required prop: "xxx"

父组件代码(测试默认值):

<template>
  <div style="font-size: 14px">
    <h3>测试props传参常见的数据类型</h3>
    <Child :message="message" />
    <!--
        :count="count"
        :isActive="isActive"
        :list="list"
        :user="user"
        :date="date"
        :callback="callback
    -->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  onMounted,
  toRefs
} from 'vue'
import Child from './Child.vue'
// vue3.0语法
export default defineComponent({
  name: '父组件名',
  components: {
    Child,
  },
  setup() {
    // 在Vue3中,`props`接收的`type`类型有以下几种:
    // 1. String:字符串类型
    // 2. Number:数字类型
    // 3. Boolean:布尔类型
    // 4. Array:数组类型
    // 5. Object:对象类型
    // 6. Date:日期类型
    // 7. Function:函数类型
    // 8. Symbol:符号类型
    // 9. [Custom Types]:自定义类型
    // 你也可以使用数组形式来表示多种类型的组合,
    // 比如`[String, Number]`表示接收字符串或数字类型的值。
    // 另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。
    // 注意:以上是常见的`type`类型列表,你也可以自定义其它类型。
    const state = reactive({
      date: new Date(1998, 12, 31),
      message: 'Hello World',
      count: 666,
      isActive: true,
      list: [1, 2, 3],
      user: {
        name: '张三',
        age: 18,
      },
      callback: () => {
        console.log('父组件传入的callback执行了')
      },
    })

    onMounted(() => {
    //
    })

    return {
      ...toRefs(state),
    }
  },
})
</script>

子组件代码:

<template>
  <div style="font-size: 14px">
    <!-- 子组件内容 -->
    <p>message: {{ message }}</p>
    <p>count: {{ count }}</p>
    <p>isActive: {{ isActive }}</p>
    <p>list: {{ list }}</p>
    <p v-for="(item,index) in list" :key="index">{{ item }}</p>
    <p>date: {{ date }}</p>
    <p>user: {{ user }}</p>
    <button @click="callback">callback按钮(调用父组件函数)</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted } from 'vue'
// vue3.0语法
export default defineComponent({
  name: '子组件名',
  props: {
    message: {
      type: String, // type 类型
      required: true, // required 是否必传, true必传 若不传则警告[Vue warn]: Missing required prop: "message"
    },
    count: {
      type: Number,
      default: 0, // default 默认值
    },
    isActive: {
      type: Boolean,
      default: false,
    },
    list: {
      type: Array,
      default: () => [],
    },
    date: {
      type: Date,
      default: () => new Date(),
    },
    user: {
      type: Object,
      default: () => ({ name: 'John Doe', email: 'johndoe@mail.com' }),
    },
    callback: {
      type: Function,
      default: () => {},
    },
  },
  setup(props) {
    onMounted(() => {
      console.log('props', props)
    })
    return {
      //
    }
  },
})
</script>

页面数据显示效果(只传了必填项message):

可以看到,接收到的props只有message是父组件传来的值,而子组件显示的其它值都是定义在default里的默认值,点击callback按钮(调用父组件函数)也是没有任何反应的。

修改父组件代码(将各种数据类型传入):

<template>
  <div style="font-size: 14px">
    <h3>测试props传参常见的数据类型</h3>
    <Child
      :message="message"
      :count="count"
      :is-active="isActive"
      :list="list"
      :user="user"
      :date="date"
      :callback="callback"
    />
    <!-- 两种命名方式都可以
        :is-active="isActive"
        :isActive="isActive"
    -->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  onMounted,
  toRefs
} from 'vue'
import Child from './Child.vue'
// vue3.0语法
export default defineComponent({
  name: '父组件名',
  components: {
    Child,
  },
  setup() {
    // 在Vue3中,`props`接收的`type`类型有以下几种:
    // 1. String:字符串类型
    // 2. Number:数字类型
    // 3. Boolean:布尔类型
    // 4. Array:数组类型
    // 5. Object:对象类型
    // 6. Date:日期类型
    // 7. Function:函数类型
    // 8. Symbol:符号类型
    // 9. [Custom Types]:自定义类型
    // 你也可以使用数组形式来表示多种类型的组合,
    // 比如`[String, Number]`表示接收字符串或数字类型的值。
    // 另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。
    // 注意:以上是常见的`type`类型列表,你也可以自定义其它类型。
    const state = reactive({
      date: new Date(1998, 12, 31),
      message: 'Hello World',
      count: 666,
      isActive: true,
      list: [1, 2, 3],
      user: {
        name: '张三',
        age: 18,
      },
      callback: () => {
        console.log('父组件传入的callback执行了')
      },
    })

    onMounted(() => {
    //
    })

    return {
      ...toRefs(state),
    }
  },
})
</script>

页面数据显示效果(各种数据类型传入了):

可以看到数据将以父组件传入的值为准,default的值被覆盖。点击callback按钮(调用父组件函数)也执行了。

踩坑小案例:

案例:父组件的数据是从接口异步请求来的 ,而子组件是会先挂载的,如果子组件接受的值是从父组件的接口里取来的,想在子组件onMounted的时候拿到这个数据来发请求却没拿到。

修改代码(看下案例):

父组件代码

<template>
  <div style="font-size: 14px">
    <h3>测试props传参常见的数据类型</h3>
    <Child
      :id="id"
      :message="message"
      :count="count"
      :is-active="isActive"
      :list="list"
      :user="user"
      :date="date"
      :callback="callback"
    />
    <!-- 两种命名方式都可以
        :is-active="isActive"
        :isActive="isActive"
    -->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  onMounted,
  toRefs
} from 'vue'
import Child from './Child.vue'
// vue3.0语法
export default defineComponent({
  name: '父组件名',
  components: {
    Child,
  },
  setup() {
    // 在Vue3中,`props`接收的`type`类型有以下几种:
    // 1. String:字符串类型
    // 2. Number:数字类型
    // 3. Boolean:布尔类型
    // 4. Array:数组类型
    // 5. Object:对象类型
    // 6. Date:日期类型
    // 7. Function:函数类型
    // 8. Symbol:符号类型
    // 9. [Custom Types]:自定义类型
    // 你也可以使用数组形式来表示多种类型的组合,
    // 比如`[String, Number]`表示接收字符串或数字类型的值。
    // 另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。
    // 注意:以上是常见的`type`类型列表,你也可以自定义其它类型。
    const state = reactive({
      id: '',
      date: new Date(1998, 12, 31),
      message: '',
      count: 666,
      isActive: true,
      list: [1, 2, 3],
      user: {
        name: '张三',
        age: 18,
      },
      callback: () => {
        console.log('父组件传入的callback执行了')
      },
    })

    onMounted(() => {
      // 模拟一个接口请求
      setTimeout(() => {
        state.id = '父组件请求接口得来的id'
      }, 3000)
    })

    return {
      ...toRefs(state),
    }
  },
})
</script>

子组件代码:

<template>
  <div style="font-size: 14px">
    <!-- 子组件内容 -->
    <p>message: {{ message }}</p>
    <p>count: {{ count }}</p>
    <p>isActive: {{ isActive }}</p>
    <p>list: {{ list }}</p>
    <p v-for="(item,index) in list" :key="index">{{ item }}</p>
    <p>date: {{ date }}</p>
    <p>user: {{ user }}</p>
    <button @click="callback">callback按钮(调用父组件函数)</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted } from 'vue'
// vue3.0语法
export default defineComponent({
  name: '子组件名',
  props: {
    id: {
      type: String, // type 类型
      required: true, // required 是否必传, true必传 若不传则警告[Vue warn]: Missing required prop: "message"
    },
    message: {
      type: String, // type 类型
      required: true, // required 是否必传, true必传 若不传则警告[Vue warn]: Missing required prop: "message"
    },
    count: {
      type: Number,
      default: 0, // default 默认值
    },
    isActive: {
      type: Boolean,
      default: false,
    },
    list: {
      type: Array,
      default: () => [],
    },
    date: {
      type: Date,
      default: () => new Date(),
    },
    user: {
      type: Object,
      default: () => ({ name: 'John Doe', email: 'johndoe@mail.com' }),
    },
    callback: {
      type: Function,
      default: () => {},
    },
  },
  setup(props) {
    onMounted(() => {
      console.log('props', props)
      console.log('props.id:', props.id)
      // 想拿到id后请求接口
      // axios.get('props.id').then(res => {
      //   console.log(res)
      // })
    })
    return {
      //
    }
  },
})
</script>

案例显示效果(取不到id):

父组件请求接口的数据最终会在子组件更新,但是想在onMounted里使用却是拿不到的,因为接口还没请求完成,没拿到该数据,我们来尝试解决这个问题。

解决方案1(v-if):

修改父组件代码:

<template>
  <div style="font-size: 14px">
    <h3>测试props传参常见的数据类型</h3>
    <Child
      v-if="id"
      :id="id"
      :message="message"
      :count="count"
      :is-active="isActive"
      :list="list"
      :user="user"
      :date="date"
      :callback="callback"
    />
    <!-- 两种命名方式都可以
        :is-active="isActive"
        :isActive="isActive"
    -->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  onMounted,
  toRefs
} from 'vue'
import Child from './Child.vue'
// vue3.0语法
export default defineComponent({
  name: '父组件名',
  components: {
    Child,
  },
  setup() {
    // 在Vue3中,`props`接收的`type`类型有以下几种:
    // 1. String:字符串类型
    // 2. Number:数字类型
    // 3. Boolean:布尔类型
    // 4. Array:数组类型
    // 5. Object:对象类型
    // 6. Date:日期类型
    // 7. Function:函数类型
    // 8. Symbol:符号类型
    // 9. [Custom Types]:自定义类型
    // 你也可以使用数组形式来表示多种类型的组合,
    // 比如`[String, Number]`表示接收字符串或数字类型的值。
    // 另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。
    // 注意:以上是常见的`type`类型列表,你也可以自定义其它类型。
    const state = reactive({
      id: '',
      date: new Date(1998, 12, 31),
      message: '',
      count: 666,
      isActive: true,
      list: [1, 2, 3],
      user: {
        name: '张三',
        age: 18,
      },
      callback: () => {
        console.log('父组件传入的callback执行了')
      },
    })

    onMounted(() => {
      // 模拟一个接口请求
      setTimeout(() => {
        state.id = '父组件请求接口得来的id'
      }, 3000)
    })

    return {
      ...toRefs(state),
    }
  },
})
</script>

解决方案1(v-if)页面效果

在使用子组件的标签上加上<Child v-if="id"/>,没有拿到id时子组件并不会渲染,当然接口如果过慢的话子组件也会渲染更慢。

解决方案2(父组件不加v-if,子组件用watchEffect):

父组件代码:

<template>
  <div style="font-size: 14px">
    <h3>测试props传参常见的数据类型</h3>
    <Child
      :id="id"
      :message="message"
      :count="count"
      :is-active="isActive"
      :list="list"
      :user="user"
      :date="date"
      :callback="callback"
    />
    <!-- 两种命名方式都可以
        :is-active="isActive"
        :isActive="isActive"
    -->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  reactive,
  onMounted,
  toRefs
} from 'vue'
import Child from './Child.vue'
// vue3.0语法
export default defineComponent({
  name: '父组件名',
  components: {
    Child,
  },
  setup() {
    // 在Vue3中,`props`接收的`type`类型有以下几种:
    // 1. String:字符串类型
    // 2. Number:数字类型
    // 3. Boolean:布尔类型
    // 4. Array:数组类型
    // 5. Object:对象类型
    // 6. Date:日期类型
    // 7. Function:函数类型
    // 8. Symbol:符号类型
    // 9. [Custom Types]:自定义类型
    // 你也可以使用数组形式来表示多种类型的组合,
    // 比如`[String, Number]`表示接收字符串或数字类型的值。
    // 另外,你还可以使用`null`或`undefined`来表示接收任意类型的值。
    // 注意:以上是常见的`type`类型列表,你也可以自定义其它类型。
    const state = reactive({
      id: '',
      date: new Date(1998, 12, 31),
      message: '',
      count: 666,
      isActive: true,
      list: [1, 2, 3],
      user: {
        name: '张三',
        age: 18,
      },
      callback: () => {
        console.log('父组件传入的callback执行了')
      },
    })

    onMounted(() => {
      // 模拟一个接口请求
      setTimeout(() => {
        state.id = '父组件请求接口得来的id'
      }, 3000)
    })

    return {
      ...toRefs(state),
    }
  },
})
</script>

子组件代码

<template>
  <div style="font-size: 14px">
    <!-- 子组件内容 -->
    <p>message: {{ message }}</p>
    <p>count: {{ count }}</p>
    <p>isActive: {{ isActive }}</p>
    <p>list: {{ list }}</p>
    <p v-for="(item,index) in list" :key="index">{{ item }}</p>
    <p>date: {{ date }}</p>
    <p>user: {{ user }}</p>
    <button @click="callback">callback按钮(调用父组件函数)</button>
  </div>
</template>

<script lang="ts">
import { defineComponent, onMounted, watchEffect } from 'vue'
// vue3.0语法
export default defineComponent({
  name: '子组件名',
  props: {
    id: {
      type: String, // type 类型
      required: true, // required 是否必传, true必传 若不传则警告[Vue warn]: Missing required prop: "message"
    },
    message: {
      type: String, // type 类型
      required: true, // required 是否必传, true必传 若不传则警告[Vue warn]: Missing required prop: "message"
    },
    count: {
      type: Number,
      default: 0, // default 默认值
    },
    isActive: {
      type: Boolean,
      default: false,
    },
    list: {
      type: Array,
      default: () => [],
    },
    date: {
      type: Date,
      default: () => new Date(),
    },
    user: {
      type: Object,
      default: () => ({ name: 'John Doe', email: 'johndoe@mail.com' }),
    },
    callback: {
      type: Function,
      default: () => {},
    },
  },
  setup(props) {
    onMounted(() => {
      console.log('onMounted props', props)
      console.log('onMounted props.id:', props.id)
      // 想拿到id后请求接口
      // axios.get('props.id').then(res => {
      //   console.log(res)
      // })
    })
    watchEffect(() => {
      console.log('watchEffect', props.id)
      if (props.id) {
        // 想拿到id后请求接口
        // axios.get('props.id').then(res => {
        //   console.log(res)
        // })
      }
    })
    return {
      //
    }
  },
})
</script>

解决方案2watchEffect的页面显示效果:

可以看到子组件的页面依然会先挂载渲染,onMounted虽然拿不到值,但是可以在watchEffect里检测到id有值了再做请求就行了。当然有其它的解决方案也欢迎评论区留言交流。

相关推荐
Watermelo6178 分钟前
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
开发语言·前端·javascript·算法·数据挖掘·数据分析·ecmascript
m0_7482489410 分钟前
HTML5系列(11)-- Web 无障碍开发指南
前端·html·html5
m0_7482356121 分钟前
从零开始学前端之HTML(三)
前端·html
一个处女座的程序猿O(∩_∩)O2 小时前
小型 Vue 项目,该不该用 Pinia 、Vuex呢?
前端·javascript·vue.js
hackeroink5 小时前
【2024版】最新推荐好用的XSS漏洞扫描利用工具_xss扫描工具
前端·xss
迷雾漫步者7 小时前
Flutter组件————FloatingActionButton
前端·flutter·dart
向前看-7 小时前
验证码机制
前端·后端
燃先生._.8 小时前
Day-03 Vue(生命周期、生命周期钩子八个函数、工程化开发和脚手架、组件化开发、根组件、局部注册和全局注册的步骤)
前端·javascript·vue.js
高山我梦口香糖9 小时前
[react]searchParams转普通对象
开发语言·前端·javascript