Learning Vue 读书笔记 Chapter 4

4.1 Vue中的嵌套组件和数据流

我们将嵌套的组件称为子组件,而包含它们的组件则称为它们的父组件。

父组件可以通过 props向子组件传递数据,而子组件则可以通过自定义事件(emits)向父组件发送事件。

4.1.1 使用Props向子组件传递数据

在 Vue 组件中,props 字段以对象或数组的形式存在,它包含了该组件可从父组件接收的所有可用数据属性。props 对象的每个属性都对应着目标组件的一个 prop(属性)。若要使组件能够接收父组件传递的数据,您需要在组件的选项对象中声明 props 字段。

在一个子组件中定义props

js 复制代码
export default { 
	name: 'ChildComponent', 
	props: { 
		name: String 
	} 
}

将动态变量作为属性传递给子组件。每当children0的值发生变化时,Vue也会更新ChildComponent中的name属性,如果需要,子组件将重新渲染其内容。

js 复制代码
<template>
  <ChildComponent :name="children[0]" />
</template>

<script lang="ts">
import ChildComponent from './ChildComponent.vue';

export default {
  data() {
    return {
      children: ['Red Sweater', 'Blue T-Shirt', 'Green Hat'],
    };
  },
};
</script>

如果name属性不是字符串类型,需要使用v-bind属性(或:)来向子组件传递静态数据,例如:对于布尔类型使用 :name="true",对于数组类型使用 :name="['hello', 'world']"。

使用v-bind(不是:)来传递整个对象,并将其属性绑定到相关子组件的props上:

js 复制代码
<template> 
   <ProductComp v-bind="product" /> 
</template>
4.1.2 声明带验证和默认值的Prop类型

将prop定义为带有默认值的字符串

js 复制代码
export default {
  name: 'ChildComponent',
  props: {
    name: {
      type: String,
      default: 'Child component'
    }
  }
}
4.1.3 使用自定义类型检查声明Props

直接将pizza prop 的类型声明为Pizza类

js 复制代码
class Pizza {
  title: string;
  description: string;
  image: string;
  quantity: number;
  price: number;

  constructor(
    title: string,
    description: string,
    image: string,
    quantity: number,
    price: number
  ) {
    this.title = title;
    this.description = description;
    this.image = image;
    this.quantity = quantity;
    this.price = price;
  }
}

export default {
  name: 'PizzaComponent',
  props: {
    pizza: {
      type: Pizza,
      required: true
    }
  }
}

或者,你可以使用TypeScript的接口或类型来定义你的自定义类型,而不是使用类。然而,在这种情况下,你必须使用vue包中的PropType类型,并按照以下语法,将声明的类型映射到目标prop:

js 复制代码
type: Object as PropType<Your-Custom-Type>
js 复制代码
import type { PropType } from 'vue';

interface Pizza {
  title: string;
  description: string;
  image: string;
  quantity: number;
  price: number;
}

export default {
  name: 'PizzaComponent',
  props: {
    pizza: {
      type: Object as PropType<Pizza>,
      required: true,
    },
  },
};
4.1.4 使用defineProps()和withDefaults() 定义Props

使用defineProps和

js 复制代码
<script setup>
import { defineProps } from 'vue';

const props = defineProps({
  name: {
    type: String,
    default: "Hello from the child component.",
  },
});
</script>

使用defineProps()和TypeScript 类型声明Props (?代表该type中name属性可有可无)

js 复制代码
<script setup>
import { defineProps } from 'vue';

type ChildProps = {
  name?: string;
};

const props = defineProps<ChildProps>();
</script>

使用defineProps() 和withDefaults()声明Props

js 复制代码
import { defineProps, withDefaults } from 'vue';

type ChildProps = {
  name?: string;
};

const props = withDefaults(defineProps<ChildProps>(), {
  name: 'Hello from the child component.',
});

4.2 使用自定义事件进行组件交流

Vue将传递给子组件的props数据视为只读的原始数据。单向数据流确保只有父组件可以更新数据属性。我们通常希望更新特定的数据属性并将其与父组件同步。为此,我们使用组件选项中的emits字段来声明自定义事件。

以ToDoList组件为例。这个ToDoList将使用ToDoItem作为其子组件来渲染任务列表,代码如下:

ToDoList Component

js 复制代码
<template>
  <ul style="list-style: none;">
    <li v-for="task in tasks" :key="task.id">
      <ToDoItem :task="task"  
      @task-completed-toggle="onTaskCompleted"/>
    </li>
  </ul>
</template>

<script lang="ts">
import { defineComponent } from 'vue';
import ToDoItem from './ToDoItem.vue';
import type { Task } from './ToDoItem';

export default defineComponent({
  name: 'ToDoList',
  components: {
    ToDoItem,
  },
  data() {
    return {
      tasks: [
        { id: 1, title: 'Learn Vue', completed: false },
        { id: 2, title: 'Learn TypeScript', completed: false },
        { id: 3, title: 'Learn Vite', completed: false },
      ] as Task[],
    };
  },
  methods: {
  onTaskCompleted(payload: { id: number; completed: boolean }) {
    const index = this.tasks.findIndex(t => t.id === payload.id);
    if (index < 0) {
      return;
    }
    this.tasks[index].completed = payload.completed;
  }
}

});
</script>

ToDoItem Componet

js 复制代码
<template>
  <div>
    <input type="checkbox" 
    :checked="task.completed"  
    @change="onTaskCompleted"/>
    <span>{{ task.title }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, type PropType } from 'vue';

export interface Task {
  id: number;
  title: string;
  completed: boolean;
}

export default defineComponent({
  name: 'ToDoItem',
  props: {
    task: {
      type: Object as PropType<Task>,
      required: true,
    },
  },
  emits: ['task-completed-toggle'],
  methods: {
  onTaskCompleted(event: Event) {
    this.$emit("task-completed-toggle", {
      ...this.task,
      completed: (event.target as HTMLInputElement)?.checked,
    });
  }
}

});
</script>

4.3 使用defineEmits()定义自定义事件

ToDoTtem使用defineEmits() 定义自定义事件

js 复制代码
<script lang="ts" setup>
  //...

  const props = defineProps({
    task: {
      type: Object as PropType<Task>,
      required: true,
    },
  });

  const emits = defineEmits(['task-completed-toggle']);

  const onTaskCompleted = (event: Event) => {
    emits("task-completed-toggle", {
      id: props.task.id,
      completed: (event.target as HTMLInputElement)?.checked,
    });
  }
</script>

4.4 使用provide/inject 进行组件沟通

4.4.1 使用provide 传递数据

组件的option 领域 provide 接受两种格式:数据对象 或函数。 provide 可以是一个包含要注入数据的对象,每个属性代表一个(键,值)数据类型。在以下示例中,ProductList 向其所有后代提供了数据值 selectedIds,其值为 1。

js 复制代码
<script>
export default {
  name: 'ProductList',
  // ...
  provide: {
    selectedIds: [1]
  },
}
</script>

provide 的另一种格式类型是一个返回对象的函数,该对象包含可用于注入后代的数据。这种格式类型的一个好处是,我们可以访问 this 实例,并将动态数据或组件方法映射到返回对象的相应字段。

js 复制代码
<script>
export default {
  // ...
  provide() {
    return {
      selectedIds: [1]
    };
  },
  // ...
}
</script>
4.4.2 使用 inject接收数据

在这段代码中,Vue将获取注入的selectedIds的值并将其赋给一个本地数据字段currentSelectedIds,如果没有注入值,则使用其默认值\[\]。

js 复制代码
<script lang='ts'>
export default {
  // ...
  inject: {
    currentSelectedIds: {
      from: 'selectedIds',
      default: [],
    },
  },
}
</script>
相关推荐
Dream-Y.ocean18 分钟前
鸿蒙PC平台宅匠 3D 室内设计适配实战:基于 Electron 壳方案的 Three.js 双渲染引擎与参数化户型编辑器开发
javascript·3d·harmonyos
Csvn1 小时前
性能监控
前端
Highcharts.js1 小时前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn2 小时前
构建工具
前端
FRing032 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷3 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen4 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒5 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫5 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus5 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude