ElementUI和Ant Design对比

作者: 陨石坠灭 | 来源:发表于2020-04-20 00:09 被阅读0次

    之前先接触了ElementUI,然后后面又接触了Ant Design,在这里做个对比,希望通过对比这两前端ui框架,能够更加深入的了解和使用这些框架。

    表格对比

        首先,通过一张表格来对比这两框架的异同吧

    对比项 ElementUI Ant Design
    logo
    官网/文档 vue: https://element.eleme.cn vue: https://www.antdv.com/docs/vue
    react: https://ant.design/docs/react/introduce-cn
    团队 饿了么 蚂蚁金服
    简介 基于 Vue 2.0 的桌面端组件库 开发和服务于企业级后台产品
    最新版本 vue: 2.13.1 vue: 1.5.3
    react: 4.1.4
    组件前缀 el- a-
    github vue: https://github.com/ElemeFE/element vue: https://github.com/vueComponent/ant-design-vue
    react: https://github.com/ant-design/ant-design
    start/fork vue: 44.8k/10.3k vue: 10k/1.4k
    react: 58.8k/21.5k
    pro版 https://github.com/PanJiaChen/vue-element-admin https://pro.ant.design/

    个人感受

        从体验上来看:

    我更加倾向于elementUI, UI上更加漂亮,使用起来更加容易上手。
    一开始,我最新接触的就是elementUI,感觉elementUI这个框架更加适合于面向外部开发。

    而作为对比的Ant Design,也有一定的优势。
    从功能上来讲,后者更加齐全。比如回到顶部组件:树形选择:<a-tree-select />Ant Design更加适合管理平台的开发。

        从实用上来看:

    对于pro版本,vue-element-admin允许初始化基础版,而ant-design-pro这个初始化后有大量的例子,开发之前还得把例子删掉,这点感觉不太好。
    总之,两个框架的pro版本做的都非常棒,但个人更加倾向于ant-design,毕竟组件多占有非常大的优势。

        总之:

    如果是想快速上手,又希望ui更加漂亮,建议用elementUI;如追求的是比较复杂的后台管理平台,可以考虑采用ant-design-pro,而且ant-design-pro无论表格还是表单,都是高度可配置化的。这点相对于elementUI来说,ant-design-pro虽然稍微复杂了点,但是换来更大的便利。

    一些建议和经验

    以下代码部分都是vue,不涉及react

    1. elementUI的菜单组件<el-dropdown>在手机端点击会回弹的问题

    修改triggerclick的方式,因为默认hover时,手机上并不能有很好的体验。

    2. elementUI如何实现通用表单的配置

    采用form-create这个库可以很方便的实现表单完全的json配置

    主页:http://www.form-create.com/
    git地址:https://github.com/xaboy/form-create

    另外还有一种方式,就是利用Vue的插槽实现,这种方式也适合ant-design的可配置表单的实现。

    ps: 注意插槽名称不要带数字,最好不要

    下面是利用插槽实现可配置的例子,这里以ant-design为例:

    form.json

    {
      "props": {
        "layout": "inline"
      },
      "dataSource": [
        {
          "label": "咨询ID",
          "cmp": "Input",
          "decorator": ["qaId", { "initialValue": "" }],
          "props": {
            "allowClear": true
          }
        }
    ]
    

    然后是编写通用表单组件:
    分为两个文件:baseForm.vue和commonForm.vue,对外使用commonForm.vue即可:

    baseForm.vue

    <template>
      <a-form v-bind="props" :form="form" @submit="onSubmit">
        <template v-for="item in dataSource">
          <a-form-item :key="item.key" :label="item.label">
            <slot :name="item.cmp" :item="item" :form="props.name"> </slot>
          </a-form-item>
        </template>
        <slot name="footer">
          <a-form-item label>
            <a-button type="primary" html-type="submit"> 提交 </a-button>
          </a-form-item>
        </slot>
      </a-form>
    </template>
    <script>
    export default {
      props: {
        props: {
          type: Object,
          default() {
            return {}
          }
        },
        dataSource: {
          type: Array,
          default() {
            return []
          }
        }
      },
      data() {
        return {
          form: this.$form.createForm(this, { name: ’base-form‘ })
        }
      },
      methods: {
        handleReset() {
          this.form.resetFields()
        },
        validate() {
          this.form.validateFields({ force: true }, () => {})
        },
        getFields() {
          return new Promise((resolve, reject) => {
            this.form.validateFields({ force: true }, (err, values) => {
              if (err) {
                reject(err)
                return
              }
              resolve(values)
            })
          })
        },
        onSubmit(e) {
          e && e.preventDefault()
          this.form.validateFields((err, values) => {
            if (!err) {
              this.$emit('change', values)
            }
          })
        }
      }
    }
    </script>
    

    commonForm.vue

    <template>
      <div v-if="dataSource.length">
        <base-form
          ref="form"
          :props="props"
          :dataSource="dataSource"
          @change="change"
        >
          <template v-slot:Input="{ item }">
            <a-input v-decorator="item.decorator" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:Radio="{ item }">
            <a-radio v-decorator="item.decorator" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:RadioGroup="{ item }">
            <a-radio-group v-decorator="item.decorator" :options="item.options" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:Switch="{ item }">
            <a-switch v-decorator="item.decorator" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:DatePicker="{ item }">
            <a-date-picker v-decorator="item.decorator" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:Checkbox="{ item }">
            <a-checkbox v-decorator="item.decorator" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:CheckboxGroup="{ item }">
            <a-checkbox-group v-decorator="item.decorator" :options="item.options" v-bind="item.props" v-on="item.events" />
          </template>
          <template v-slot:Select="{ item }">
            <a-select v-decorator="item.decorator" v-bind="item.props" :options="item.options" v-on="item.events" />
          </template>
        </base-form>
      </div>
    </template>
    <script>
    export default {
      props: {
        value: {
          type: Object,
          default() {
            return {}
          }
        },
        props: {
          type: Object,
          default() {
            return {}
          }
        },
        dataSource: {
          type: Array,
          default() {
            return []
          }
        }
      },
      components: {
        BaseForm: () => import('./BaseForm')
      },
      model: {
        prop: 'value',
        event: 'change'
      },
      methods: {
        reset() {
          this.$refs.form.handleReset()
        },
        validate() {
          this.$refs.form.validate()
        },
        getFields() {
          return this.$refs.form.getFields()
        },
        isExistedSlot(name) {
          return this.registedSlot.includes(name)
        },
        change(values) {
          this.$emit('change', values)
        }
      }
    }
    </script>
    

    ps: 这里需要注意v-bindv-on,平时我们都是用:<属性名称>以及@<事件名称>,而这里属性和事件并不是固定的,通过v-bind="props"以及v-on="events"可以批量的不固定的设置属性和事件

    3. 关于手动文件上传

    注意,ant-design中,file对象可以通过绑定<a-upload-dragger :beforeUpload="beforeUpload" />beforeUpload方法得到。

    export default {
      methods:{
        importDoc(data, file, progress) {
               return this.$axios({
                url: '<上传地址>',
                method: 'post',
                headers: { 'Content-Type': 'multipart/form-data' },
                onUploadProgress: function(progressEvent) {
                const complete = ((progressEvent.loaded / progressEvent.total) * 100) | 0
                progress(file, complete)
                },
                data
            })
        }
      },
    upload(file){
      var formData = new FormData()
            formData.append('file', file)
            file.status = 'uploading'
            const res = await importDoc(formData, file, this.progress)
            file.status = 'success'
      }
    }
    

    4. Ant Design表单自定义组件,且支持校验

    实际上这个很好做:

    export default {
      props:['value'],
      model:{ prop: 'value', event: 'change' },
      methods:{
        changeValue(value){
          this.$emit('change', value)
        }
      }
    }
    

    这里需要注意,属性只能是value,这样也同时支持了valuev-model。然后假设有自定义组件demo.vue,则该表单组件可以这样写:

    <demo v-decorator="['demo',{ 'initialValue': '', rules:[ { required: true, message: '请输入demo' } ] }]" />

    5. store文件夹下的状态管理中,modules文件夹下所有文件的自动引入

    这个可以采纳vue-element-admin中的写法:

    替换strore/index.vue文件:

    import Vue from 'vue'
    import Vuex from 'vuex'
    import getters from './getters'
    Vue.use(Vuex)
    const modulesFiles = require.context('./modules', true, /\.js$/)
    // 遍历modules文件
    const modules = modulesFiles.keys().reduce((modules, modulePath) => {
      const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
      const value = modulesFiles(modulePath)
      modules[moduleName] = value.default
      return modules
    }, {})
    const store = new Vuex.Store({
      modules,
      getters
    })
    export default store
    

    这里需要注意,strore/modules下的文件不一定都是状态文件,所以可以对于value进行进一步判断,比如说判断value是否存在,是否有state这个属性。

    相关文章

      网友评论

        本文标题:ElementUI和Ant Design对比

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