ElementUI和Ant Design对比

之前先接触了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这个属性。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容