专栏首页方球vue 页面逻辑复用

vue 页面逻辑复用

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

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

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

例子

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

  • 目录结构
    - view
        - base-form.jsx
        - create-form.vue
        - edit-form.vue
  • base-form.jsx
/*
 * 表单组件列表
 */
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
<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
<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 组件和模板方式依然可以做到。只是相较之下使用组件的方式,将产生很多碎片文件,且需要提供数据接口。对于只是小幅修改的情况比较麻烦。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • chrome 插件通信DEOM

    content_script -> background : chrome.runtime

    copy_left
  • WebSorcet 回调转 Pormise task

    当前门禁卡通过本地服务插件与页面建立 websorcet 通信, 实现读写卡操作。

    copy_left
  • mouseHook vue 鼠标移动hook

    copy_left
  • flask 一个页面多个提交按钮(flask 23)

    class NewPostForm(FlaskForm): title = StringField('Title', validators=[DataRequ...

    用户5760343
  • Flask(表单验证 八)

    zx钟
  • Django学习之八:forms组件【对

        Handle (掌控)一个form是非常复杂的工程,需要做很多功能:不同的类型的数据要有不同的渲染;校验数据;获取检验后的干净数据,并将数据反序列化为相...

    py3study
  • Flask信号和wtforms 一、信号二、wtforms组件使用

    zhang_derek
  • Django小技巧15: 使用基于类视图的Mixins

    依类似的方式, 你可以在UpdateView中, 重用相同的FormMessageMixin, 并覆盖默认的form_invalid_message方法.

    用户1416054
  • React Native 最快捷的开发框架分享

    工具人
  • flask 使用sendgrid发送邮件(flask 33)

    import sendgrid from sendgrid.helpers.mail import Email as SGEmail, Content, Ma...

    用户5760343

扫码关注云+社区

领取腾讯云代金券