“This is the fifth day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
A, effects,
This component is very simple to use and only requires the following configuration:
/** * Table column data (mandatory) * label Table column name * prop: Table data field name * width column width * align content alignment (center by default) * headerAlign (center by default) * columnType Whether slot is enabled * soltName Slot name (custom) */
tableColumnOptions: [{label: "Account".prop: "id" },
{ label: "Name".prop: "name" },
{ label: "tag".prop: "type".columnType: true.soltName: "tag" },
{ label: "Special style".columnType: true.soltName: "link" },
{ label: "Operation".width: "300".columnType: true.soltName: "operation"},]Copy the code
Can display:
Second, technical points
1. Component value transfer
Pass data to child components through Prop
Prop is a set of custom attributes that you can register on components. When a value is passed to a prop attribute, it becomes a property of that component instance and is easy to use:
- On the child component call tag of the parent component: Bind custom property names and property values
// partent.vue
<template>
<div>// On the child component call tag of the parent component: bind the custom attribute name and attribute value<childTemp :title="partentTitle"></childTemp>
</div>
</template>
<script>
import childTemp from "./child.vue"
export default {
compontent:{childTemp},
data(){
return{
partentTitle:"xxxxxxxx"}}}</script>
Copy the code
- In the subcomponent: use props to receive the passed value and use the received data in the same way as in data
// child.vue
<template>
<div>
<h2>{{title}}</h2>
</div>
</template>
<script>
export default {
props: ['title'] // In the child component, use props to receive the title bound in the parent component
}
</script>
Copy the code
Listen for child component events
- Bind a function to the child’s click event via this.$emit(“
Custom event name for a parent component
“,parameter
) Pass data
//child.vue
<template>
<div>
<button @click="childClick">button</button>
</div>
</template>
<script>
export default {
props: ['title'].data(){
return{
childData:"Data from child components"}},methods: {childClick(){
this.$emit("fun".this.childData)
}
}
}
</script>
Copy the code
- In the parent component: Use v-bind (@ for short) on the call tag to bind the event name fun that was just defined in the child component, and give it a custom function. The arguments that were just passed in the child component via this.$emit are automatically injected into the arguments of the custom function
<template>
<div>
<childTemp @fun="getData"></childTemp>
</div>
</template>
<script>
import childTemp from ".. /co/PropsChild.vue"
export default {
components:{childTemp},
data(){
return{
partentTitle:"xxxxxxxx"}},methods: {getData(e){//
console.log(e); // Print out "data from child components"}}}</script>
Copy the code
2. Named slot
Named slots can appear in different places and have no limit on the number of times they can appear. As long as the name matches then the content will be inserted into the slot for the name.
Like v-on and v-bind, v-slot has an abbreviation that replaces everything before the argument (v-slot:) with the character #. For example, v-slot:header can be rewritten as #header:
- The parent component
The
XXXXXX
tag automatically takes the slot tag called header in the child component and replaces everything wrapped in the template tag with that slot tag
<template>
<div>
<childTemp>
<template #header>If I write something here, it will automatically find a slot tag called header in the child component and replace it</template>
<! </template> --> </template> -->
<template #footer>If I write something here, it will automatically find a slot tag called footer in the child component and replace it</template>
</childTemp>
</div>
</template>
<script>
import childTemp from "./childTemp.vue";
export default {
components: { childTemp }
};
</script>
</script>
Copy the code
- The child components
<template>
<div class="container">I'm not in the slot tag, so I'm still visible<header style="background:blue">
<slot name="header">So what if I write it, as soon as somebody calls me, I'm replaced</slot>
</header>
<main style="background:red">
<slot name="main">I'm still here if you don't call me</slot>
</main>
<footer style="background:pink">
<slot name="footer"></slot>
</footer>
</div>
</template>
<script>
</script>
Copy the code
Prompt,
The V-slot directive was introduced since Vue 2.6.0 to provide a better API alternative that supports slot and slot-scope attributes. Slot and slot-scope attributes will still be supported in all subsequent 2.x releases, but have been officially deprecated and will not appear in Vue 3.
Get back to business and encapsulate components
The code for the encapsulated table component is as follows
BaseTable.vue
<template>
<div id="Wrap">
<! - form - >
<el-table height="100px" @selection-change="selectionChange" class="table" :data="tableData" :border="hasBorder" :row-class-name="tableRowClassName">
<el-table-column type="selection" width="50" v-if="selectionShow"> </el-table-column>
<! - serial number -- -- >
<el-table-column v-if="hasIndex" type="index" label="Serial number" header-align="center" align="center" width="80" > </el-table-column>
<! -- -- -- > other
<template v-for="item in tableColumnOptions">
<! -- Slot column -->
<el-table-column
v-if="item.columnType"
:key="item.label"
:prop="item.prop"
:label="item.label"
:width="item.width"
:header-align="item.headerAlign || 'center'"
:align="item.align || 'center'"
>
<template slot-scope="{ row }">
<slot :name="item.soltName" :data="row"></slot>
</template>
</el-table-column>
<! -- Non-slot column -->
<el-table-column
v-else
:key="item.label"
:prop="item.prop"
:label="item.label"
:width="item.width"
:header-align="item.headerAlign || 'center'"
:align="item.align || 'center'"
>
</el-table-column>
</template>
</el-table>
<! -- Pager -->
<div class="pagination" v-if="paginationShow">
<el-pagination
:hide-on-single-page="isShowPagination"
:page-sizes="[10, 20, 50, 100]." "
:current-page="currentPage"
:page-size="pageSize"
:total="tableDataTotal"
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
>
</el-pagination>
</div>
</div>
</template>
<script type="text/ecmascript-6">
export default {
name: "BaseTable".props: {
// Table data
tableData: {
type: Array.default() {
return[]; }},// Table entry
tableColumnOptions: {
type: Array.require: true.default() {
return[]; }},// Total table data
tableDataTotal: {
type: Number.default() {
return 0; }},// Whether there is an index
hasIndex: {
type: Boolean.default() {
return true; }},// Whether to display a border
hasBorder: {
type: Boolean.default() {
return false; }},// Whether to display the selection box
selectionShow: {
type: Boolean.default() {
return true; }},// Whether to display the selected pager
paginationShow: {
type: Boolean.default() {
return true; }},},data() {
return {
// The current page number of the table
currentPage: 1.// Number of tables per page
pageSize: 10}; },computed: {
// Calculates whether the pager is displayed
isShowPagination() {
const isShow = this.tableDataTotal === 0;
returnisShow; }},methods: {
// The table changes color
tableRowClassName({ row, rowIndex }) {
if (rowIndex % 2= =1) {
return "color-row"; }},// Modify the current page
handleCurrentChange(val) {
const params = {
currentPage: val,
pageSize: this.pageSize,
};
this.$emit("tableUpdate", params);
},
// Change the number per page
handleSizeChange(val) {
const params = {
currentPage: this.currentPage,
pageSize: val,
};
this.$emit("tableUpdate", params);
},
// The selection box changes
selectionChange(e){
this.$emit('selectionChange',e)
}
},
};
</script>
<style scoped>
#Wrap {
width: 100%;
height: 100%;
box-sizing: border-box;
background-color: #fff;
display: flex;
flex-direction: column; } > > >.el-table{
/* overflow-y:scroll! important; * /
}
#Wrap .pagination{
margin-top: auto;
margin-left: auto; } > > >.cell{
text-align: center; } > > >.cell #link{
font-family: MicrosoftYaHei;
color: #445af7;
cursor: pointer; } > > >.cell #delete {
color: #ff5b5b;
margin-left: 35px;
cursor: pointer; } > > >.color-row{
background-color: rgb(243.243.243); } > > >.el-table--border::after..el-table--group::after..el-table::before {
content: ' ';
position: absolute;
background-color: transparent! important;
z-index: 1;
}
</style>
Copy the code
Fifth, use
In the page to be used
<template>
<div id="baseButton">
<BaseTable
:has-index="true"
:has-border="false"
:table-data="tableData"
:table-data-total="tableData.length"
:table-column-options="tableColumnOptions"
@tableUpdate="tableUpdate"
@selectionChange="selectionChange"
>
<! -- Type slot -->
<template #tag="{ data }">
<div class="tag">
<el-tag type="success" v-if="data.type == 1">tag1</el-tag>
<el-tag type="danger" v-if="data.type == 0">tag2</el-tag>
</div>
</template>
<! -- Operation slot -->
<template #operation="{ data }">
<span @click="tableRowEdit(data)">The editor</span>
<span @click="tableRowDelete(data)" id="delete">delete</span>
</template>
<! -- Link slot -->
<template #link="{ data }">
<span id="link" @click="check(data)">To view</span>
</template>
</BaseTable>
</div>
</template>
<script>
import BaseTable from ".. /BaseTable.vue";
export default {
components: {
BaseTable,
},
methods: {
selectionChange(e) {
console.log("Select box changes:",e);
},
tableUpdate(e) {
console.log("When the form changes",e);
},
tableRowEdit(e){
console.log("Get the data for this row.",e); }},data() {
return {
// Table component -- simulates data
tableData: [{id: 201791074073.name: "Zhang".type: 1 },
{ id: 201791074071.name: "Bill".type: 0 },
{ id: 201791074074.name: "A second".type: 0 },
{ id: 201791074074.name: "A second".type: 0 },
{ id: 201791074074.name: "A second".type: 1},]./** * Table column data (mandatory) * label Table column name * prop: * width Column item width * align content alignment (center by default) * headerAlign header alignment (center by default) * columnType Whether to enable slot * soltName Slot name */
tableColumnOptions: [{label: "Account".prop: "id" },
{ label: "Name".prop: "name" },
{ label: "tag".prop: "type".columnType: true.soltName: "tag" },
{ label: "Special style".columnType: true.soltName: "link" },
{ label: "Operation".width: "300".columnType: true.soltName: "operation"},]}; }};</script>
Copy the code
ColumnType will slot open and soltName slot name. ColumnType will slot open and soltName. Use named slots in the baseTable tag to write your particular style.
In this way, we call this component in different pages, not only ensure the different page table style is consistent, also ensure that the difference of the different pages, is the biggest benefit of using this component, form the style of the uniform set within the encapsulated form component, a change, other parts change, can rapid global change style.