1
4.1 案例------商品管理
4.1.1 项目初始化
在开发"商品管理"项目时,需要先完成一些准备工作,具体步骤如下。
① 打开命令提示符,切换到 D:\vue\chapter04 目录,在该目录下执行如下命令,创
建项目。
npm create vite@4.1.0 table -- --template vue
项目创建完成后,执行如下命令进入项目目录,启动项目。
cd table
npm install
npm run dev
项目启动后,可以使用 URL 地址 http://127.0.0.1:5173/ 进行访问。
② 使用 VS Code 编辑器打开 D:\vue\chapter04\table 目录。
③ 将 src\style.css 文件中的样式代码全部删除,从而避免项目创建时自带的样式代
码影响本案例的实现效果。
④ 引用 Bootstrap 样式。在 D:\vue\chapter04\table 根目录下的 index.html 文件中使用
jsDelivr (一个免费且开源的 CDN ),在页面上引入 Bootstrap 的核心 CSS 文件,引用之
后可以在页面上使用 Bootstrap 进行样式开发,具体代码如下。
1 <html lang="en">
2 <head>
3 ......(原有代码)
4 <link
5 href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstr
ap.min.css" rel="stylesheet" crossorigin="anonymous"
6 />
7 </head>
上述代码中,将 <link> 标签添加到 <head> 标签中,完成 Bootstrap 核心 CSS 文件的引
入。
至此,项目初始化已完成。
4.1.2 初始化商品列表数据 2
接下来正式进入"商品管理"案例的开发,在 App 组件中定义列表数据,具体代码
如下。
1 <script setup>
2 import { ref } from 'vue'
3 const goodsList = ref([
4 {
5 id: 1,
6 goods_name: ' 夏季专柜同款女鞋 ',
7 goods_price: 298,
8 tags: [' 舒适 ', ' 透气 '],
9 inputVisible: false,
10 inputValue: ''
11 },
12 {
13 id: 2,
14 goods_name: ' 冬季保暖女士休闲雪地靴 舒适加绒防水短靴 防滑棉鞋 ',
15 goods_price: 89,
16 tags: [' 保暖 ', ' 防滑 '],
17 inputVisible: false,
18 inputValue: ''
19 },
20 {
21 id: 3,
22 goods_name: ' 秋冬新款女士毛衣 套头宽松针织衫 简约上衣 ',
23 goods_price: 199,
24 tags: [' 秋冬 ', ' 毛衣 '],
25 inputVisible: false,
26 inputValue: ''
27 },
28 {
29 id: 4,
30 goods_name: '2023 春秋装新款大码女装 衬衫 上衣 ',
31 goods_price: 19,
32 tags: [' 雪纺衫 ', ' 打底 '],
33 inputVisible: false,
34 inputValue: ''
35 },
36 { 3
37 id: 5,
38 goods_name: ' 长款长袖圆领女士毛衣 2022 秋装新款假两件连衣裙 ',
39 goods_price: 178,
40 tags: [' 圆领 ', ' 连衣裙 '],
41 inputVisible: false,
42 inputValue: ''
43 }
44 ])
45 </script>
上述代码中,第 3~44 行代码定义了 goodsList 变量,表示商品列表数据,其中
goods_name 属性表示商品名称、 goods_price 属性表示商品价格、 id 属性表示商品编号、
inputValue 属性表示文本框的值、 inputVisible 属性设置文本框的显示与隐藏的标识符、
tags 数组表示商品标签。
4.1.3 封装 MyTable 组件
初始化数据完成后,需要将数据在页面上展示出来。为了提高组件的复用性,需要
封装 MyTable 组件。需要将 App 组件中的数据通过 props 属性传递给 MyTable 组件实现
数据共享。为了方便组件的使用者可以自定义表格的标题和内容,分别通过具名插槽、
作用域插槽实现自定义表格中的标题和内容。封装 MyTable 组件包括创建并使用
MyTable 组件、声明数据源、预留名称为 header 的具名插槽和预留名称为 body 的作用域
插槽,下面分别进行实现。
( 1 )创建并使用 MyTable 组件
① 在 D:\vue\chapter04\table\src\components 目录下新建 MyTable.vue 文件,表示
MyTable 组件,用于展示商品列表表格。
② 在 App 组件中导入并注册 MyTable 组件,具体代码如下。
1 <script setup>
2 import MyTable from './components/MyTable.vue'
3 </script>
上述代码中,第 2 行代码通过 import 语法导入 MyTable 组件。
③ 在 App 组件中使用 MyTable 组件,具体代码如下。
1 <template>
2 <h4> 商品管理 </h4>
3 <MyTable></MyTable>
4 </template>
上述代码中,第 3 行代码以标签的形式使用 MyTable 组件。
( 2 )声明数据源 4
在使用 MyTable 组件时,需要从父组件( App 组件)中获取数据。通过 props 属性实
现父子组件之间的数据共享,首先在子组件( MyTable 组件)中定义 props 属性用于接收
数据,然后在父组件中进行数据传递。声明 MyTable 组件数据源的具体步骤如下。
① 在 MyTable 组件的 props 属性中声明 goodsList 数据源,具体代码如下。
1 <script setup>
2 const props = defineProps({
3 goodsList: {
4 type: Array,
5 required: true,
6 default: []
7 }
8 })
9 </script>
上述代码中,第 2~8 行代码通过 defineProps() 函数定义表格中需要接收的数据源,其
中第 3~7 行代码定义了 goodsList 属性,表示需要从父组件中接收该数据,同时在接收
goodsList 时进行验证。第 4 行代码中通过 type 属性验证 goodsList 值类型为 Array (数
组);第 5 行代码通过 required 属性验证 goodsList 为必填项;第 6 行代码通过 default 属
性验证 goodList 默认值为空数组。
② 在 App 组件中使用 MyTable 组件时,动态绑定 goodsList 的值,具体代码如下。
<MyTable :goodsList="goodsList"></MyTable>
上述代码中,通过 v-bind 指令为表格指定数据源 goodsList 。
通过 Mustache 语法将 goodsList 在页面上展示出来,测试父组件向子组件中传递数据
是否成功。在测试完成后删除即可。
至此,声明 MyTable 组件数据源已完成。
( 3 )预留名称为 header 的具名插槽
在封装组件时,为了提高组件的复用性,把表格标题区域预留为具名插槽,使得用
户可以自定义表格标题,具体步骤如下。
① 使用 Bootstrap 提供的 Tables 渲染 MyTable 组件中基本的模板结构,具体代码如
下。
1 <template>
2 <table class="table table-striped table-bordered">
3 <!-- 表格标题区域 -->
4 <thead>
5 <tr>
6 <th scope="col">#</th>
7 <th scope="col"> 商品名称 </th>
8 <th scope="col"> 价格 </th>
9 <th scope="col"> 标签 </th> 5
10 <th scope="col"> 操作 </th>
11 </tr>
12 </thead>
13 <!-- 表格主体区域 -->
14 <tbody></tbody>
15 </table>
16 </template>
上述代码中,第 2~15 行代码定义了表格区域,用于展示商品列表数据,其中第 4~12
行代码定义了表格标题区域,第 14 行代码定义了表格主体区域。
② 修改 MyTable 组件中的代码,以具名插槽的形式展示表格标题区域,具体代码
如下。
1 <thead>
2 <tr>
3 <slot name="header"></slot>
4 </tr>
5 </thead>
上述代码中,第 3 行代码为修改后的代码,定义名称为 header 的插槽,这样会将组
件使用者自定义的内容全部填充到名称为 header 的插槽中。
③ 在 App 组件中,通过具名插槽为 MyTable 组件指定标题名称,具体代码如下。
1 <MyTable :goodsList="goodsList">
2 <template v-slot:header>
3 <th scope="col">#</th>
4 <th scope="col"> 商品名称 </th>
5 <th scope="col"> 价格 </th>
6 <th scope="col"> 标签 </th>
7 <th scope="col"> 操作 </th>
8 </template>
9 </MyTable>
上述代码中,第 2~8 行代码定义了 <template> 标签,并在该标签上使用 v-slot 指令,
以 v-slot 参数的形式提供名称,从而向名称为 header 的插槽提供内容。
④ 在 App 组件中,设置表格标题的样式,具体代码如下。
1 <style scoped>
2 th {
3 text-align: center;
4 }
5 </style>
上述代码中,第 2~4 行代码设置了表格中标题列文本的对齐方式为居中对齐。
至此,预留名称为 header 的具名插槽已完成。 6
( 4 )预留名称为 body 的作用域插槽
在封装组件时,为了自定义表格内容,将表格主体区域预留为作用域插槽,具体步
骤如下。
① 在 MyTable 组件中渲染表格的数据行,具体代码如下。
1 <tbody>
2 <tr v-for="(item, index) in goodsList" :key="item.id"></tr>
3 </tbody>
上述代码中,第 2 行代码通过 v-for 指令将 App 组件中接收到的数据循环渲染出来。
② 修改 MyTable 组件中的代码,把表格里面的数据行中的 <td> 标签预留为具名插
槽,具体代码如下。
1 <tbody>
2 <tr v-for="(item, index) in goodsList" :key="item.id">
3 <slot name="body"></slot>
4 </tr>
5 </tbody>
上述代码中,第 3 行代码为新增代码,通过 name 属性定义插槽的名称为 body ,这
样可以自定义表格内容到名称为 body 的插槽中。
③ 为了让组件的使用者在提供 body 插槽的内容时,能够自定义内容的渲染方式,
需要把 body 具名插槽同时升级成作用域插槽,修改 MyTable 组件中的代码,具体如下。
<slot name="body" :row="item" :index="index" ></slot>
上述代码中,在定义插槽的同时定义 row 属性表示表格行的数据,定义 index 属性表
示商品序号。
④ 在 App 组件中,基于作用域插槽方式渲染表格的数据,具体代码如下。
1 <template #body="{ row, index }">
2 <td>{{ index + 1 }}</td>
3 <td>{{ row.goods_name }}</td>
4 <td> ¥ {{ row.goods_price }}</td>
5 <td>{{ row.tags }}</td>
6 <td>
7 <button type="button" class="btn btn-outline-danger btn-sm"> 删除
</button>
8 </td>
9 </template>
上述代码中,第 1 行代码使用名称为 body 的作用域插槽对外提供的数据对象,通过
解构赋值接收数据,其中第 2~5 行代码通过 Mustache 语法将接收到的数据按需展示出
来,第 7 行代码定义了 button 按钮,表示删除按钮。
⑤ 在 App 组件中设置表格中内容样式,具体代码如下。
1 <style scoped> 7
2 td{
3 line-height: 30px;
4 }
5 </style>
上述代码中,第 2~4 行代码设置表格中主体内容区域行高为 30px ,使得文本垂直居
中。
保存上述代码后在浏览器中打开 http://127.0.0.1:5173/ ,页面效果如图 4-1 所示。
图 4-1 页面效果
从图 4-1 中可以看出,商品信息成功渲染在页面上。
4.1.4 实现删除整条商品数据功能
在本案例中,对商品信息进行管理,对无效的商品信息进行删除,接下来实现删除
整条商品数据的功能,具体步骤如下。
① 在 App 组件中修改 <button> 标签的代码,添加 click 事件,具体代码如下。
<button type="button" class="btn btn-outline-danger btn-sm"
@click=" onRemove(row.id) "> 删除 </button>
② 在 App 组件的中声明 onRemove() 方法,实现商品数据的删除,具体代码如下。
1 <script setup>
2 ......(原有代码)
3 const onRemove = id => {
4 goodsList.value = goodsList.value.filter(item => item.id != id)
5 }
6 </script> 8
上述代码中,第 4 行代码通过调用 filter() 方法,将传入 id 与原始数组中 id 相同的数
据进行过滤。
保存并运行上述代码,读者自行尝试商品列表中商品的删除功能。
4.1.5 实现添加标签的功能
在本案例中,实现添加商品标签功能时需要添加一个文本框和一个按钮,当单击按
钮时,显示文本框同时按钮隐藏,此时可以在文本框中输入标签内容,添加商品标签。
实现添加标签功能的具体步骤如下。
① 自定义渲染标签列。在 App 组件中修改渲染商品标签列,具体代码如下。
1 <td>
2 <span class="btn btn-outline-dark" v-for="item in row.tags" :key="item
">
3 {{ item }}
4 </span>
5 </td>
上述代码中,第 2 行代码通过 v-for 将 tags 数组进行循环渲染,第 3 行代码通过
Mustache 语法将 item 在页面上渲染出来。
② 修改 App 组件中的代码,实现文本框和按钮的按需展示,具体如下。
1 <td>
2 <input type="text" v-if="row.inputVisible" class="form-control form-co
ntrol-sm ipt-tag"/>
3 <button class="btn btn-outline-primary rounded-pill" v-else @click="ro
w.inputVisible = true">+Tag</button>
4 ......(原有代码)
5 </td>
上述代码中,第 2~3 行代码分别定义了 <input> 标签和 <button> 标签,用于表示文本
框和按钮。通过 v-if 、 v-else 指令及当前行的 inputVisible 属性来实现文本框和按钮的按需
展示。若 inputVisible 属性值为 true ,则文本框展示,否则展示按钮。第 3 行代码设置了
单击事件,在单击按钮时 inputVisible 属性值为 true ,使得文本框展示。
③ 在 App 组件中为文本框添加样式,具体代码如下。
1 <style scoped>
2 .ipt-tag {
3 width: 80px;
4 display: inline;
5 }
6 </style> 9
上述代码中,第 2~5 行代码设置了文本框的宽度和设置文本框为行内元素显示,让
文本框和其他元素在同一行显示。
④ 当单击按钮切换到文本框之后,还需文本框自动获取焦点,接下来在 App 组件
中编写自定义指令,具体代码如下。
1 <script setup>
2 ......(原有代码)
3 const vFocus = (el) => { el.focus() }
4 </script>
上述代码中,第 3 行代码以函数的形式定义 focus 指令,实现获取焦点的功能。
⑤ 在 App 组件中使用自定义指令,实现指令第一次绑定文本框时获取焦点,具体
代码如下。
<input type="text" v-if="row.inputVisible" class="form-control form
control-sm ipt-tag" v-focus >
上述代码中,为 input 输入框添加 v-focus 指令。
⑥ 通过添加 v-model 指令实现数据的双向绑定,具体代码如下。
1 <input type="text"
2 v-if="row.inputVisible"
3 class="form-control form-control-sm ipt-tag"
4 v-focus
5 v-model="row.inputValue"
6 />
上述代码中,第 5 行代码为新增代码,当用户改变 input 输入框中的值时,
inputValue 的值会发生改变。
⑦ 监听文本框的 blur 事件,在触发事件时,把当行数据传递进去,具体代码如
下。
1 <input type="text" v-if="row.inputVisible" class="form-control form
control-sm ipt-tag" v-focus
2 v-model="row.inputValue"
3 @blur="onInputConfig(row)"
4 />
上述代码中,第 3 行代码为新增代码,添加 blur 事件,当文本框失去焦点时触发
onInputConfig() 方法。
⑧ 在 App 组件中声明 onInputConfig() 方法,实现将文本框中数据保存并清空,具
体代码如下。
1 <script setup>
2 ......(原有代码)
3 const onInputConfig = row => {
4 const val = row.inputValue 10
5 row.inputValue = ''
6 row.inputVisible = false
7 }
8 </script>
上述代码中,第 3~7 行代码定义了 onInputConfig() 方法,表示文本框失去焦点时的事
件。第 4 行代码将文本框中获取的值保存在 val 属性中,第 5 行代码将文本框的值置空,
第 6 行代码将 inputVisible 属性值设置为 false ,展示按钮。
⑨ 进一步修改 onInputConfig() 方法,实现标签的添加,具体代码如下。
1 const onInputConfig = (row) => {
2 ......(原有代码)
3 if (!val || row.tags.indexOf(val) !== -1) {
4 return
5 }
6 row.tags.push(val)
7 }
上述代码中,第 3~5 行代码首先对 val 值进行判断,如果 val 值为空或者已经存在于
tags 数组中,则不在进行添加,直接返回,否则执行第 6 行代码,将用户输入的内容作为
新的标签通过调用 push() 方法添加到当前行的 tags 数组中。
⑩ 添加文本框的内容。当用户按下" Enter "键时,把当前输入的内容添加为 tag
标签,具体代码如下。
1 <input type="text"
2 v-if="row.inputVisible"
3 class="form-control form-control-sm ipt-tag" v-focus
4 model="row.inputValue"
5 @blur="onInputConfig(row)"
6 @keyup.enter="onInputConfig(row)"
7 />
上述代码中,第 6 行代码为新增代码,为回车按键绑定 onInputConfig() 方法,实现标
签的添加功能。
⑪ 清空文本框的内容。当用户在文本框中按下" Esc "按键时,清空文本框的内
容,具体代码如下。
1 <input type="text" v-if="row.inputVisible" class="form-control form
control-sm ipt-tag" v-focus
2 v-model="row.inputValue"
3 @blur="onInputConfig(row)"
4 @keyup.enter="onInputConfig(row)"
5 @keyup.esc="row.inputValue = ''"
6 /> 11
上述代码中,第 5 行代码为新增代码,为 Esc 键绑定方法,当按下" Esc "键时,
inputValue 属性值设置为空,清空文本框中的内容。
保存并运行上述代码,单击按钮可以切换到文本框,通过文本框实现标签添加功
能。
至此,"商品管理"案例已开发完成。
Vue3阶段四开发文档商品管理
寒月6582024-06-22 9:27
相关推荐
小阮的学习笔记6 分钟前
Vue3中使用LogicFlow实现简单流程图YBN娜7 分钟前
Vue实现登录功能杨荧10 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统minDuck11 分钟前
ruoyi-vue集成tianai-captcha验证码嚣张农民2 小时前
推荐3个实用的760°全景框架计算机-秋大田2 小时前
基于Spring Boot的船舶监造系统的设计与实现,LW+源码+讲解落魄小二3 小时前
el-table 表格索引不展示问题neter.asia3 小时前
vue中如何关闭eslint检测?十一吖i3 小时前
前端将后端返回的文件下载到本地光影少年3 小时前
vue2与vue3的全局通信插件,如何实现自定义的插件