美文网首页
render + mixins 写法,基础篇

render + mixins 写法,基础篇

作者: 三省吾身_9862 | 来源:发表于2021-12-31 12:26 被阅读0次

    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 不做改动
    优点
    1. 把js部分的代码,提取到mixins/footerPagination.js中;使得js配置不用在每个页面重复的写
    2. 规范组件中属性和方法,强制命名;避免不同页面,属性和方法命名不一样
    缺点
    1. template中html部分仍然无法做到复用
    2. 配置中的属性和方法,新手不容易找到,可能会忽略覆盖

    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>
          )
        },
      }
    }
    
    优点
    1. 可以复用template中html部分,把es-pagination组件,真正直接放到页面里;直接用页面里的data属性和methods方法,不需要下发和上报
    缺点
    1. 写法复杂,但随着vue-cli3对vue-jsx的支持,让jsx在vue中开发使用,也变得更加便利;
    2. 官方文档:https://github.com/vuejs/jsx

    render + mixins

    1. 结合mixins的优点:复用js逻辑代码;
    2. 结合render的优点:复用html结构;
      以上两者结合在一起使用,可以做到真正意义上的代码复用;而不是组件形式的伪复用。

    源码链接:https://gitee.com/wkp_mayun/render-mixins-esay

    下一篇:render + mixins 写法,进阶

    相关文章

      网友评论

          本文标题:render + mixins 写法,基础篇

          本文链接:https://www.haomeiwen.com/subject/rtaiqrtx.html