vue中使用 render + mixins 写法,极大程度简化代码开发
背景介绍
-
常规的列表页面开发
页面展示
组件
- 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="请输入查询关键字" />
</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>
<!-- 内容区域 -->
<main class="page-content">
<es-table :data="table.data">
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手机号" />
<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();
},
/**
* 获取数据
*/
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 {Number} page 页数
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改变每页条数
* @param {Number} size 每页条数
*/
changeSize(size) {
this.pagination.size = size
this.changePage(1)
},
/**
* 编辑
* @param {Object} row 操作的行数据
*/
editItem(row) {
console.log(row)
},
/**
* 删除
* @param {Object} row 操作的行数据
*/
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>
优点
- FooterPagination.vue
// 这些代码可以复用,只要在这里改动配置,可以达到系统中所有分页都生效
<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"
/>
缺点
- 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: {
...
/**
* 改变分页页数
* @param {Number} page 页数
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改变每页条数
* @param {Number} size 每页条数
*/
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: {
/**
* 改变分页页数
* @param {Number} page 页数
*/
changePage(page) {
this.pagination.page = page
this.getTableData()
},
/**
* 改变每页条数
* @param {Number} size 每页条数
*/
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="请输入查询关键字" />
</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>
<!-- 内容区域 -->
<main class="page-content">
<es-table :data="table.data">
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手机号" />
<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();
},
/**
* 获取数据
*/
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 操作的行数据
*/
editItem(row) {
console.log(row)
},
/**
* 删除
* @param {Object} row 操作的行数据
*/
deleteItem(row) {
console.log(row)
}
}
}
</script>
- FooterPagination.vue 不做改动
优点
- 把js部分的代码,提取到mixins/footerPagination.js中;使得js配置不用在每个页面重复的写
- 规范组件中属性和方法,强制命名;避免不同页面,属性和方法命名不一样
缺点
- template中html部分仍然无法做到复用
- 配置中的属性和方法,新手不容易找到,可能会忽略覆盖
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();
},
/**
* 获取数据
*/
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 操作的行数据
*/
editItem(row) {
console.log(row)
},
/**
* 删除
* @param {Object} row 操作的行数据
*/
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="请输入查询关键字" />
</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>
{/* 内容区域 */}
<main class="page-content">
<es-table data={this.table.data}>
<es-table-column prop="name" label="姓名" />
<es-table-column prop="phone" label="手机号" />
<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>
)
},
}
}
优点
- 可以复用template中html部分,把es-pagination组件,真正直接放到页面里;直接用页面里的data属性和methods方法,不需要下发和上报
缺点
- 写法复杂,但随着vue-cli3对vue-jsx的支持,让jsx在vue中开发使用,也变得更加便利;
- 官方文档:https://github.com/vuejs/jsx
render + mixins
- 结合mixins的优点:复用js逻辑代码;
- 结合render的优点:复用html结构;
以上两者结合在一起使用,可以做到真正意义上的代码复用;而不是组件形式的伪复用。
网友评论