vue中使用 render + mixins 寫法塔逃,極大程度簡化代碼開發(fā)
背景介紹
-
常規(guī)的列表頁面開發(fā)
頁面展示
組件
- page.vue
<template>
<div class="page-container">
<!-- 查詢條件 -->
<header class="page-search">
<es-row>
<es-col :span="8" class="form-item">
<label>查詢條件</label>
<es-input v-model="searchParams.keyword" placeholder="請輸入查詢關(guān)鍵字" />
</es-col>
<es-col :span="8" class="form-item">
<es-button type="primary" :loading="table.loading" @click="search">查詢</es-button>
<es-button @click="reset">重置</es-button>
</es-col>
</es-row>
</header>
<!-- 內(nèi)容區(qū)域 -->
<main class="page-content">
<es-table :data="table.data">
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手機(jī)號" />
<es-table-column prop="address" label="地址" />
<es-table-column label="操作" width="140">
<template v-slot="{ row }">
<es-button size="mini" type="primary" plain @click="editItem(row)">編輯</es-button>
<es-button size="mini" type="danger" @click="deleteItem(row)">刪除</es-button>
</template>
</es-table-column>
</es-table>
</main>
<!-- 底部分頁 -->
<FooterPagination :page="pagination.page" :size="pagination.size" :total="pagination.total" @changePage="changePage" @changeSize="changeSize" />
</div>
</template>
<script>
import FooterPagination from './components/FooterPagination.vue'
export default {
components: {
FooterPagination
},
data() {
return {
// 查詢條件
searchParams: {
keyword: ''
},
cloneParams: {},
// 表格
table: {
loading: false,
data: []
},
// 分頁
pagination: {
page: 1,
size: 20,
total: 78
}
}
},
created() {
this.cloneParams = JSON.parse(JSON.stringify(this.searchParams))
this.search()
},
methods: {
/**
* 查詢
*/
search() {
this.pagination.page = 1;
this.getTableData();
},
/**
* 獲取數(shù)據(jù)
*/
getTableData() {
this.table.loading = true;
this.$axios.get('/data/list.json').then(({ data }) => {
this.table.loading = false;
this.table.data = data.list;
this.pagination.total = data.totalCount;
}).catch(() => {
this.table.loading = false;
})
},
/**
* 重置
*/
reset() {
this.searchParams = JSON.parse(JSON.stringify(this.cloneParams))
},
/**
* 改變分頁頁數(shù)
* @param {Number} page 頁數(shù)
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改變每頁條數(shù)
* @param {Number} size 每頁條數(shù)
*/
changeSize(size) {
this.pagination.size = size
this.changePage(1)
},
/**
* 編輯
* @param {Object} row 操作的行數(shù)據(jù)
*/
editItem(row) {
console.log(row)
},
/**
* 刪除
* @param {Object} row 操作的行數(shù)據(jù)
*/
deleteItem(row) {
console.log(row)
}
}
}
</script>
- FooterPagination.vue
<template>
<footer class="page-pagination">
<es-pagination
@size-change="changeSize"
@current-change="changePage"
:current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
/>
</footer>
</template>
<script>
export default {
props: {
page: Number,
size: Number,
total: Number,
},
methods: {
changePage(page) {
this.$emit('changePage', page);
},
changeSize(size) {
this.$emit('changeSize', size);
},
},
}
</script>
優(yōu)點(diǎn)
- FooterPagination.vue
// 這些代碼可以復(fù)用挖炬,只要在這里改動配置揽浙,可以達(dá)到系統(tǒng)中所有分頁都生效
<es-pagination
@size-change="changeSize"
@current-change="changePage"
:current-page="page"
:page-sizes="[10, 20, 50, 100]"
:page-size="size"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
/>
缺點(diǎn)
- page.vue
// 還是要在父組件繁瑣的寫配置,如果要加一個props或者$emit茅茂,那么還要到每個引用的底部分頁的頁面去加
<template>
...
<!-- 底部分頁 -->
<FooterPagination :page="pagination.page" :size="pagination.size" :total="pagination.total" @changePage="changePage" @changeSize="changeSize" />
</template>
<script>
import FooterPagination from './components/FooterPagination.vue'
export default {
components: {
FooterPagination
},
data() {
return {
...
// 分頁
pagination: {
page: 1,
size: 20,
total: 78
}
}
},
methods: {
...
/**
* 改變分頁頁數(shù)
* @param {Number} page 頁數(shù)
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改變每頁條數(shù)
* @param {Number} size 每頁條數(shù)
*/
changeSize(size) {
this.pagination.size = size
this.changePage(1)
},
...
}
}
</script>
mixins
- 引入 footerPagination.js
import FooterPagination from '@/components/FooterPagination.vue'
export default {
components: {
FooterPagination
},
data() {
return {
// 分頁
pagination: {
page: 1,
size: 20,
total: 78
}
}
},
methods: {
/**
* 改變分頁頁數(shù)
* @param {Number} page 頁數(shù)
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改變每頁條數(shù)
* @param {Number} size 每頁條數(shù)
*/
changeSize(size) {
this.pagination.size = size
this.changePage(1)
},
}
}
- 修改 page.vue
<template>
<div class="page-container">
<!-- 查詢條件 -->
<header class="page-search">
<es-row>
<es-col :span="8" class="form-item">
<label>查詢條件</label>
<es-input v-model="searchParams.keyword" placeholder="請輸入查詢關(guān)鍵字" />
</es-col>
<es-col :span="8" class="form-item">
<es-button type="primary" :loading="table.loading" @click="search">查詢</es-button>
<es-button @click="reset">重置</es-button>
</es-col>
</es-row>
</header>
<!-- 內(nèi)容區(qū)域 -->
<main class="page-content">
<es-table :data="table.data">
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手機(jī)號" />
<es-table-column prop="address" label="地址" />
<es-table-column label="操作" width="140">
<template v-slot="{ row }">
<es-button size="mini" type="primary" plain @click="editItem(row)">編輯</es-button>
<es-button size="mini" type="danger" @click="deleteItem(row)">刪除</es-button>
</template>
</es-table-column>
</es-table>
</main>
<!-- 底部分頁 -->
<FooterPagination :page="pagination.page" :size="pagination.size" :total="pagination.total" @changePage="changePage" @changeSize="changeSize" />
</div>
</template>
<script>
import footerPagination from './mixins/footerPagination.js'
export default {
mixins: [footerPagination],
data() {
return {
// 查詢條件
searchParams: {
keyword: ''
},
cloneParams: {},
// 表格
table: {
loading: false,
data: []
},
}
},
created() {
this.cloneParams = JSON.parse(JSON.stringify(this.searchParams))
this.search()
},
methods: {
/**
* 查詢
*/
search() {
this.pagination.page = 1;
this.getTableData();
},
/**
* 獲取數(shù)據(jù)
*/
getTableData() {
this.table.loading = true;
this.$axios.get('/data/list.json').then(({ data }) => {
this.table.loading = false;
this.table.data = data.list;
this.pagination.total = data.totalCount;
}).catch(() => {
this.table.loading = false;
})
},
/**
* 重置
*/
reset() {
this.searchParams = JSON.parse(JSON.stringify(this.cloneParams))
},
/**
* 編輯
* @param {Object} row 操作的行數(shù)據(jù)
*/
editItem(row) {
console.log(row)
},
/**
* 刪除
* @param {Object} row 操作的行數(shù)據(jù)
*/
deleteItem(row) {
console.log(row)
}
}
}
</script>
- FooterPagination.vue 不做改動
優(yōu)點(diǎn)
- 把js部分的代碼捏萍,提取到mixins/footerPagination.js中;使得js配置不用在每個頁面重復(fù)的寫
- 規(guī)范組件中屬性和方法空闲,強(qiáng)制命名令杈;避免不同頁面,屬性和方法命名不一樣
缺點(diǎn)
- template中html部分仍然無法做到復(fù)用
- 配置中的屬性和方法碴倾,新手不容易找到逗噩,可能會忽略覆蓋
render
- 改寫 page.vue
<script>
import footerPagination from './mixins/footerPagination.js'
export default {
mixins: [footerPagination],
data() {
return {
// 查詢條件
searchParams: {
keyword: ''
},
cloneParams: {},
// 表格
table: {
loading: false,
data: []
},
}
},
created() {
this.cloneParams = JSON.parse(JSON.stringify(this.searchParams))
this.search()
},
methods: {
/**
* 查詢
*/
search() {
this.pagination.page = 1;
this.getTableData();
},
/**
* 獲取數(shù)據(jù)
*/
getTableData() {
this.table.loading = true;
this.$axios.get('/data/list.json').then(({ data }) => {
this.table.loading = false;
this.table.data = data.list;
this.pagination.total = data.totalCount;
}).catch(() => {
this.table.loading = false;
})
},
/**
* 重置
*/
reset() {
this.searchParams = JSON.parse(JSON.stringify(this.cloneParams))
},
/**
* 編輯
* @param {Object} row 操作的行數(shù)據(jù)
*/
editItem(row) {
console.log(row)
},
/**
* 刪除
* @param {Object} row 操作的行數(shù)據(jù)
*/
deleteItem(row) {
console.log(row)
}
},
render() {
return (
<div class="page-container">
{/* 查詢條件 */}
<header class="page-search">
<es-row>
<es-col span={8} class="form-item">
<label>查詢條件</label>
<es-input vModel={this.searchParams.keyword} placeholder="請輸入查詢關(guān)鍵字" />
</es-col>
<es-col span={8} class="form-item">
<es-button type="primary" loading={this.table.loading} vOn:click={() => this.search()}>查詢</es-button>
<es-button vOn:click={() => this.reset()}>重置</es-button>
</es-col>
</es-row>
</header>
{/* 內(nèi)容區(qū)域 */}
<main class="page-content">
<es-table data={this.table.data}>
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手機(jī)號" />
<es-table-column prop="address" label="地址" />
<es-table-column label="操作" width="140"
scopedSlots={{
default: ({ row }) => (
<div>
<es-button size="mini" type="primary" plain vOn:click={() => this.editItem(row)}>編輯</es-button>
<es-button size="mini" type="danger" vOn:click={() => this.deleteItem(row)}>刪除</es-button>
</div>
),
}} />
</es-table>
</main>
{/* 底部分頁 */}
{this.genFooterPagination()}
</div>
)
}
}
</script>
- 改寫 mixins/footerPagination.js
在methods里,增加genFooterPagination方法
export default {
...
methods: {
...
/**
* 渲染 底部分頁
*/
genFooterPagination() {
return (
<footer class="page-pagination">
<es-pagination
vOn:size-change={this.changeSize}
vOn:current-change={this.changePage}
current-page={this.pagination.page}
page-sizes={[10, 20, 50, 100]}
page-size={this.pagination.size}
layout="total, sizes, prev, pager, next, jumper"
total={this.pagination.total}
/>
</footer>
)
},
}
}
優(yōu)點(diǎn)
- 可以復(fù)用template中html部分跌榔,把es-pagination組件异雁,真正直接放到頁面里;直接用頁面里的data屬性和methods方法僧须,不需要下發(fā)和上報(bào)
缺點(diǎn)
- 寫法復(fù)雜纲刀,但隨著vue-cli3對vue-jsx的支持,讓jsx在vue中開發(fā)使用担平,也變得更加便利示绊;
- 官方文檔:https://github.com/vuejs/jsx
render + mixins
- 結(jié)合mixins的優(yōu)點(diǎn):復(fù)用js邏輯代碼;
- 結(jié)合render的優(yōu)點(diǎn):復(fù)用html結(jié)構(gòu)暂论;
以上兩者結(jié)合在一起使用面褐,可以做到真正意義上的代碼復(fù)用;而不是組件形式的偽復(fù)用取胎。