文章目录
以下是关于封装my-table表格组件的基本要求,理解即可。
1.数据不能写死,动态传递表格渲染的数据;
2.结构不能写死:
(1)表头支持自定义;
(2)主体支持自定义;
基本步骤如下:
1.新建MyTable.vue文件
2.导入和注册
3.使用组件
4.数据准备(渲染表格所需要的数据来源)
5.父组件中的goods数据向子组件(MyTable.vue)传递数据
6.自定义表头
7.自定义表主体
代码结构如下所示,总共四个代码文件,如果只是为了学习表格组件封装,只需要看MyTable.vue以及app.vue即可。
8.代码分享
app.vue代码如下:
<template>
<div class="app">
<div class="table-case">
<MyTable :data="goods">
<template #head>
<th>编号</th>
<th>图片</th>
<th>名称</th>
<th width="100px">标签</th>
</template>
<template #body="{ item, index }">
<td>{{ index + 1 }}</td>
<td>
<img :src="item.picture" alt="" />
</td>
<td>{{ item.name }}</td>
<td>
<!-- 标签组件 -->
<MyTag v-model="item.tag"></MyTag>
</td>
</template>
</MyTable>
</div>
</div>
<!--
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div> -->
</template>
<script>
// import HelloWorld from "./components/HelloWorld.vue";
// my-tag组件的封装
// 1.创建组件-初始化
// 2.实现功能
// (1)双击显示,并且自动获取焦点;
// (2)失去焦点,隐藏输入框;
// (3)双击要回显标签信息;(回显的标签信息一定是父组件传过来的)
// (4)内容修改了,回车可以实现修改标签信息。
// --------------------------------------------------------------
// 封装my-table表格组件
// 1.数据不能写死,动态传递表格渲染的数据;
// 2.结构不能写死
// (1)表头支持自定义;
// (2)主体支持自定义;
import MyTag from "./components/MyTag.vue";
import MyTable from "./components/MyTable.vue";
export default {
name: "TableCase",
data() {
return {
tempText: "紫砂壶",
tempText1: "茶壶",
goods: [
{
id: 101,
picture:
"https://img.icons8.com/?size=100&id=37879&format=png&color=000000",
name: "毛茸茸紫砂壶",
tag: "紫砂锅",
},
{
id: 102,
picture:
"https://img.icons8.com/?size=100&id=15585&format=png&color=000000",
name: "巧克力紫砂壶",
tag: "紫砂壶",
},
{
id: 103,
picture:
"https://img.icons8.com/?size=100&id=81384&format=png&color=000000",
name: "喵咪咪紫砂壶",
tag: "暖手壶",
},
],
};
},
components: {
MyTag,
MyTable,
},
};
</script>
<style scoped>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
MyTable.vue代码如下:
<template>
<table class="my-table">
<thead>
<slot name="head"></slot>
</thead>
<tbody>
<tr v-for="(item, index) in data" :key="item.id">
<slot name="body" :item="item" :index="index"></slot>
</tr>
</tbody>
</table>
</template>
<script>
export default {
props: {
data: {
type: Array,
required: true,
},
},
};
</script>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f4f4f4;
}
.app {
max-width: 800px;
margin: auto;
background: white;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 20px;
}
.table-case {
overflow-x: auto; /* 对于大表格,添加水平滚动条 */
}
.my-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.my-table th,
.my-table td {
border: 1px solid #dddddd;
text-align: center;
padding: 12px;
}
.my-table th {
background-color: #1c5d99; /* 表头背景颜色 */
color: white; /* 表头字体颜色 */
}
.my-table tr:nth-child(even) {
background-color: #f9f9f9; /* 斑马条纹效果 */
}
.my-table tr:hover {
background-color: #f1f1f1; /* 鼠标悬停效果 */
}
.my-tag {
display: inline-block;
padding: 5px 10px;
/* background-color: #f7f9fd; 标签背景颜色 */
color: rgb(27, 25, 25); /* 标签字体颜色 */
border-radius: 3px;
font-size: 14px;
/* border: 1px solid rgb(171, 164, 164); */
}
img {
max-width: 80px; /* 确保图片不会过大 */
height: auto;
}
</style>
MyTag.vue代码如下:
<template>
<div class="my-tag">
<input
ref="inp"
v-focus
v-if="isEdit"
type="text"
class="input"
placeholder="输入标签"
@blur="isEdit = false"
:value="value"
@keyup.enter="handleEnter"
/>
<div v-else class="text" @dblclick="handleClick">{{ value }}</div>
</div>
</template>
<script>
export default {
props: {
value: String,
},
data() {
return {
isEdit: false,
};
},
methods: {
handleClick() {
this.isEdit = true;
// // vue是异步dom更新
// this.$nextTick(() => {
// //立刻获取焦点
// this.$refs.inp.focus();
// });
},
handleEnter(e) {
// 子传父,将回车时,输入框的内容提交给父组件更新
// 由于父组件用了v-model,触发事件需要触发input
if (e.target.value.trim() === "") {
return alert("标签内容不能为空");
}
console.log(e.target.value);
this.$emit("input", e.target.value);
this.isEdit = false;
},
},
};
</script>
<style lang="less" scoped>
.my-tag {
cursor: pointer;
// background-color: aqua;
.input {
appearance: none;
outline: none;
border: 1px solid #ccc;
width: 80px;
height: 40px;
box-sizing: border-box;
padding: 10px;
color: #666;
&::placeholder {
color: #666;
}
}
}
</style>
main.js代码如下:
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
//封装全局指令focus 否则MyTag中的获取焦点函数内要写很多次
Vue.directive('focus',{
inserted(el){
el.focus()
}
})
new Vue({
render: h => h(App),
}).$mount('#app')