Vue3---(6)Props

6 阅读5分钟

目录

Props声明

defineProps()

 props选项

 响应式Props解构

默认语法声明props默认值

将解构的 props 传递到函数中

Props的传递

格式

 静态props

动态props

一个对象绑定多个prop

 使用

单项数据流

动态prop

修改prop的场景处理

prop用于初始值

prop进一步处理

 面试重点

1. ​为什么不要直接修改 Props?

 2. ​如何传递复杂对象?

3. ​Props 的响应性原理

 4. ​Props 和 Emits 的关系


Props声明

defineProps()

在<script setup> 的单文件组件中使用defineProps()声明

<script setup>
const props = defineProps(['test'])

console.log(props.test)
</script>
//对象形式
defineProps({
  test: String,
  test2: Number
})

 props选项

没有使用script setup> 的单文件组件时,使用props选项声明

export default {
  props: ['test'],
  setup(props) {
    // setup() 接收 props 作为第一个参数
    console.log(props.test)
  }
}
// 对象形式
export default {
  props: {
    test: String,
    test2: Number
  }
}

 响应式Props解构

Vue 的响应系统基于属性访问跟踪状态的使用情况。例如,在计算属性或侦听器中访问 props.foo 时,foo 属性将被跟踪为依赖项。

默认语法声明props默认值

const { foo = 'hello' } = defineProps<{ foo?: string }>()

将解构的 props 传递到函数中

const { test} = defineProps(['test'])
//侦听解构的prop
watch(() => foo, /* ... */)

Props的传递

格式

推荐使用kebab-case形式,更贴近HTML的书写格式,任何类型的值都可以作为props的值传递(Number,Boolean,Array,Object,String...)

<MyComponent test-message="hello" />

 静态props

<MyComponent test-message="hello" />

动态props

<MyComponent :test-message="test" />

let test = ref('hello word')

一个对象绑定多个prop

将一个对象的所有属性都当作 props 传入,你可可以使用没有参数的v-bind,即只使用 v-bind 而非 :prop-name

const post = {
  id: 1,
  title: 'My Journey with Vue'
}

<BlogPost v-bind="post" />


等价于
<BlogPost :id="post.id" :title="post.title" />

 使用

单项数据流

  • 禁止直接修改 Props
  • 正确做法:通过 emit 事件让父组件修改

所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,所以不应该在子组件中去更改一个 prop

动态prop

<ChildComponent :[dynamicPropName]="value" />

修改prop的场景处理

prop用于初始值

prop 被用于传入初始值;而子组件想在之后将其作为一个局部数据属性

const props = defineProps(['test'])

// 将 props.test作为初始值
// 像下面这样做就使 prop 和后续更新无关了
const test1= ref(props.test)

prop进一步处理

需要对传入的 prop 值做进一步的转换。在这种情况中,最好是基于该 prop 值定义一个计算属性

const props = defineProps(['test'])

// 该 prop 变更时计算属性也会自动更新
const test1= computed(() => props.test.trim().toLowerCase())

 面试重点

1. ​为什么不要直接修改 Props?

  • 破坏单向数据流,导致组件状态难以追踪
  • 父组件更新时,子组件的本地修改会被覆盖

 2. ​如何传递复杂对象?

// 传递整个对象
<UserProfile :user="userData" />

// 解构传递(保持响应性需要 toRefs)
<UserProfile v-bind="userData" />

3. ​Props 的响应性原理

  • Vue3 使用 Proxy 实现响应式
  • 如果传递非响应式数据,子组件不会自动更新
// 错误示例:直接传递字面量对象
<UserProfile :user="{ id: 1, name: 'John' }" />

// 正确做法:使用 reactive/ref
const user = reactive({ id: 1, name: 'John' })

 4. ​Props 和 Emits 的关系

  • Props 向下传递数据
  • Emits 向上传递事件
  • 组合使用实现组件通信