目录
1、Input 输入框
2、Table 表格
3、Tree 树形控件
4、Pagination 分页
5、Dialog 对话框
6、ECharts 图表
7、wangEditor 富文本编辑器
整理一下自己在 Vue2 项目中常用到的一些封装组件 :
大部分是结合 element-ui 组件库 进行的二次封装 :
饿了么组件库 => Element - The world's most popular Vue UI framework
通过鼠标或键盘输入字符
场景需求 : 输入框限制用户只能输入数字类型
开始封装 :
项目 / src / components / common / numInput.vue
项目 / src / utils / digitalInput.js 文件
/** 数字型输入框
* @param {} event 事件对象
* @param {} modelValue 输入框绑定值
* @return {} 处理好的内容
*/
// 限制用户只能输入数字
export const digitalInput = (event, modelValue) => {
// 限制用户输入非数字内容 且 不能以 0 开头
if (!/^[0-9]*[1-9][0-9]*$/.test(event)) {
modelValue = event.replace(/\D/g, "").replace(/^0/g, "");
}
console.log(modelValue, "封装函数");
return modelValue;
};
开始使用 :
项目 / src / views / edit / index.vue
用于展示多条结构类似的数据,可对数据进行排序、筛选、对比或其他自定义操作。
开始封装 :
项目 / src / components / common / publicTable.vue
{{ scope.$index + 1 }}
开始使用 :
项目 / src / views / list / index.vue
第二种封装写法 :
{{
scope.$index + 1
}}
{{ scope.row[item.field] }}
用清晰的层级结构展示信息,可展开或折叠。
项目 / src / utils / tools.js 文件
/**
* 数组去重
*/
const unique = function (arr) {
return arr.filter((item, index) => {
return arr.indexOf(item, 0) === index;
});
};
开始使用 :
项目 / src / views / index.vue
当数据量过多时,使用分页分解数据。
开始封装 :
项目 / src / components / page / index.vue
开始使用 :
项目 / src / views / list / index.vue
第二种封装方法 :
使用方法 :
在保留当前页面状态的情况下,告知用户并承载相关操作。
开始封装 :
项目 / src / components / common / publicDialog.vue
开始使用 :
项目 / src / views / submit / index.vue
选择用户组
添加用户组
删除用户组
上传分组文件
下载分组模板
一个基于 JavaScript 的开源可视化图表库
Apache ECharts
开始封装 :
项目 / src / components / echarts / echartsChart.vue
开源 Web 富文本编辑器,开箱即用,配置简单
wangEditor
安装 wangEditor
npm 安装
npm i wangeditor --save
注:wangeditor 全小写
package.json 文件
"wangeditor": "^4.7.11"
封装 wangEditor 组件(wangEditor.vue)
src / components / wangEditor / index.vue
this.editor.customConfig.uploadImgServer = Settings.apiUrl + ‘/api/CoreService/File/UploadFile’ // 配置服务器端地址,这个是处理图片上传问题的
src / components / wangEditor / fileMenu.js
/**
* editor: wangEditor 的实例
* editorSelector: wangEditor 挂载点的节点
* options: 一些配置
*/
import uploadFile from "./uploadFile";
import vue from "vue";
export default (editor, editorSelector, options) => {
editor.fileMenu = {
init: function (editor, editorSelector) {
const div = document.createElement("div");
div.className = "w-e-toolbar w-e-menu";
div.style.zIndex = 10001;
div.setAttribute("data-title", "附件");
const rdn = new Date().getTime();
div.onclick = function (e) {
if (e.stopPropagation) {
e.stopPropagation();
} else {
e.cancelBubble = true;
}
// document.getElementById(`up-${rdn}`).click()
};
const input = document.createElement("input");
input.type = "file";
input.name = "file";
input.id = `up-${rdn}`;
input.className = "upload-file-input";
div.innerHTML = ``;
div.appendChild(input);
editorSelector.getElementsByClassName("w-e-toolbar")[0].appendChild(div);
input.onchange = (e) => {
console.log(e, "change");
// 使用 uploadFile 上传文件
// uploadFile(e.target.files, {
// onOk: (data) => {
// console.log(data);
// // 可以使用 editor.txt.html(data) 进行更新
// },
// onFail: (err) => {
// console.log(err);
// },
// onprogress: (percent) => {
// console.log(percent);
// },
// });
uploadFile(e.target.files, {
onOk: (data) => {
// console.log(data, '文件上传');
const { code, result } = data || {};
if (code == 0) {
e.target.value = ""; // 解决 input onchange 事件第二次调不起的解决方法
let fileName = result.fileName.toLowerCase();
let fileIconUrl = ""; // 存放附件前面小 icon 地址的变量
let _index = fileName.lastIndexOf(".") + 1;
let fileDot = fileName.substring(_index, fileName.length);
if (fileDot == "doc") {
fileIconUrl =
"http://83.12.234.567:8080/icon_doc.gif";
} else if (fileDot == "txt") {
fileIconUrl =
"http://83.12.234.567:8080/icon_doc.gif";
} else if (fileDot == "xls" || fileDot == "xlsx") {
fileIconUrl =
"http://83.12.234.567:8080/icon_doc.gif";
}
editor.txt.append(
``
);
}
},
onFail: (err) => {
console.log(err);
},
onprogress: (percent) => {
console.log(percent);
},
});
};
},
};
// 创建完之后立即实例化
editor.fileMenu.init(editor, editorSelector);
};
src / components / wangEditor / uploadFile.js
import { message } from "element-ui";
import { uploadFileApi } from "@/api/listApi";
function uploadFile(files, options) {
if (!files || !files.length) {
return;
}
// let uploadFileServer = commonApi.imgUploadApi; // 文件上传地址
let uploadFileServer = uploadFileApi; // 文件上传地址
const maxSize = 100 * 1024 * 1024; // 100M
const maxSizeM = maxSize / 1000 / 1000;
const maxLength = 1;
const uploadFileName = "file";
const uploadFileParams = {};
const uploadFileParamsWithUrl = {};
const timeout = 5 * 60 * 1000; // 5 min
// ---------------------- 验证文件信息 ---------------------------
const resultFiles = [];
const errInfo = [];
for (let file of files) {
const name = file.name;
const size = file.size;
// chrome 低版本 name ===== undefined
if (!name || !size) return;
if (maxSize < size) {
// 上传附件过大
errInfo.push("\u3010" + name + "\u3011\u5927\u4E8E" + maxSizeM + "M");
return;
}
// 验证通过的加入结果列表
resultFiles.push(file);
}
// 抛出验证信息
if (errInfo.length) {
this._alert("附件验证未通过, \n" + errInfo.join("\n"));
return;
}
if (resultFiles.length > maxLength) {
this._alert("一次最多上传" + maxLength + "个文件");
return;
}
// ----------------------- 自定义上传 ----------------------
const formdata = new FormData();
for (let file of resultFiles) {
const name = uploadFileName || file.name;
formdata.append("file", file);
// formdata.append(name, file);
}
// 附件上传
uploadFileApi(fromdata)
.then((res) => {
options.onOk && options.onOk(res);
})
.catch((err) => {
options.onFail && options.onFail(err);
});
// // ----------------------- 上传附件 -------------------------
// if (uploadFileServer && typeof uploadFileServer === "string") {
// for (key in uploadFileParams) {
// val = encodeURIComponent(uploadFileParams[val]);
// formdata.append(key, val);
// }
// }
// // 定义 xhr
// const xhr = new XMLHttpRequest();
// xhr.open("POST", uploadFileServer);
// // 设置超时
// xhr.timeout = timeout;
// xhr.ontimeout = function () {
// if (options.timeout && typeof options.timeout === "function") {
// options.timeout(xhr, editor);
// }
// message.error("上传附件超时");
// };
// // 监控 progress
// if (xhr.upload) {
// xhr.upload.onprogress = function (e) {
// let percent = void 0;
// // 进度条
// if (e.lengthComputable) {
// percent = e.loaded / e.total;
// if (options.onprogress && typeof options.onprogress === "function") {
// options.onprogress(percent);
// }
// }
// };
// }
// // 返回数据
// xhr.onreadystatechange = function () {
// let result = void 0;
// if (xhr.status < 200 || xhr.status >= 300) {
// if (options.onFail && typeof options.onprogress === "function") {
// options.onFail(xhr, editor);
// }
// return;
// }
// result = xhr.responseText;
// if (
// (typeof result === "undefined" ? "undefined" : typeof result) !== "object"
// ) {
// try {
// result = JSON.parse(result);
// } catch (ex) {
// if (options.onFail && typeof options.onFail === "function") {
// options.onFail(xhr, editor, result);
// }
// return;
// }
// }
// const data = result || [];
// if (data.code == 0) {
// options.onOk && options.onOk(data.data);
// }
// };
// // 自定义 headers
// for (let key in uploadFileHeaders) {
// xhr.setRequestHeader(key, uploadFileHeaders[key]);
// }
// // 跨域传 token
// xhr.widthCredentials = false;
// // 发送请求
// xhr.send(formdata);
}
export default uploadFile;
导入并引用组件
src / views / edit / components / parameter.vue
展示效果