修改ElementUI源码实践
提要
github地址:https://github.com/boychina/element-dev
Vue2.0+Vuex+ElementUI是现在很多项目都在使用的BS软件的开发组合。
Vue相较于Angular具有学习成本低,上手快以及组件轻量化的特点;相较于React,其官方提供的很多指令以及可以自定义的指令能够为让开发更加高效。并且相较于React生命周期监听所有props和state的变化,Vue中提供的watch方法监听单个数据的变化,能够更加直观的进行数据操作。
需要修改源码的项目需求
需要修改源码的项目需求总共有两处:
- ElementUI提供的树型组件的CheckBox需要进行置灰;
- ElementUI的的穿梭框中需要进行6000条以上的数据操作;
准备工作
利用 npm install element-ui --save 下载的内容中包括了ElementUI每个组件的源码 node_modules\element-ui\packages, 以及官方当前版本打包以后的代码 node_modules\element-ui\lib, 我们一般全量引入或者是部分引入组件都引用是打包以后的 lib 里边的代码。
- //main.js 全量引入ElementUI组件
- import Vue from 'vue'
- import App from './App'
- import router from './router'
- import store from './vuex/index'
- import './libs/auto'
- import ElementUI from 'element-ui'
- import 'element-ui/lib/theme-default/index.css'
- import './assets/common/css/reset.css'
- Vue.config.productionTip = false
- Vue.use(ElementUI)
- /* eslint-disable no-new */
- new Vue({
- el: '#app',
- store,
- router,
- ElementUI,
- template: '<App/>',
- components: { App }
- })
- //main.js 中部分引入组件
- import Vue from 'vue'
- import { Button, Select } from 'element-ui'
- import App from './App.vue'
- Vue.component(Button.name, Button)
- Vue.component(Select.name, Select)
- /* 或写为
- * Vue.use(Button)
- * Vue.use(Select)
- */
- new Vue({
- el: '#app',
- render: h => h(App)
- })
所以,如果利用以上两种方式是不能引用到packages里边我们修改以后的代码的。 要用直接在packages文件里边引入模块的方式进行引入。
- import Button from 'element-ui/packages/button'
不过,这种方式也存在相应的问题: 由于ElementUI中使用了一些高级语法,其中包括jsx等的方式,所以需要下载相应的模块,比如‘transform-vue-jsx’。 并且在.babelrc文件中添加:
- "plugins": ["transform-runtime","transform-vue-jsx"],
这样,就可以跑出来了,一切看起来似乎都好了。
但是,不幸的是只是添加这些babel方法并不能解决原版能够向低版本浏览器支持的能力,比如IE11就悲剧了。
所以,只能采取其他方式,即在GitHub上找到ElementUI——Dev源码,然后修改打包后直接替换lib文件里边的所有内容。
具体如何进行ElementUI的开发,官方有相应的介绍:https://github.com/ElemeFE/element/blob/master/.github/CONTRIBUTING.zh-CN.md
问题分析与解决方法
- 针对第一个问题,由于原生的树型组件(Tree)并没有提供对于Checkbox进行置灰的操作,但是通过观察Tree这个组件的源码,
- //tree-node.vue文件
- <template>
- // ...
- <el-checkbox
- v-if="showCheckbox"
- v-model="node.checked"
- :indeterminate="node.indeterminate"
- @change="handleCheckChange"
- @click.native.stop="handleUserClick">
- </el-checkbox>
- //...
- </template>
- <script type="text/jsx">
- //...
- import ElCheckbox from 'element-ui/packages/checkbox';
- //...
- </script>
我们很明显能够看出,其中使用的CheckBox是通过引入ElCheckbox这个组件来生成的,所以ElCheckBox这个组件时有disabled这个属性的,所以给饮用的CheckBox这个组件添加disabled为true即可。
- //tree-node.vue文件
- <el-checkbox
- v-if="showCheckbox"
- v-model="node.checked"
- :indeterminate="node.indeterminate"
- :disabled="checkboxDisabled"
- @change="handleCheckChange"
- @click.native.stop="handleUserClick">
- </el-checkbox>
并且可以通过props一层一层把设置的变量传递到tree-node.vue文件。并且tree组件的特点,tree-node里边还有下一层的tree-node,所以也要把checkboxDisabled这个属性进行递归传递。
- //tree-node.vue
- <template>
- //...
- <el-checkbox
- v-if="showCheckbox"
- v-model="node.checked"
- :indeterminate="node.indeterminate"
- :disabled="checkboxDisabled"
- @change="handleCheckChange"
- @click.native.stop="handleUserClick">
- </el-checkbox>
- <span
- v-if="node.loading"
- class="el-tree-node__loading-icon el-icon-loading">
- </span>
- <node-content :node="node"></node-content>
- </div>
- <el-collapse-transition>
- <div
- class="el-tree-node__children"
- v-show="expanded">
- <el-tree-node
- :checkboxDisabled="checkboxDisabled"
- :render-content="renderContent"
- v-for="child in node.childNodes"
- :key="getNodeKey(child)"
- :node="child"
- @node-expand="handleChildNodeExpand">
- </el-tree-node>
- </div>
- </el-collapse-transition>
- //...
- </template>
- <script type="text/jsx">
- import ElCollapseTransition from 'element-ui/src/transitions/collapse-transition';
- import ElCheckbox from 'element-ui/packages/checkbox';
- import emitter from 'element-ui/src/mixins/emitter';
- export default {
- name: 'ElTreeNode',
- componentName: 'ElTreeNode',
- mixins: [emitter],
- props: {
- node: {
- default() {
- return {};
- }
- },
- checkboxDisabled: Boolean,
- props: {},
- renderContent: Function
- }
- //...
- </script>
同时,tree.vue这个文件也要进行参数传递:
- //tree.vue文件
- <template>
- <div class="el-tree" :class="{ 'el-tree--highlight-current': highlightCurrent }">
- <el-tree-node
- v-for="child in root.childNodes"
- :checkboxDisabled="checkboxDisabled"
- :node="child"
- :props="props"
- :key="getNodeKey(child)"
- :render-content="renderContent"
- @node-expand="handleNodeExpand">
- </el-tree-node>
- <div class="el-tree__empty-block" v-if="!root.childNodes || root.childNodes.length === 0">
- <span class="el-tree__empty-text">{{ emptyText }}</span>
- </div>
- </div>
- </template>
- <script>
- //...
- props: {
- data: {
- type: Array
- },
- checkboxDisabled: Boolean,
- //...
- },
- //...
- </script>
当然,在使用tree这个组件的地方也相应的把属性传下去。
- //项目文件.vue
- <el-tree
- :data="allMenuPermissions"
- :checkboxDisabled=true
- default-expand-all
- show-checkbox
- node-key="funsflowId"
- ref="tree"
- highlight-current
- :props="defaultProps">
- </el-tree>
到现在为止,第一个问题解决了,通过打包验证能够实现对tree组件中的CheckBox进行置灰的操作了。
- 对于第二个问题,是由于数据量过大,如果将全部数据渲染到页面上,会导致节点数量过多,页面卡顿。
所以解决的办法就是要减少页面节点渲染,并且能够在进行搜索的时候能够对全量数据进行搜索。
找到动态生成每一项的穿梭框文件transfer-panel组件,
- //transfer-panel.vue文件
- <template>
- //...
- <el-checkbox-group
- v-model="checked"
- v-show="!hasNoMatch && data.length > 0"
- :class="{ 'is-filterable': filterable }"
- class="el-transfer-panel__list"
- :isShow="isShowItem(item,filteredData)">
- <el-checkbox
- class="el-transfer-panel__item"
- v-for="item in filteredData"
- :label="item[keyProp]"
- :disabled="item[disabledProp]"
- :key="item[keyProp]">
- <option-content :option="item"></option-content>
- </el-checkbox>
- //...
- </template>
首先,里边的<el-checkbox></el-checkbox>中的内容是要根据显示的数据个数进行动态循环生成。
要达到减少节点的目的,刚开始的思路是利用vue提供的v-if指令,当需要显示的数据长度超过100条是,
就将让v-if=false,达到不渲染当前节点的目的。
修改代码:
- //transfer-panel.vue文件
- <template>
- //...
- <el-checkbox-group
- v-model="checked"
- v-show="!hasNoMatch && data.length > 0"
- :class="{ 'is-filterable': filterable }"
- class="el-transfer-panel__list"
- :isShow="isShowItem(item,filteredData)">
- <el-checkbox
- class="el-transfer-panel__item"
- v-for="item in filteredData"
- v-if="showItem(item)"
- :label="item[keyProp]"
- :disabled="item[disabledProp]"
- :key="item[keyProp]">
- <option-content :option="item"></option-content>
- </el-checkbox>
- //...
- </template>
- <script>
- //...
- methods: {
- //...
- showItem(i){
- if(filteredData.indexOf(i) > 100){
- return false;
- } else {
- return true;
- }
- }
- //...
- }
- //...
- </script>
这样就可以根据数据渲染的数据在整体数据中的位置来判断,是否要渲染这条数据对应的节点。
这样的处理方式在高版本的处理器(chrome58以上)上是没有问题的,但是在低一点的版本的浏览器或者性能低一点的FireFox或者IE上还是会出现卡顿的现象。
通过查看节点,相对应的节点也是已经没有显示渲染了。但是没有渲染的部分莫名其妙的出现了很多的<!---->这样的注释内容。通过把HTML文件拷贝出来查看,发现文件总共大小有12M以上,由于动手吧<!---->以及换行和空格删除后,发现整个文件大小缩小为2M左右。
所以,基本可以肯定卡顿是由于渲染出来的HTML文件内容过多引起的。
大概估计这个由于Vue中的<template>标签引起的,虽然具体的内容节点没有渲染,
但是CheckBox这个组件的循环渲染也会出现很多的空的<template></template>,这个空标签就会渲染成<!--->;
通过在segmentfault上向询问,大家给出的建议是通过修改渲染的数据,只循环渲染前100条数据以达到目的。最后的实现方式也是这样做的。
采用这种方式就是要小心搜索的数据和最终渲染的数据要进行关联和解关联。
- //transfer-panel.vue文件
- <script>
- //...
- computed: {
- filteredData() {
- let arrData = this.data.filter(item => {
- if (typeof this.filterMethod === 'function') {
- return this.filterMethod(this.query, item);
- } else {
- const label = item[this.labelProp] || item[this.keyProp].toString();
- return label.toLowerCase().indexOf(this.query.toLowerCase()) > -1;
- }
- });
- if (arrData.length > 100) {
- this.showFilteredData = arrData.slice(0, 100);
- } else {
- this.showFilteredData = arrData;
- }
- return arrData;
- },
- }
- //...
- </script>
在渲染的数据生成的时候,就对this.showFilteredData这个要渲染的数据进行赋值。
如果总数据超过100条,那就截取前100条赋值为this.showFilteredData。
这样就能够保证最多有100条数据进行循环渲染。
最终解决
这样修改完代码,然后执行npm run dist,就可以再次生成lib文件中的代码。替换到相对应的文件element-ui中的lib中,就可以达到解决问题的目的。
修改ElementUI源码实践的更多相关文章
- 修改ElementUI源码
1.克隆ElementUI官方仓库代码到本地 https://github.com/ElemeFE/element 2.在cmd命令行安装依赖 1)找到代码文件夹 cd element 2)npm ...
- 修改elementUI源码新增组件/修改组件
前言 经常我们会遇到elementUI组件库期间有5%达不到我们想要的需求,第一我们重新写组件,第二我们改源码 安装element https://github.com/ElemeFE/element ...
- 修改ElementUI源码样式
参考:https://segmentfault.com/a/1190000010932321
- elementUI源码修改定制
1.修改elementUI源码 首先从Git上克隆代码或者下载代码包 进入文件夹打开终端或Git Bash Here,运行npm install 安装依赖包.npm run dev 打开网页http: ...
- 记一次ElementUI源码修改过程
修改目的 使用ElementUI el-tree过程发现选中节点,键盘移动上下键时(key down\key up)el-tree默认高亮移动的节点,业务上需要重写此事件. 从官网发现该事件没有暴露 ...
- [原]在win上编译 subversion 源码实践Tonyfield的专栏
(百度和网页的作者无关,不对其内容负责。百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面。) [原]在win上编译 subversion 源码实践 2013-6-9阅读400 评论0 (参考 ...
- ElementUI 源码定制防坑指南
背景 我司OA系统公文管理模块Office在线编辑使用的是金格IWebOffice中间件[PPAPI插件,通过<object>标签加载],IWebOffice在chrome中设置div盒子 ...
- 05.ElementUI源码学习:项目发布配置(github pages&npm package)
0x00.前言 书接上文.项目第一个组件已经封装好,说明文档也已编写好.下面需要将说明文档发布到外网上,以此来展示和推广项目,使用 Github Pages功能实现.同时将组件发布之 npm 上,方便 ...
- 修改FFMpeg源码—捕获丢包
概述 最近我们项目有一个需求就是解决客户端播放RTSP视频流花屏的问题,一般来说丢包就会引起花屏,导致客户端花屏的因素又有很多,比如说: 相机到服务器丢包 服务器到客户端丢包 等等... 其中服务器到 ...
随机推荐
- windows下Python 3.x图形图像处理库PIL的安装
图像处理是一门应用非常广的技术,而拥有非常丰富第三方扩展库的 Python 当然不会错过这一门盛宴.PIL (Python Imaging Library)是 Python 中最常用的图像处理库,目前 ...
- OVS 中的 upcall 线程
总体概览如下: 假设upcall handler线程有两个,vport有四个,那么每个vport下都将持有两个NetLink连接的信息,这两个NetLink连接将被用来上送upcall消息. 每个Ne ...
- Android WebView 不支持 H5 input type="file" 解决方法
最近因为赶项目进度,因此将本来要用原生控件实现的界面,自己做了H5并嵌入webview中.发现点击H5中 标签 不能打开android资源管理器. 通过网络搜索发现是因为 android webvie ...
- HTMLCollection 对象详解,以及为什么循环获取的dom合集操作可能会出现下标不正确的情况?
有时候循环dom合集,然后操作其中的某些dom之后,发现下标不正确了 比如我们要删除一个dom合集的时候: var selectDom = document.getElementsByClassNam ...
- Cookie的作用以及封装的方法
Cookie相当于本地储存(local Storage),也是一种储存信息的方式. 它通过 document.cookie ='name=value' //name name值 value value ...
- python编写知乎爬虫实践
爬虫的基本流程 网络爬虫的基本工作流程如下: 首先选取一部分精心挑选的种子URL 将种子URL加入任务队列 从待抓取URL队列中取出待抓取的URL,解析DNS,并且得到主机的ip,并将URL对应的网页 ...
- EJB基础知识
本人博客文章网址:https://www.peretang.com/basic-knowledge-of-ejb/ 什么是EJB 可移植的, 可重用的, 可伸缩的业务应用程序的平台 为什么选择EJB ...
- Layered Windows窗口的半透明效果
介绍: Layered Windows是windows窗口中的一类,提供类似半透明的效果(阿尔法混合).半透明效果是字面上有能看出来的,但实际上根据MSND,该类型的窗口还能更好的支持非矩形的窗口,使 ...
- Chapter 5:Spectral-Subtractive Algorithms
作者:桂. 时间:2017-05-24 10:06:39 主要是<Speech enhancement: theory and practice>的读书笔记,全部内容可以点击这里. 书中 ...
- Github 开源:高效好用的对象间属性拷贝工具:升讯威 Mapper( Sheng.Mapper)
Github 地址:https://github.com/iccb1013/Sheng.Mapper 对象属性值映射/拷贝工具.不需要创建映射规则,不要求对象类型一致,适用于简单直接的拷贝操作,可以全 ...