前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >vue 页面逻辑复用

vue 页面逻辑复用

作者头像
copy_left
发布2019-08-29 10:45:25
1.4K0
发布2019-08-29 10:45:25
举报
文章被收录于专栏:方球方球

在开发表单页面时, 经常碰到一种情况。 同一表单存在 新建 编辑 查看 几种状态。页面的大体组成基本相同,但又需要做部分针对当前状态的处理,处理这类问题,一般存在两种方式

  1. 直接拷贝多分,在不同页面中做处理
    • 优点: 处理简单,页面各个状态之间不会相互影响
    • 缺点: 复用率低,后期修改麻烦
  2. 在同一页面中做处理,页面跳转时提供状态标识符号,通过标识符切换页面显示
    • 优点:复用率高,修改同一
    • 缺点:逻辑复杂度高, 状态处理麻烦,页面逻辑不利于阅读
jsx + mixins 页面复用

这里提供一种使用 jsx 编写基础页面,子类页面通过修改基础页面对象,实现属于子类的页面对象

例子

这里是用 ant 实现简单表单,表单存在两种状态 新增 编辑

  • 目录结构
代码语言:javascript
复制
    - view
        - base-form.jsx
        - create-form.vue
        - edit-form.vue
  • base-form.jsx
代码语言:javascript
复制
/*
 * 表单组件列表
 */
export function formCmps(vm, form){

    return [

       {
           key: 'orderName',
           cmp: (h) =>{
                return (
                    <a-form-item label='订单名称' label-col={{span: 4}} wrapper-col={ {span: 12} }>
                    { form.getFieldDecorator('orderName')(<a-input/>) } 
                    </a-form-item>
                )
            }
       },

       {
           key: 'orderType',
           cmp: (h) =>{

            const options = [
                {
                    key: 'inland',
                    label: '国内'
                },
                {
                    key: 'overseas',
                    label: '海外'
                }
            ]
            
            return (
                    <a-form-item label='订单类型' label-col={{span: 4}} wrapper-col={ {span: 12} }>
                    {   
                        form.getFieldDecorator('orderType')(
                            <a-select>
                                { options.map(({key, label}) => <a-select-option key={key}> { label } </a-select-option> ) }
                            </a-select>
                        ) 
                    } 
                    </a-form-item>
                )
            }
       },

       {
           key: 'createTime',
           cmp:  (h) =>{
                return (
                    <a-form-item label='创建时间' label-col={{span: 4}} wrapper-col={ {span: 12} } >
                    { 
                        form.getFieldDecorator('createTime', {
                            initialValue: (new Date()).toString()
                        })( <a-date-picker  format="YYYY-MM-DD HH:mm:ss"    style={ {width: '100%'} } /> ) 
                    } 
                    </a-form-item>
                )
            }
       },

       {
        key: 'controll',
        cmp:  (h) =>{
             return (
                 <a-form-item style={ {'text-align': 'center'} } label='' label-col={{span: 4}} wrapper-col={ {span: 12} }>
                    <a-button type='primary' onClick={ vm.submit }> 提交 </a-button>
                    <a-button  onClick={ vm.reset } style={{ marginLeft: '10px' }} > 重置 </a-button>
                 </a-form-item>
             )
         }
    }


        
    ]
    
}


/**
 * 渲染函数(render)
 * 这里提供渲染模板,通过包装函数传递相应的上下文对象既 vue 实例
 */ 
export function warpRender({vm, formItems}){

    formItems = formItems || formCmps(vm, vm.form)
    
    // 这里 h 时必须的
    return function(h){
        
        return (
            <div class="form">
                <h4 class="title">
                    { vm.title }
                </h4>
                <a-form form={ vm.form }>
                    { formItems.map(item => item.cmp(h)) }
                </a-form>
            </div>
        )
        
    }
        
}

/**
 * 基础组件实例
 * 这里将挂载通用属性及方法
 */

const BaseForm = {

    name: 'base-form',
    computed:{
        orderId(){
            return this.$route.params.id
        },
    },
    data(){
        return{
            title: '默认标题',
            form: this.$form.createForm(this)
        }
    },  
    methods: {

        reset(){},
        submit(){},

        upDate(data){
            console.log(`submit data:`, data)
        },
      
    },
    
    
}

export default BaseForm
  • create-form.vue
代码语言:javascript
复制
<script>
import Vue from 'vue'
import BaseForm, { warpRender, formCmps } from './base-form'
 


export default {
    name: 'create',
    mixins: [BaseForm],
    data(){
        return {}
    },
    render(h){
        const { form } = this
        // 渲染基础函数
        return warpRender({ vm: this })(h)
    },
    methods:{
        // 改写默认方法
        submit(){
            this.upDate(this.form.getFieldsValue())
        }
    }
    
}
</script>
<style lang="stylus" scoped>
.form
    overflow hidden
    max-width 800px
    margin 20px auto
    padding 10px
    border-radius 4px
    box-shadow 0 12px 6px -4px rgba(120, 120, 120, .1)
    background #efefef;

.title{
    margin-bottom 30px;
}
</style>

新增 一基础信息出入为主,主要继承基础组件

  • edit-form.vue
代码语言:javascript
复制
<script>
import Vue from 'vue'
import BaseForm, { warpRender, formCmps } from './base-form'
 
// 编辑页私有组件
function editCmp(vm, form){
  return [
    {
      key: 'editTime',
      cmp: (h) => {
        return (
          <a-form-item label='编辑时间'  format="YYYY-MM-DD HH:mm:ss" label-col={{span: 4}} wrapper-col={ {span: 12} } >
            { 
              form.getFieldDecorator('editTime')( <a-date-picker style={ {width: '100%'} } /> ) 
            } 
          </a-form-item>
        )
      }
    }
    
  ]
}

export default {
    name: 'edit',
    mixins: [BaseForm],
    data(){
        return {
          title: '编辑页',
          sourceForm: {}, 
        }
    },
    render(h){
        const { form } = this
        const cmps = formCmps(this, form).map(item => {
          if(item.key === 'createTime'){
            item.cmp = (h) => (
              // 替换时间组件
              <a-form-item label='创建时间' label-col={{span: 4}} wrapper-col={ {span: 12} } >
                {  form.getFieldValue('createTime') }
              </a-form-item>
            )
          }
          
          return item
        })
        
        // 添加私有组件
        cmps.splice(cmps.length - 1, 0, ...editCmp(this, form))
        return warpRender({ vm: this, formItems: cmps  })(h)
    },
    methods:{
        submit(){
          this.upDate(this.form.getFieldsValue())
        },
        
        // 添加私有方法
        getOrder(id){
          return Promise.resolve({
            orderName: 'F16',
            orderType: 'inland',
            createTime: (new Date()).toString(),
          })
        },
        reset(){
          console.log(this.sourceForm)
          this.form.setFieldsValue(this.sourceForm)
        }
    },

    created(){
      // 设置表单初始数据
      this.getOrder(this.id).then(data =>  this.sourceForm = data ).then(this.reset)
    }
    
}
</script>
<style lang="stylus" scoped>
.form
    overflow hidden
    max-width 800px
    margin 20px auto
    padding 10px
    border-radius 4px
    box-shadow 0 12px 6px -4px rgba(120, 120, 120, .1)
    background #efefef

.title
  margin: 20px auto 30px auto
  margin-bottom 30px
  font-size 18px
  text-align center 
</style>

编辑 状态下, 需要提供默认数据。同时禁用部分功能

优点
  • 保证复用的情况下,劲量分割差异。
缺点
  • 基础组件编写相较模板模式复杂,更接近react
总结

这里使用 jsx 的目的在于可以动态编辑页面模板。在需要增减组件时,能提供比较灵活的手段。

其实这种处理方式,使用 vue 组件和模板方式依然可以做到。只是相较之下使用组件的方式,将产生很多碎片文件,且需要提供数据接口。对于只是小幅修改的情况比较麻烦。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.08.27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • jsx + mixins 页面复用
  • 例子
  • 优点
  • 缺点
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档