vue 从入门到入土---复习 组件高级下

目录

ref 引用

 动态组件

 插槽

 自定义指令

Table 案例

总结


ref 引用

1. 什么是 ref 引用

ref 用来辅助开发者在 不依赖于 jQuery 的情况下 ,获取 DOM 元素或组件的引用。
每个 vue 的组件实例上,都包含一个 $refs 对象 ,里面存储着对应的 DOM 元素或组件的引用。默认情况下, 组件的 $refs 指向一个空对象

 2. 使用 ref 引用 DOM 元素          

如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:       

 4. 控制文本框和按钮的按需切换

通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。示例代码如下:

 5. 让文本框自动获得焦点

当文本框展示出来之后,如果希望它立即获得焦点,则可以为其添加 ref 引用,并调用原生 DOM 对象的 .focus() 方法即可。示例代码如下:

 6. this.$nextTick(cb) 方法

组件的 $nextTick(cb) 方法,会把 cb 回调 推迟到下一个 DOM 更新周期之后执行 。通俗的理解是:等组件的 DOM 异步地重新渲染完成后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

 动态组件

动态组件指的是 动态切换组件的显示与隐藏 。vue 提供了一个内置的 <component> 组件,专门用来实现组件 的动态渲染。
  • ① <component> 是组件的占位符
  • ② 通过 is 属性动态指定要渲染的组件名称
  • ③ <component is="要渲染的组件的名称"></comp

2. 如何实现动态组件渲染

3. 使用 keep-alive 保持状态

默认情况下,切换动态组件时 无法保持组件的状态 。此时可以使用 vue 内置的 <keep-alive> 组件保持动态组 件的状态。示例代码如下:

 插槽

1. 什么是插槽

插槽 Slot )是 vue 为 组件的封装者 提供的能力。允许开发者在封装组件时,把 不确定的 希望由用户指定的 部分 定义为插槽 可以把插槽认为是组件封装期间,为用户预留的 内容的占位符

 2. 体验插槽的基础用法

在封装组件时,可以通过 <slot> 元素定义插槽,从而为用户预留内容占位符。示例代码如下:

2.1 没有预留插槽 的内容会被丢弃

 如果在封装组件时没有预留任何 <slot> 插槽,则用户提供的任何自定义内容会被丢弃

 2.2 后备内容

封装组件时,可以为预留的 <slot> 插槽提供 后备内容 (默认内容)。如果组件的使用者没有为插槽提供任何 内容,则后备内容会生效。示例代码如下:

 3. 具名插槽

如果在封装组件时 需要预留多个插槽节点 ,则需要为每个 <slot> 插槽指定 具体的 name 名称 。这种 带有具体名称的插槽 叫做“具名插槽”。示例代码如下:
注意:没有指定 name 名称的插槽, 会有隐含的名称叫做 “ default ”。

 3.1 为具名插槽提供内容

在向具名插槽提供内容的时候,我们可以在一个 <template> 元素上使用 v-slot 指令,并以 v-slot 的参数的 形式提供其名称。示例代码如下

 3.2 具名插槽的简写形式

跟 v-on 和 v-bind 一样,v-slot 也有缩写,即把参数之前的所有内容 ( v-slot: ) 替换为字符 # 。例如 v-slot: header 可以被重写为 # header

 4. 作用域插槽

在封装组件的过程中,可以为预留的 <slot> 插槽绑定 props 数据,这种 带有 props 数据的 <slot> 叫做“ 作用 域插槽 ”。示例代码如下:

 4.1 解构作用域插槽的 Prop

作用域插槽对外提供的数据对象,可以使用解构赋值简化数据的接收过程。示例代码如下:

 4.2 声明作用域插槽

在封装 MyTable 组件的过程中,可以通过 作用域插槽 把表格每一行的数据传递给组件的使用者。

 4.3 使用作用域插槽

在使用 MyTable 组件时,自定义单元格的渲染方式,并接收作用域插槽对外提供的数据

 自定义指令

1. 什么是自定义指令

vue 官方提供了 v-for、v-model、v-if 等常用的内置指令。除此之外 vue 还允许开发者自定义指令

vue 中的自定义指令分为两类,分别是:私有自定义指令  ,全局自定义指令

2. 声明私有自定义指令的语法

在每个 vue 组件中,可以在 directives 节点下声明私有自定义指令。示例代码如下:

 3. 使用自定义指令

在使用自定义指令时,需要加上 v- 前缀。示例代码如下:

 4. 声明全局自定义指令的语法

全局共享的自定义指令需要通过“单页面应用程序的实例对象”进行声明,示例代码如下:

 5. updated 函数

 mounted 函数只在元素第一次插入 DOM 时被调用,当 DOM 更新时 mounted 函数不会被触发。 updated 函数会在每次 DOM 更新完成后被调用。示例代码如下:

注意:在 vue2 的项目中使用自定义指令时,【 mounted -> bind 】【 updated -> update

 6. 函数简写

如果 mounted 和updated 函数中的逻辑完全相同,则可以简写成如下格式:

 7. 指令的参数值

在绑定指令时,可以通过“ 等号 ”的形式为指令绑定 具体的参数值 ,示例代码如下:

Table 案例

1. 案例效果

 2. 用到的知识点

  • 组件封装
  • 具名插槽
  • 作用域插槽
  • 自定义指令

3. 实现步骤

1. 搭建项目基本结构

1.1 初始化项目

1. 在终端运行如下的命令,初始化 vite 项目:

2. cd 到项目根目录,安装依赖项:

3. 安装 less 依赖包:

4. 使用 vscode 打开项目,并在 vscode 集成的终端下运行如下的命令,把项目运行起来:

npm init vite-app table-demo 
npm install 
npm i less -D
npm run dev 
1.2 梳理项目结构
重置 App.vue 根组件的代码结构:
<template>
 <div>
 <h1>App 根组件</h1>
 </div>
</template> <script>
export default {
 name: 'MyApp', }
</script> <style lang="less" scoped></style>
2. 删除 components 目录下的 HelloWorld.vue 组件
3. 重置 index.css 中的样式:
:root {
 font-size: 12px; }
body {
 padding: 8px; } 1234567
4. 把资料 目录下的 css 文件夹复制、粘贴到 assets 目录中,并在 main.js 入口文件中
导入 bootstrap.css
import { createApp } from 'vue'
import App from './App.vue'
// 导入 bootstrap 样式表
import './assets/css/bootstrap.css'
import './index.css'
createApp(App).mount('#app')
2. 请求商品列表的数据
npm install axios@0.21.0 -S
2. 在 main.js 入口模块中,导入并全局配置 axios
/ 1. 导入 axios
import axios from 'axios'
const app = createApp(App)
// 2. 将 axios 挂载到全局,今后,每个组件中,都可以直接通过
this.$http 代替 axios 发起 Ajax 请求
app.config.globalProperties.$http = axios
// 3. 配置请求的根路径
axios.defaults.baseURL = 'https://www.escook.cn'
app.mount('#app')
3. 在 App.vue 组件的 data 中声明 goodslist 商品列表数据:
data() {
 return {
 // 商品列表数据
 goodslist: []
 }
} 
4. 在 App.vue 组件的 methods 中声明 getGoodsList 方法,用来从服务器请求商品列 表的数据:
methods: {
 // 初始化商品列表的数据
 async getGoodsList() {
 // 发起 Ajax 请求
 const { data: res } = await this.$http.get('/api/goods')
 // 请求失败
 if (res.status !== 0) return console.log('获取商品列表失
败!')
 // 请求成功
 this.goodslist = res.data
 }
}
5. App.vue 组件中,声明 created 生命周期函数,并调用 getGoodsList 方法:
created() {
 this.getGoodsList()
} 
3. 封装 MyTable 组件
3.0 MyTable 组件的封装要求
  • 1. 用户通过名为 data prop 属性,为 MyTable.vue 组件指定数据源
  • 2. 在 MyTable.vue 组件中,预留名称为 header 的具名插槽
  • 3. 在 MyTable.vue 组件中,预留名称为 body 的作用域插槽

3.1 创建并使用 MyTable 组件

1. 在 components/my-table 目录下新建 MyTable.vue 组件
<template>
 <div>MyTable 组件</div>
</template> <script>
export default {
 name: 'MyTable',
}
</script> <style lang="less" scoped></style>
App.vue 组件中导入并注册 MyTable.vue 组件:
/ 导入 MyTable 组件
import MyTable from './components/my-table/MyTable.vue'
export default {
 name: 'MyApp',
 // ... 省略其它代码
 // 注册 MyTable 组件
 components: {
 MyTable
 }
} 
3. App.vue 组件的 DOM 结构中使用 MyTable.vue 组件:
<template>
 <div>
 <h1>App 根组件</h1>
 <hr />
 <!-- 使用表格组件 -->
 <my-table></my-table>
 </div>
</template> 
3.2 为表格声明 data 数据源
1. MyTable.vue 组件的 props 节点中声明表格的 data 数据源
export default {
 name: 'MyTable',
 props: {
 // 表格的数据源
 data: {
 type: Array,
 required: true,
 default: [],
 },
 },
} 
2. App.vue 组件中使用 MyTable.vue 组件时,通过 属性绑定的形式 为表格指定 data 数 据源:
<!-- 使用表格组件 -->
<my-table :data="goodslist"></my-table> 
3.3 封装 MyTable 组件的模板结构
1. 基于 bootstrap 提供的Tables在 MyTable.vue 组件中渲染最基本的模板结构
( https://v4.bootcss.com/docs/content/tables/ )
<template>
 <table class="table table-bordered table-striped">
 <!-- 表格的标题区域 -->
 <thead>
 <tr>
 <th>#</th>
 <th>商品名称</th>
 <th>价格</th>
 <th>标签</th>
 <th>操作</th>
 </tr>
 </thead>
 <!-- 表格的主体区域 -->
 <tbody></tbody>
 </table>
</template>
2. 为了提高组件的复用性,最好把表格的 标题区域 预留为 <slot> 具名插槽 ,方便使用者 自定义表格的标题
<template>
 <table class="table table-bordered table-striped">
 <!-- 表格的标题区域 -->
 <thead>
 <tr>
 <!-- 命名插槽 -->
 <slot name="header"></slot>
 </tr>
 </thead>
 <!-- 表格的主体区域 -->
 <tbody></tbody>
 </table>
</template> 
3. App.vue 组件中,通过 具名插槽 的形式,为 MyTable.vue 组件指定标题名称:
<!-- 使用表格组件 -->
<my-table :data="goodslist">
 <!-- 表格的标题 -->
 <template v-slot:header>
 <th>#</th>
 <th>商品名称</th>
 <th>价格</th>
 <th>标签</th>
 <th>操作</th>
 </template>
</my-table>
3.4 预留名称为 body 的作用域插槽
1. MyTable.vue 组件中,通过 v-for 指令循环渲染表格的数据行:
<template>
 <table class="table table-bordered table-striped">
 <thead>
 <tr>
 <slot name="header"></slot>
 </tr>
 </thead>
 <!-- 表格的主体区域 -->
 <tbody>
<!-- 使用 v-for 指令,循环渲染表格的数据行 -->
 <tr v-for="(item, index) in data" :key="item.id"></tr>
 </tbody>
 </table>
</template>
为了提高 MyTable.vue 组件的复用性,最好把表格数据行里面的 td 单元格预留为 <slot> 具名插槽。示例代码如下:
<template>
 <table class="table table-bordered table-striped">
 <thead>
 <tr>
 <slot name="header"></slot>
 </tr>
 </thead>
 <!-- 表格的主体区域 -->
 <tbody>
 <!-- 使用 v-for 指令,循环渲染表格的数据行 -->
 <tr v-for="(item, index) in data" :key="item.id">
 <!-- 为数据行的 td 预留的插槽 -->
 <slot name="body"></slot>
 </tr>
 </tbody>
 </table>
</template> 
3. 为了让组件的使用者在提供 body 插槽的内容时,能够自定义内容的渲染方式,需要把
body 具名插槽 升级为 作用域插槽
<template>
 <table class="table table-bordered table-striped">
 <thead>
 <tr>
 <slot name="header"></slot>
 </tr>
 </thead>
 <!-- 表格的主体区域 -->
 <tbody>
 <!-- 使用 v-for 指令,循环渲染表格的数据行 -->
 <tr v-for="(item, index) in data" :key="item.id">
 <!-- 为数据行的 td 预留的“作用域插槽” -->
 <slot name="body" :row="item" :index="index"></slot>
 </tr>
</tbody>
 </table>
</template>
4. App.vue 组件中,基于 作用域插槽 的方式渲染表格的数据:
<!-- 使用表格组件 -->
<my-table :data="goodslist">
 <!-- 表格的标题 -->
 <template v-slot:header>
 <th>#</th>
 <th>商品名称</th>
 <th>价格</th>
 <th>标签</th>
 <th>操作</th>
 </template>
 <!-- 表格每行的单元格 -->
 <template v-slot:body="{ row, index }">
 <td>{{ index + 1 }}</td>
 <td>{{ row.goods_name }}</td>
 <td>¥{{ row.goods_price }}</td>
 <td>{{ row.tags }}</td>
 <td>
 <button type="button" class="btn btn-danger btn-sm">删除
</button>
 </td>
 </template>
</my-table> 
4. 实现删除功能
1. 为删除按钮绑定 click 事件处理函数:
<td>
 <button type="button" class="btn btn-danger btn-sm"
@click="onRemove(row.id)">删除</button>
</td> 123
App.vue 组件的 methods 中声明事件处理函数如下:
methods: {
 // 根据 Id 删除商品信息
 onRemove(id) {
 this.goodslist = this.goodslist.filter(x => x.id !== id)
 },
}
5. 实现添加标签的功能
5.1 自定义渲染标签列
根据 bootstrap 提供的 Badge效果,循环渲染商品的标签信息如下:
( https://v4.bootcss.com/docs/components/badge/#contextual-variations )
<td>
 <span class="badge badge-warning ml-2" v-for="item in row.tags"
:key="item">{{tag}}</span>
</td> 
5.2 实现 input button 的按需展示
使用 v-if 结合 v-else 指令,控制 input button 的按需展示:
<td>
 <!-- 基于当前行的 inputVisible,来控制 input 和 button 的按需展
示-->
 <input type="text" class="form-control form-control-sm ipt-tag"
v-if="row.inputVisible">
 <button type="button" class="btn btn-primary btn-sm" velse>+Tag</button>
 <span class="badge badge-warning ml-2" v-for="item in row.tags"
:key="item">{{item}}</span>
</td> 
2. 点击按钮,控制 input button 的切换:
<td>
 <!-- 基于当前行的 inputVisible,来控制 input 和 button 的按需展
示-->
 <input type="text" class="form-control form-control-sm ipt-tag"
v-if="row.inputVisible" />
 <button type="button" class="btn btn-primary btn-sm" v-else
@click="row.inputVisible = true">+Tag</button>
 <span class="badge badge-warning ml-2" v-for="item in row.tags"
:key="item">{{item}}</span>
</td> 
5.3 input 自动获取焦点
1. 在 App.vue 组件中,通过 directives 节点自定义 v-focus 指令如下:
directives: {
 // 封装自动获得焦点的指令
 focus(el) {
 el.focus()
 },
}
2. 为 input 输入框应用 v-focus 指令:
<input type="text" class="form-control ipt-tag form-control-sm" vif="row.inputVisible" v-focus />
5.4 文本框失去焦点自动隐藏
1. 使用 v-model 指令把 input 输入框的值双向绑定到 row.inputValue 中:
<input
 type="text"
 class="form-control ipt-tag form-control-sm"
 v-if="row.inputVisible"
 v-focus
 v-model.trim="row.inputValue"
/>
2. 监听文本框的 blur 事件,在触发其事件处理函数时,把 当前行的数据 传递进去:
<input
 type="text"
 class="form-control ipt-tag form-control-sm"
 v-if="row.inputVisible"
 v-focus
 v-model.trim="row.inputValue"
 @blur="onInputConfirm(row)"
/>
3. 在 App.vue 组件的 methods 节点下声明 onInputConfirm 事件处理函数:
onInputConfirm(row) {
 // 1. 把用户在文本框中输入的值,预先转存到常量 val 中
 const val = row.inputValue
 // 2. 清空文本框的值
 row.inputValue = ''
 // 3. 隐藏文本框
 row.inputVisible = false
} 
5.5 为商品添加新的 tag 标签
进一步修改 onInputConfirm 事件处理函数如下:
onInputConfirm(row) {
 // 把用户在文本框中输入的值,预先转存到常量 val 中
 const val = row.inputValue
 // 清空文本框的值
 row.inputValue = ''
 // 隐藏文本框
 row.inputVisible = false
 // 1.1 判断 val 的值是否为空,如果为空,则不进行添加
 // 1.2 判断 val 的值是否已存在于 tags 数组中,防止重复添加
 if (!val || row.tags.indexOf(val) !== -1) return
 // 2. 将用户输入的内容,作为新标签 push 到当前行的 tags 数组中
 row.tags.push(val) }
5.6 响应文本框的回车按键
当用户在文本框中敲击了 回车键 的时候,也希望能够把当前输入的内容添加为 tag 标签。此时,可 以为文本框绑定 keyup 事件如下:
<input
 type="text"
 class="form-control ipt-tag form-control-sm"
 v-if="row.inputVisible"
 v-focus
 v-model.trim="row.inputValue"
 @blur="onInputConfirm(row)"
 @keyup.enter="onInputConfirm(row)"
/>
5.7 响应文本框的 esc 按键
当用户在文本框中敲击了 esc 按键的时候,希望能够快速清空文本框的内容。此时,可以为文本框
绑定 keyup 事件如下:
<input
 type="text"
 class="form-control ipt-tag form-control-sm"
 v-if="row.inputVisible"
 v-focus
 v-model.trim="row.inputValue"
 @blur="onInputConfirm(row)"
 @keyup.enter="onInputConfirm(row)"
 @keyup.esc="row.inputValue = ''"
/>

总结        

①能够知道如何使用 ref 引用 DOM 和组件实例

通过 ref 属性指定引用的名称、使用 this.$refs 访问引用实例

② 能够知道 $nextTick 的调用时机

组件的 DOM 更新之后,才执行 $nextTick 中的回调

③ 能够说出 keep-alive 元素的作用

动态组件的状态

④ 能够掌握插槽的基本用法

<slot> 标签、具名插槽、作用域插槽v-slot: 简写为 #

⑤ 能够知道如何自定义指令

私有自定义指令、全局自定义指令

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue3.0中的组件高级功能包括保持动态组件状态和引用DOM元素。 保持动态组件状态的方法是使用Vue内置的<keep-alive>组件。通过将动态组件包裹在<keep-alive>标签中,可以在切换动态组件时保持组件的状态。例如: ```html <keep-alive> <component :is="comName"></component> </keep-alive> ``` 在这个例子中,comName是一个data属性,用于指定当前要渲染的组件的名称。通过在<component>标签中使用:is属性,可以动态地指定要渲染的组件。 引用DOM元素的方法是使用ref属性。通过给DOM元素添加ref属性,可以在组件中通过$refs属性获取对DOM元素的引用。例如: ```html <template> <h3>MyRef组件</h3> <button @click="getRef">获取$refs引用</button> </template> <script> export default { methods: { getRef() { console.log(this.$refs) // $refs指向一个空对象,需要在DOM元素上添加ref属性 } } } </script> ``` 在这个例子中,点击按钮后,调用getRef方法可以在控制台上输出当前组件实例对象this。通过this.$refs可以访问到DOM元素的引用。 以上就是Vue3.0中组件高级功能的两个示例,分别是保持动态组件状态和引用DOM元素。希望能对你有所帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Vue3.0----组件高级【下】(第五章)](https://blog.csdn.net/QQ675396947/article/details/127486948)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值