前言
Vue目前是一款流行的前端框架,已更新到3.0版本,她是一套用于构建用户界面的渐进式框架,易于上手并且有强大的社区,和友好的开发文档。上一篇简单整理了vue的基础,本章继续学习vue的组件,代码还是一定要自己敲一遍两遍三遍。
组件基础
一、组件基础
使用cdn,示例:
<div id="app">
{{text}}
<button-counter />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
text: 111
}
}
})
// 创建一个组件
app.component('button-counter', {
data() {
return {
}
},
template: `<div>我是一个组件</div>`
})
app.mount('#app')
</script>
使用npm
新建一个component.vue文件,然后在父组件index.vue中,使用import component from 'component.vue'引入子组件,最后在index.vue中使用,示例:
// index.vue 父组件
<template>
<div>我是父组件</div>
<component />
</template>
<script setup>
import component from './component.vue'
</script>
// component.vue 子组件
<template>
<div>我是子组件</div>
</template>
二、通过prop向子组件传递数据
使用cdn,示例:
<div id="app">
{{text}}
<button-counter v-model:title="title" />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
text: 111,
title: '父组件向子组件传值'
}
}
})
// 创建一个组件
app.component('button-counter', {
data() {
return {
}
},
props: ['title'],
template: `
<div>我是一个组件</div>
<div>{{title}}</div>
`
})
app.mount('#app')
</script>
使用npm
我这里使用的是vue3的setup语法糖,子组件拿到父组件的值需要用到defineProps这个函数。如果不想使用setup语法糖也可以使用cdn的写法。
// index.vue 父组件
<template>
<div>我是父组件</div>
<component title="父组件向子组件传值" />
</template>
<script setup>
import component from './component.vue'
</script>
// component.vue 子组件
<template>
<div>我是子组件</div>
<div>{{props.title}}</div>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
title: {
required: true
}
})
</script>
三、监听子组件事件
当我们在开发组件的时候,它有些功能是需要和父组件进行沟通的,这时候我们就可以用这个方法。
使用cdn,示例:
<div id="app">
<button-counter @event-child="handlerEvent" />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
}
},
methods: {
handlerEvent () {
console.log('我被子组件触发了')
}
}
})
// 创建一个组件
app.component('button-counter', {
data() {
return {
}
},
template: `
<div @click="handlerBtn">点击</div>
`,
methods: {
handlerBtn () {
this.$emit('eventChild')
}
}
})
app.mount('#app')
</script>
使用npm
使用vue3的setup语法糖,子组件向父组件传值需要用到defineEmits这个函数
// index.vue 父组件
<template>
<div>我是父组件</div>
<component @eventChild="handlerEvent" />
</template>
<script setup>
import component from './component.vue'
const handlerEvent = (val) => {
console.log('我被子组件触发了')
console.log(val)
}
</script>
// component.vue 子组件
<template>
<div>我是子组件</div>
<div @click="handlerBtn">点击</div>
</template>
<script setup>
import { defineEmits } from 'vue'
const emit = defineEmits(['eventChild'])
const handlerBtn = () => {
emit('defineEmits', '我可以传值给父组件')
}
</script>
特殊,可以使用$emit('update:title', '修改的值')直接修改父组件传来的执行,而不需要通过事件去修改。示例:
<div id="app">
<button-counter v-model:title="title" />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
title: '父组件向子组件传值'
}
},
methods: {
}
})
// 创建一个组件
app.component('button-counter', {
data() {
return {
}
},
props: ['title'],
template: `
<div @click="handlerBtn">点击:{{title}}</div>
`,
methods: {
handlerBtn () {
this.$emit('update:title', '直接被子组件修改了')
}
}
})
app.mount('#app')
</script>
四、插槽
向一个组件传递内容,比如:文本或者html元素。这时就可以使用插槽(slot)来实现。示例:
使用cdn,npm也是一样的
<div id="app">
<button-counter>
<div>通过插槽来传递内容</div>
<div>传递内容到子组件</div>
</button-counter>
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
const app = Vue.createApp({
data() {
return {
}
},
methods: {
}
})
// 创建一个组件
app.component('button-counter', {
data() {
return {
}
},
template: `
<div>我是一个子组件</div>
<slot></slot>
`
})
app.mount('#app')
</script>
五、Provide / Inject
深度嵌套。如果父组件向子组件传值,如果只有一层使用props即可,如果嵌套了多层就需要使用Provide / Inject来实现。
使用cdn,示例:
<div id="app">
<div @click="handlerProvide">点击:{{text}}</div>
<button-counter />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// 父组件
const app = Vue.createApp({
data() {
return {
text: 111,
title: '父组件传递的值'
}
},
provide() {
return {
parentText: Vue.computed(() => this.title)
}
},
methods: {
handlerProvide() {
this.title = '改变了,父组件传递的值'
}
}
})
// 第一层子组件
app.component('button-counter', {
data() {
return {
}
},
template: `
<div>我是一个一层嵌套组件</div>
<button-counter-child />
`
})
// 第二层子组件
app.component('button-counter-child', {
data() {
return {
}
},
inject: ['parentText'],
template: `
<div>我是一个二层嵌套组件</div>
<div>{{parentText.value}}</div>
`
})
app.mount('#app')
</script>
注意:如果要想实现响应式,通过Vue.computed来实现,如父组件中的parentText属性。
使用npm,示例:
// 父组件
<template>
<div @click="handlerProvide">点击改变值</div>
<test1-component />
</template>
<script setup>
import test1Component from './test1-component.vue'
import { ref, provide } from 'vue'
const title = ref('父组件传递的值')
provide('parentText', title)
const handlerProvide = () => {
title.value = '修改了父组件传递的值'
}
</script>
// 第一层子组件
<template>
<div>我是一个一层嵌套组件</div>
<test2-component />
</template>
<script setup>
import test2Component from './test2-component.vue'
</script>
// 第二层子组件
<template>
<div>我是一个二层嵌套组件</div>
<div>{{title}}</div>
</template>
<script setup>
import { inject } from 'vue'
const title = inject('parentText')
</script>
六、模板引用
虽然已经存在了props 和 事件,基本可以解决与子组件的通信,但有时候我们会在JavaScript中直接访问子组件。那么我们可以使用ref来实现。示例:
使用cdn,示例:
<div id="app">
<button-counter ref="userInput" />
</div>
<script src="https://unpkg.com/vue@next"></script>
<script>
// 父组件
const app = Vue.createApp({
data() {
return {
}
},
mounted() {
this.$refs.userInput.focusInput()
}
})
// 子组件
app.component('button-counter', {
data() {
return {
}
},
template: `
<input ref="input" placeholder="请输入" />
`,
methods:
focusInput() {
this.$refs.input.focus()
}
}
})
app.mount('#app')
</script>
使用npm,示例:
// index.vue 父组件
<template>
<component ref="userInput" />
</template>
<script setup>
import component from './component.vue'
import { ref, onMounted } from 'vue'
const userInput = ref(null)
onMounted(() => {
userInput.value.$refs.input.focus()
})
</script>
// component.vue 子组件
<template>
<input ref="input" placeholder="请输入" />
</template>
结语:本章主要介绍了vue的组件的一些内容,后面还有更新的会再更新。