效果展示

创建项目
- 创建项目
| npm init vite-app table
cd table
npm i
npm i less -D
npm i axios -S
|
- 设置全局样式
在index.css中:
1 2 3 4 5 6 7 8 9 10 11
| :root {
font-size: 12px;
}
body {
padding: 5px;
}
|
- 引入Bootstrap.css
将Bootstrap.css复制到static/css文件夹下面
在main.js中:
1
| import './static/css/Bootstrap.css';
|
- 封装axios
创建api/api.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import axios from 'axios';
axios.defaults.baseURL = 'https://www.escook.cn';
export const MyRequest;
在main.js中:
import { MyRequest } from './api/api.js';
const app = createApp(App);
app.config.globalProperties.$http = MyRequest;
app.mount('#app');
|
封装数据
在App.vue中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <script>
export default {
data() {
return {
goodList: []
}
},
created() {
this.getGoodList();
},
methods: {
async getGoodList() {
const { data: res } = await this.$http.get('/api/goods');
if (res.status !== 0) return alert('商品列表获取失败!');
this.goodList = res.data;
}
}
}
</script>
|
创建组件MyTable.vue,注册到App.vue中,并传入数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <template>
<my-table :data="goodList"></my-table>
</template>
<script>
import MyTable from './components/MyTable.vue';
export default {
components: { MyTable }
}
</script>
|
- 实现header
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <template>
<table>
<thead>
<tr>
<slot name="header"></slot>
</tr>
</thead>
<tbody></tbody>
</table>
</template>
|
- 在App.vue中渲染表头:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <template>
<my-table>
<template #header>
<th>序号</th>
<th>商品名称</th>
<th>价格</th>
<th>标签</th>
<th>操作</th>
</template>
</my-table>
</template>
|
实现body作用域插槽
- 实现body:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <template>
<table>
...
<tbody>
<tr v-for="item in data" :key="item.id">
<slot name="body" :item="item"></slot>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
data: {
type: Array,
required: true
}
}
}
</script>
|
- 在App.vue中渲染body
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| <template>
<my-table>
...
<template #body="{ item }">
<td>{{ item.id }}</td>
<td>{{ item.goods_name }}</td>
<td>¥{{ item.goods_price }}</td>
<td>
<input class="form-control form-control-sm form-ipt" type="text" v-model.trim="item.inputValue" v-if="item.inputVisible" />
<button class="btn btn-primary btn-sm" v-else @click="item.inputVisible = true">+Tag</button>
<div class="badge badge-warning tag" v-for="tag in item.tags" :key="tag">{{ tag }}<div>
</td>
<td>
<button class="btn btn-danger btn-sm">删除</button>
</td>
</template>
</my-table>
</template>
<style>
.form-ipt {
width: 80px;
display: inline;
}
.tag {
margin: 0 4px;
}
</style>
|
增加删除功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| <template>
...
<button @click="onDelete(item.id)">...</button>
...
</template>
<script>
export default {
...
methods: {
onDelete(id) {
this.goodList = this.goodList.filter(x => x.id !== id);
}
}
}
</script>
## 实现显示组件获得焦点
<template>
...
<input ... v-focus />
...
</template>
<script>
export default {
directives: {
focus(el) {
el.focus();
}
}
}
</script>
|
借助自定义指令功能实现
实现失去焦点后的功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| <template>
...
<input ... @blur="onAddTag(item)">
...
</template>
<script>
export default {
methods: {
onAddTag(item) {
const val = item.inputValue;
item.inputValue = '';
item.inputVisible = false;
// 检查是否重复
if (!val || item.tags.indexOf(val) !== -1) return;
item.tags.push(val);
}
}
}
</script>
|
添加按键功能
按下回车键添加标签,按下esc键清空输入框:
1 2
| <input ... @keyup.enter="onAddTag(item)" @keyup.esc="item.inputValue=''" />
|
参考:
Vue3.0-23.Table案例 -
介绍案例的效果以及主要实现步骤
Vue3.0-24.Table案例 -
初始化项目
Vue3.0-25.Table案例 -
请求商品列表的数据
Vue3.0-26.Table案例 -
封装my-table组件并声明data数据源
Vue3.0-27.Table案例 -
把表头区域封装为header具名插槽
Vue3.0-28.Table案例 -
把表格主体区域封装为body作用域插槽
Vue3.0-29.Table案例 -
实现删除商品的功能
Vue3.0-30.Table案例 -
循环渲染Tag标签
Vue3.0-31.Table案例 -
实现input和button的按需显示
Vue3.0-32.Table案例 -
实现文本框自动获得焦点的功能
Vue3.0-33.Table案例 -
文本框失去焦点自动隐藏
Vue3.0-34.Table案例 -
实现新增Tag标签的功能