美文网首页
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