🎉 Vue2 Props 属性传递机制详解
This commit is contained in:
parent
85c1ae88d5
commit
926cb154cb
|
@ -1,14 +1,17 @@
|
||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<Demo1 />
|
<Demo1 />
|
||||||
|
<hr />
|
||||||
|
<Demo2 />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Demo1 from "@/views/demo1/index.vue";
|
import Demo1 from "@/views/demo1/index.vue";
|
||||||
|
import Demo2 from "@/views/demo2/index.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
components: { Demo1 },
|
components: { Demo1, Demo2 },
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
import SchoolInfo from "@/views/demo1/components/SchoolInfo.vue";
|
import SchoolInfo from "@/views/demo1/components/SchoolInfo.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "Demo-1",
|
||||||
components: { SchoolInfo },
|
components: { SchoolInfo },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -0,0 +1,192 @@
|
||||||
|
# Vue2 Props 属性传递机制详解
|
||||||
|
|
||||||
|
## 一、Props 的基本概念
|
||||||
|
|
||||||
|
Props 是 Vue 组件之间数据传递的主要方式,允许父组件向子组件传递数据。它具有明确的单向数据流特性(父组件 → 子组件)。
|
||||||
|
|
||||||
|
## 二、三种 Props 声明方式对比
|
||||||
|
|
||||||
|
### 1. 数组式声明(简单接收)
|
||||||
|
```javascript
|
||||||
|
props: ["name", "sex", "age"]
|
||||||
|
```
|
||||||
|
- **特点**:仅指定属性名
|
||||||
|
- **适用场景**:快速原型开发
|
||||||
|
- **限制**:无类型检查,无验证逻辑
|
||||||
|
|
||||||
|
### 2. 对象式声明(类型检查)
|
||||||
|
```javascript
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
sex: String,
|
||||||
|
age: Number
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **特点**:添加基础类型检查
|
||||||
|
- **优势**:在开发模式下会发出警告
|
||||||
|
- **不足**:无法设置必填/默认值
|
||||||
|
|
||||||
|
### 3. 配置对象声明(完整配置)
|
||||||
|
```javascript
|
||||||
|
props: {
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
required: true // 必须传入
|
||||||
|
},
|
||||||
|
sex: {
|
||||||
|
type: String,
|
||||||
|
default: "男🚹" // 默认值
|
||||||
|
},
|
||||||
|
age: {
|
||||||
|
type: Number,
|
||||||
|
required: true,
|
||||||
|
validator: value => value >= 6 && value <= 60 // 自定义验证
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- **完整功能**:
|
||||||
|
- 类型检查 (`type`)
|
||||||
|
- 必填标记 (`required`)
|
||||||
|
- 默认值 (`default`)
|
||||||
|
- 自定义验证 (`validator`)
|
||||||
|
|
||||||
|
## 三、核心特性详解
|
||||||
|
|
||||||
|
### 1. 类型系统支持
|
||||||
|
Vue 支持以下原生构造函数作为类型:
|
||||||
|
- `String`
|
||||||
|
- `Number`
|
||||||
|
- `Boolean`
|
||||||
|
- `Array`
|
||||||
|
- `Object`
|
||||||
|
- `Date`
|
||||||
|
- `Function`
|
||||||
|
- `Symbol`
|
||||||
|
|
||||||
|
也可以使用自定义构造函数:
|
||||||
|
```javascript
|
||||||
|
props: {
|
||||||
|
author: Person // 检查是否是Person的实例
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 默认值函数
|
||||||
|
当默认值是对象或数组时,必须使用工厂函数:
|
||||||
|
```javascript
|
||||||
|
props: {
|
||||||
|
config: {
|
||||||
|
type: Object,
|
||||||
|
default: () => ({ pageSize: 10 })
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 自定义验证器
|
||||||
|
```javascript
|
||||||
|
age: {
|
||||||
|
type: Number,
|
||||||
|
validator: value => {
|
||||||
|
return value >= 6 && value <= 60;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 四、最佳实践
|
||||||
|
|
||||||
|
### 1. 命名规范
|
||||||
|
- **Prop 名称**:使用 camelCase(JavaScript)
|
||||||
|
- **HTML 特性**:使用 kebab-case(DOM)
|
||||||
|
```html
|
||||||
|
<!-- 父组件模板 -->
|
||||||
|
<child-component user-name="张三"></child-component>
|
||||||
|
|
||||||
|
<!-- 子组件声明 -->
|
||||||
|
props: ['userName']
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 单向数据流原则
|
||||||
|
- **禁止**子组件直接修改 prop
|
||||||
|
- **正确做法**:
|
||||||
|
```javascript
|
||||||
|
// 子组件中使用data接收
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
localAge: this.age
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 或使用计算属性
|
||||||
|
computed: {
|
||||||
|
normalizedAge() {
|
||||||
|
return this.age + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 类型定义技巧
|
||||||
|
```javascript
|
||||||
|
// 使用PropType增强类型提示
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
|
||||||
|
props: {
|
||||||
|
user: {
|
||||||
|
type: Object as PropType<User>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 五、高级用法
|
||||||
|
|
||||||
|
### 1. 非Prop特性
|
||||||
|
未在props中声明的特性会自动绑定到组件的根元素上:
|
||||||
|
```html
|
||||||
|
<my-component data-test="123" class="extra"></my-component>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. 同步修饰符
|
||||||
|
`.sync` 修饰符实现双向绑定(Vue 2.3+):
|
||||||
|
```html
|
||||||
|
<!-- 父组件 -->
|
||||||
|
<child :title.sync="pageTitle"></child>
|
||||||
|
|
||||||
|
<!-- 等价于 -->
|
||||||
|
<child :title="pageTitle" @update:title="pageTitle = $event"></child>
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. v-model 整合
|
||||||
|
自定义组件实现 v-model:
|
||||||
|
```javascript
|
||||||
|
props: ['value'],
|
||||||
|
methods: {
|
||||||
|
updateValue(newVal) {
|
||||||
|
this.$emit('input', newVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 六、常见问题
|
||||||
|
|
||||||
|
1. **Prop未更新问题**:
|
||||||
|
- 确保父组件数据是响应式的
|
||||||
|
- 对象/数组需要确保是新的引用
|
||||||
|
|
||||||
|
2. **类型检查失败**:
|
||||||
|
- 开发模式下会输出警告
|
||||||
|
- 生产环境会静默失败
|
||||||
|
|
||||||
|
3. **性能优化**:
|
||||||
|
- 避免传递大型对象
|
||||||
|
- 必要时使用 `v-once` 冻结静态内容
|
||||||
|
|
||||||
|
## 七、与 Vue3 的区别
|
||||||
|
|
||||||
|
| 特性 | Vue2 | Vue3 |
|
||||||
|
| ---------- | ------------ | ----------------------- |
|
||||||
|
| 默认值函数 | 必须使用函数 | 可以直接赋值 |
|
||||||
|
| 类型定义 | PropType | 原生TypeScript支持 |
|
||||||
|
| 废弃语法 | .sync | 移除,用v-model参数替代 |
|
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>学生姓名:{{ name }}</h2>
|
||||||
|
<h2>学习性别:{{ sex }}</h2>
|
||||||
|
<h2>学生年龄:{{ age + 1 }}</h2>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "SchoolInfo",
|
||||||
|
// 第一种传入方法---简单接受
|
||||||
|
// props: ["name", "sex", "age"],
|
||||||
|
|
||||||
|
// 第二种传入方法---接受同时对数据进行限制
|
||||||
|
// props: {
|
||||||
|
// name: String,
|
||||||
|
// sex: String,
|
||||||
|
// age: Number,
|
||||||
|
// },
|
||||||
|
props: {
|
||||||
|
name: { type: String, required: true /* 必须要传入的 */ },
|
||||||
|
sex: { type: String, default: "男🚹" /* 给一个默认值 */ },
|
||||||
|
age: { type: Number, required: true },
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
|
@ -0,0 +1,20 @@
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<SchoolInfo name="Bunny1" sex="女🚺" :age="16" />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<SchoolInfo name="Bunny2" sex="女🚺" :age="16" />
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<SchoolInfo name="Bunny3" :age="16" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import SchoolInfo from "./components/SchoolInfo.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: "Demo-2",
|
||||||
|
components: { SchoolInfo },
|
||||||
|
};
|
||||||
|
</script>
|
Loading…
Reference in New Issue