一、什么是组件
组件允许我们将 UI 划分为独立的、可重用的部分,并且可以对每个部分进行单独的思考。在实际应用中,组件常常被组织成层层嵌套的树状结构:
这和我们嵌套HTML元素的方式类似,Vue实现了自己的组件模型,使我们可以在每个组件内封装自定义内容与逻辑。在Vue中,我们可以将页面中独立的、可重用的部分封装成组件,对组件的结构、样式和行为进行设置。组件是Vue的基本结构单元,组件之间可以相互引用。
1.1定义一个计数器组件ButtonCounter.vue
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>
1.2在父组件ButtonFather.vue中导入ButtonCounter组件
<script setup>
import ButtonCounter from './ButtonCounter.vue'
// 引入ButtonCounter组件
</script>
<template>
<h1>Here is a child component!</h1>
<!-- 使用ButtonCounter组件,在使用组件时有两种方式1.<组件名/> 2.<组件名></组件名> ,而且组件可以被重用任意多次 -->
<ButtonCounter/> <!-- 使用第一种方式使用组件 -->
<ButtonCounter></ButtonCounter> <!-- 使用第二种方式使用组件 -->
</template>
分别点击页面中这两个组件不同次数后的浏览器页面截图如下(你会注意到,每当点击这些按钮时,每一个组件都维护着自己的状态,是不同的count。这是因为每当你使用一个组件,就创建了一个新的实例):
1.3全局注册ButtonCounter计数器组件
使用component(‘组件名称’, 需要被注册的组件)方法在main.js中全局注册ButtonCounter计数器组件:
import { createApp } from 'vue'
import './style.css'
import ButtonCounter from './components/ButtonCounter.vue' // 引入组件
import App from './components/ButtonFather.vue' // 引入根组件,程序的入口
// createApp(App).mount('#app') 将这句代码注释掉,并拆成如下两句const app = createApp(App)和app.mount('#app')
const app = createApp(App)
app.component('ButtonCounter',ButtonCounter) // 注册全局组件
app.mount('#app')
之后注释掉父组件ButtonFather.vue中引入ButtonCounter组件的代码:
<script setup>
// import ButtonCounter from './ButtonCounter.vue'
</script>
<template>
<h1>Here is a child component!</h1>
<!-- 使用ButtonCounter组件,在使用组件时有两种方式1.<组件名/> 2.<组件名></组件名> ,而且组件可以被重用任意多次 -->
<ButtonCounter/> <!-- 使用第一种方式使用组件 -->
<ButtonCounter></ButtonCounter> <!-- 使用第二种方式使用组件 -->
</template>
浏览器依旧正常显示全局注册的ButtonCounter组件:
二、父组件向子组件传递数据
知识点-defineProps:如果我们正在构建一个博客,我们可能需要一个表示博客文章的组件。我们希望所有的博客文章分享相同的视觉布局,但有不同的内容。要实现这样的效果自然必须向组件中传递数据,例如每篇文章标题和内容,这就会使用到props。
Props是一种特别的attributes,你可以在组件上声明注册。要传递给博客文章组件一个标题,我们必须在组件的props列表上声明它。这里要用到defineProps宏,defineProps是一个仅<script setup>中可用的编译宏命令,并不需要显式地导入。声明的props会自动暴露给模板。defineProps会返回一个对象,其中包含了可以传递给组件的所有props。
传递prop的细节详见Props | Vue.js。
2.1在子组件中声明数据
在子组件BlogPost.vue中声明要从父组件那里接收的props数据:
<script setup>
defineProps(['title']) // 通过 defineProps 定义 title 属性
</script>
<template>
<h4>{{ title }}</h4> <!-- 使用 title 属性 -->
</template>
2.2在父组件中向子组件传递数据
在父组件BlogFather.vue中向子组件传递数据:
<script setup>
import { ref } from 'vue'
import BlogPost from './BlogPost.vue' // 导入子组件BlogPost
const title1 = ref('My journey with Vue') // 定义一个变量title1
</script>
<template>
<BlogPost :title="title1" ></BlogPost>
<!— 动态绑定title1变量给子组件BlogPost的title属性 -->
</template>
三、子组件向父组件传递数据
3.1在子组件中定义事件
在子组件EmitSub.vue中通过调用内置的defineEmits方法,定义updateCount事件,并在点击按钮时触发该事件同时向父组件传递参数:
<template>
<h4>点击按钮{{ count }}次</h4>
<button @click="add">每次加{{ n }}</button>
</template>
<script setup>
import { ref } from 'vue'
const emit = defineEmits(['updateCount']) // 定义一个 updateCount 事件
const count = ref(0)
const n = ref(2)
const add = () => {
count.value++ // count 自增
emit('updateCount', n.value) // 触发 updateCount 事件,并传参
}
</script>
3.2在父组件中监听事件
在父组件EmitFather.vue中监听子组件的事件updateCount,并触发 updateEmitCount 方法:
<template>
<!-- 事件监听,监听子组件的事件updateCount,触发 updateEmitCount 方法 -->
<EmitSub @updateCount ="updateEmitCount" ></EmitSub>
<h4>父组件当前值为number:{{ number }}</h4>
</template>
<script setup>
import { ref } from 'vue'
import EmitSub from './EmitSub.vue' // 导入子组件
const number = ref(10)
// 定义一个 updateEmitCount 方法,接收一个参数 value, value 为子组件传递的值
const updateEmitCount = (value) => {
number.value += value
}
</script>
四、跨级组件之间的数据传递
通过 inject()函数 获取数据,通过 provide()函数提供数据。
子组件:
<template>
<div>子组件</div>
<hr>
从爷爷组件接收到的资金:{{ money }}
<button @click="updateMoney(500)">单击按钮增加资金</button>
</template>
<script setup>
import { inject } from 'vue' // 导入 inject
let money = inject('money') // 通过 inject 获取爷爷组件传递的 money
let updateMoney = inject('updateMoney') // 通过 inject 获取爷爷组件传递的 updateMoney 方法
</script>
父组件:
<template>
<div>父组件</div>
<hr>
<ProvideChildren />
</template>
<script setup>
import ProvideChildren from './ProvideChildren.vue'
</script>
爷爷组件:
<template>
<div>爷爷组件</div>
<hr>
<ProvideParent />
</template>
<script setup>
import ProvideParent from './ProvideParent.vue'
import { ref, provide } from 'vue' // 导入 provide
let money = ref(1000)
let updateMoney = (value) => {
money.value += value
}
provide('money', money) // 通过 provide 提供 money
provide('updateMoney', updateMoney) // 通过 provide 提供 updateMoney
</script>
附本节项目代码下载地址:
链接:https://pan.baidu.com/s/1ssiN4GAkxLfhxcg7tRXRiA?pwd=8888
提取码:8888