vue应用构建基石-组件
1)如何封装展示内容和控制逻辑
2)组件之间层层嵌套为树状结构
3)配合使用原生Web Component
一、定义vue组件
构建型vue和非构建型各有不同的定义语法
1. SFC - 构建型vue的组件定义-标准方式
<script setup>
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">You clicked me {{ count }} times.</button>
</template>
2. vue特定选项的javascript对象 - 非构建型vue的组件定义
是一个包含 Vue 特定选项的 JavaScript 对象来定义
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
return { count }
},
// 模板是一个内联的 JavaScript 字符串,Vue 将会在运行时编译它
template: `
<button @click="count++">
You clicked me {{ count }} times.
</button>`
// 模板也可以是一个ID选择器,针对一个 DOM 内联模板:
// template: '#my-template-element'
}
二、使用vue组件
1. 导入, 全局导入和局部导入
2. 在SFC中 和 在html DOM中使用组件的名称格式注意点
1)SFC中使用驼峰PascalCase 标签名
// .vue文件中
<h1>Here is a child component!</h1>
<ButtonCounter />
<ButtonCounter />
<ButtonCounter />
2)若直接DOM中,使用kebab-case 形式,并显示关闭标签
<!-- 如果是在 DOM 中书写该模板 -->
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
三、向(子)组件传递props
1. 声明组件的props
1).<script setup>中可用defineProps(编译宏命令)
<!-- BlogPost.vue -->
<script setup>
const props = defineProps(['title'])
console.log(props.title)
</script>
<template>
<h4>{{ title }}</h4>
</template>
2).export + setup函数
export default {
props: ['title'],
setup(props) {
console.log(props.title)
}
}
2. 传递静态props
<BlogPost title="My journey with Vue" />
<BlogPost title="Blogging with Vue" />
<BlogPost title="Why Vue is so fun" />
3. 传递动态props
const posts = ref([
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
])
...
<BlogPost
v-for="post in posts"
:key="post.id"
:title="post.title"
/>
四、抛出/监听事件
1. 子组件声明要抛出事件名
1),<script setup>中声明
<!-- BlogPost.vue -->
<script setup>
defineProps(['title'])
const emits = defineEmits(['enlarge-text'])
...
// 抛出事件
emits('enlarge-text')
</script>
2),export + setup()中声明
export default {
emits: ['enlarge-text'],
setup(props, ctx) {
// 抛出事件
ctx.emit('enlarge-text')
}
}
2. 父组件监听事件
和监听原生 DOM 事件一样
<BlogPost
...
@enlarge-text="postFontSize += 0.1"
/>
3. 第三种抛出事件方式:内置的 $emit 方法
<!-- BlogPost.vue, 省略了 <script> -->
<template>
<div class="blog-post">
<h4>{{ title }}</h4>
<button @click="$emit('enlarge-text')">Enlarge text</button>
</div>
</template>
五、插槽占位符<slot>
1. 问题:如何传入如下:Something to sub component.
<AlertBox>
Something to sub component.
</AlertBox>
2. 解决, 插槽占位符<slot>
<template>
<div class="alert-box">
<strong>This is an Error for Demo Purposes</strong>
<slot />
</div>
</template>
六、动态组件
1. <component>标签实现
<!-- currentTab 改变时组件也改变 -->
<component :is="tabs[currentTab]"></component>
2. 存活被切换出的组件
在上述<component>外套一个 <KeepAlive> 组件
七、vue模板来源方式
1. 四种来源方式
1)单文件组件
2)内联模板字符串 (例如 template: '...')
3)<script type="text/x-template">
4)DOM内直接编写(受浏览器解析DOM行为的限制)
2. 浏览器解析DOM的行为限制对上述第4)中方式的影响
1)名称方面注意点包括:组件名称、prop名称、v-on事件名称的。需要将PascalCase 形式、camelCase 形式的转换成kebab-case (短横线连字符)
2)闭合标签
<my-component /> <!-- 这个关闭标签无效,需要显式闭合 -->
<span>hello</span>
3)特定子元素类型限制
例如 <ul>,<ol>,<table> 和 <select>,相应的只允许特定的子元素,即<li>,<tr> 和 <option>。
如下使用子组件<blog-post-row>,将被忽略
<table>
<blog-post-row></blog-post-row>
</table>
改用特殊属性 is, 注意子组件名使用 vue:开头
<table>
<tr is="vue:blog-post-row"></tr>
</table>