vue常用公共组件总结

您所在的位置:网站首页 举例写出asp的常用内置组件 vue常用公共组件总结

vue常用公共组件总结

2023-11-22 22:34| 来源: 网络整理| 查看: 265

在vue项目中,为了开发便利和可复用性的考虑。经常会封装一些比较常用的组件, 随着能力和水平的提高,封装的组件的功能会越来越多,内容也越来越多。 所以我觉得需要把这些常用的公共组件都提炼出来, 在今后再做项目或者review代码的时候都可以随时去进行查漏补缺和快速实现功能。 针对每个项目都重新写一套组件即费时,也可能仓促写的容易出现bug。 所以我打算在今后的工作中, 把自己认为封装的好一些的组件都记录在这篇博客里, 组件里的一些bug也会不断的修复, 功能也会不断扩展。 争取能做到一次封装, 多处复用, 且易于阅读,扩展性高。

1. 如何引用公共组件

组件可以通过局部引入和全局引入。

局部引入的步骤, 首先在需要引入的文件中import组件, 然后在components对象中注入, 最后在template中使用。 import partComponent from './partCompnent' components: {partComponent} 全局引入的步骤。 我比较喜欢, 新建一个文件夹,例importGlobalComp, 然后使用一个js方法去遍历这个文件夹下的所有.vue文件, 全局注册到vue中。 importGlobalComp.js // 全局注册全局组件 import Vue from 'vue'; const requireComponent = require.context( // 其组件目录的相对路径 // 这块是存放公共组件的文件目录, 是需要根据相应的路径更改的 '@/components', // 是否查询其子目录 true, // 匹配基础组件文件名的正则表达式 /\.vue$/ ); requireComponent.keys().forEach((fileName) => { // 获取组件配置 const componentConfig = requireComponent(fileName); // 获取组件的 PascalCase 命名 let componentName = // 获取和目录深度无关的文件名 fileName.replace(/^\.\//, '').replace(/\.\w+$/, ''); // 递归遍历文件下的.vue文件, 获取其文件名。 let reverseName = componentName.split('').reverse().join('') componentName = reverseName.split('/')[0].split('').reverse().join(''); // 全局注册组件 Vue.component( componentName, // 如果这个组件选项是通过 `export default` 导出的, // 那么就会优先使用 `.default`, // 否则回退到使用模块的根。 componentConfig.default || componentConfig ); });

main.js

// main.js中引入js文件 import '@/utils/importGlobalComp' 2. element-ui相关的二次封装组件 1. 对elment-ui的单日期组件 el-date-picker 进行的二次封装(element-ui) 父组件使用方法

解释: :val.sync是子传父方法$emit的语法糖, 传值方法相应的改为this.$emit("update:val", v)这种方式。 这样就不用再使用子传父后, 父通过方法去更新值的操作了。这样不仅省去了子传父数据更新的操作, 更重要的是利于组件的复用。 我们只需要调用组件即可实现数据的双向数据绑定, 不必再另写代码去处理组件内部的逻辑。

子组件的gDate.vue文件代码 {{title}}: export default { name: "GDate", props: { val: { type: [String, Date], default: "" }, title: { type: String, default: "" } }, watch: { val(e) { this.timePicker = e; } }, data() { return { timePicker: this.val, pickerOptions: { disabledDate(time) { return time.getTime() > Date.now(); }, shortcuts: [ { text: "今天", onClick(picker) { picker.$emit("pick", new Date()); } }, { text: "昨天", onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24); picker.$emit("pick", date); } }, { text: "一周前", onClick(picker) { const date = new Date(); date.setTime(date.getTime() - 3600 * 1000 * 24 * 7); picker.$emit("pick", date); } } ] } }; }, methods: { dateChange(v) { console.log('11111>11111'); console.log(v); this.timePicker = v; this.$emit("update:val", v); } } }; .title { margin-right: 10px; } 2. 对对elment-ui的双日期组件 el-date-picker 进行的二次封装(element-ui) 父组件使用方法

解释: :val.sync是子传父方法$emit的语法糖。 不必再进行子传父后, 父通过方法去更新date值的操作了。 title可写可不写。 可传值:: new Date() 和 2020-10-24 03:02:03 这种类型的数据。 如果想传递年月日, 修改value-format="yyyy-MM-dd"

子组件的gDoubleDate.vue文件代码 {{title}}: import moment from "moment"; export default { name: "GDoubleDate", props: { val: { default: "" }, title: { default: "" } }, watch: { val(e) { this.timePicker = e; } }, data() { return { timePicker: this.val, pickerOptions: { // 时间选择器时间段 shortcuts: [ { text: "本月", onClick(picker) { let start = moment( moment() .month(moment().month()) .startOf("month") .valueOf() )._d; let end = moment( moment() .month(moment().month()) .endOf("month") .valueOf() )._d; picker.$emit("pick", [start, new Date()]); } }, { text: "最近一周", onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 7); picker.$emit("pick", [start, end]); } }, { text: "最近一个月", onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 30); picker.$emit("pick", [start, end]); } }, { text: "最近三个月", onClick(picker) { const end = new Date(); const start = new Date(); start.setTime(start.getTime() - 3600 * 1000 * 24 * 90); picker.$emit("pick", [start, end]); } } ] } }; }, methods: { dateChange(v) { console.log('11111>11111'); console.log(v); this.timePicker = v; this.$emit("update:val", v); } } }; .title { margin-right: 10px; } 3. 点击回到顶部gBackToTop.vue

使用:

export default { name: 'BackToTop', props: { visibilityHeight: { type: Number, default: 400 }, backPosition: { type: Number, default: 0 }, customStyle: { type: Object, default: () => { return { right: '50px', bottom: '50px', width: '40px', height: '40px', zIndex: '10', opacity: 0.7, 'border-radius': '4px', 'line-height': '45px', background: '#e7eaf1' } } }, transitionName: { type: String, default: 'fade' } }, data() { return { visible: false, interval: null, isMoving: false } }, mounted() { window.addEventListener('scroll', this.handleScroll) }, beforeDestroy() { window.removeEventListener('scroll', this.handleScroll) if (this.interval) { clearInterval(this.interval) } }, methods: { handleScroll() { this.visible = window.pageYOffset > this.visibilityHeight }, backToTop() { if (this.isMoving) return const start = window.pageYOffset let i = 0 this.isMoving = true this.interval = setInterval(() => { const next = Math.floor(this.easeInOutQuad(10 * i, start, -start, 500)) if (next dom.currentStyle[attr] } else { return (dom, attr) => getComputedStyle(dom, false)[attr] } })() dialogHeaderEl.onmousedown = (e) => { // 鼠标按下,计算当前元素距离可视区的距离 const disX = e.clientX - dialogHeaderEl.offsetLeft const disY = e.clientY - dialogHeaderEl.offsetTop const dragDomWidth = dragDom.offsetWidth const dragDomHeight = dragDom.offsetHeight const screenWidth = document.body.clientWidth const screenHeight = document.body.clientHeight const minDragDomLeft = dragDom.offsetLeft const maxDragDomLeft = screenWidth - dragDom.offsetLeft - dragDomWidth const minDragDomTop = dragDom.offsetTop const maxDragDomTop = screenHeight - dragDom.offsetTop - dragDomHeight // 获取到的值带px 正则匹配替换 let styL = getStyle(dragDom, 'left') let styT = getStyle(dragDom, 'top') if (styL.includes('%')) { styL = +document.body.clientWidth * (+styL.replace(/\%/g, '') / 100) styT = +document.body.clientHeight * (+styT.replace(/\%/g, '') / 100) } else { styL = +styL.replace(/\px/g, '') styT = +styT.replace(/\px/g, '') } document.onmousemove = function(e) { // 通过事件委托,计算移动的距离 let left = e.clientX - disX let top = e.clientY - disY // 边界处理 if (-(left) > minDragDomLeft) { left = -minDragDomLeft } else if (left > maxDragDomLeft) { left = maxDragDomLeft } if (-(top) > minDragDomTop) { top = -minDragDomTop } else if (top > maxDragDomTop) { top = maxDragDomTop } // 移动当前元素 dragDom.style.cssText += `;left:${left + styL}px;top:${top + styT}px;` // emit onDrag event vnode.child.$emit('dragDialog') } document.onmouseup = function(e) { document.onmousemove = null document.onmouseup = null } } } }) 5. 远程可搜索的select /** * @描述 * 远程搜索input * @使用方法 * @param * * @LastEditTime: 最后更新时间 * 2022-04-01 * @Author: andy凌云 */ import { cusUserList } from '@/server/plateformApi' // 这是用户列表 export default { props: { sendLabel: { type: String, default: "label", }, // 取名id会报错 sendValue: { type: String, default: "id", }, sendName: { type: String, default: 'name' }, // 这里传递的是接口名称 sendType: { type: String, default: "cusUserList", }, sendList: { type: Array, default: () => [], }, }, data() { return { // tableData: [], tableData: [], sValue: [], saveData: [], isSelect: false, } }, watch: { sendList(val) { this._handleValue(val) }, sValue(newVal, oldVal) { if (!this.isSelect) { return } let differenceArr = newVal.concat(oldVal).filter(v => !newVal.includes(v) || !oldVal.includes(v)) let difference = differenceArr[0] // 新增 if (newVal.length > oldVal.length) { this.tableData.forEach(v => { if (v[this.sendValue] === difference) { let obj = { [this.sendValue]: v[this.sendValue], [this.sendLabel]: v[this.sendLabel], [this.sendName]: v[this.sendName], } this.saveData.push(obj); } }) } else { // 减少 let findIdx = this.saveData.findIndex(v => v[this.sendValue] === difference) this.saveData.splice(findIdx, 1); } console.log(`obj打印***** this.saveData ***** 107行 ~/kj/gaea-fe/src/components/autoImportComps/testComps/gRemoteSearch.vue 16:22:24`); console.log(JSON.stringify(this.saveData, null, '\t')); } }, created() { // this.sValue = this._handleValue(this.sendList); this._handleValue(this.sendList); }, mounted() { }, methods: { // 比较前后的值并生成add和delete的数组对象 _compareValueChange() { // 获取两个数组的差集 let toFaterArr = []; this.saveData.forEach((v, i) => { // 如果传递进来的sendList的长度为0, 那就全是add if (this.sendList.length === 0) { toFaterArr.push(this.changeValueType(v)); } else { // 如果saveData中的值sendList不存在, 则为 ADD let isHas = this.sendList.find(val => { return val.data[this.sendValue] === v[this.sendValue] }) if (!isHas) { toFaterArr.push(this.changeValueType(v)); } } }) // 遍历父组件传递过来的list。 如果在saveList中找不到就是删除。 this.sendList.forEach(v => { let isHas = this.saveData.find(item => { return item[this.sendValue] === v.data[this.sendValue]; }) if (!isHas) { toFaterArr.push(this.changeValueType(v, 'DELETE')); } }) return toFaterArr; }, changeValueType(item, type = 'ADD') { console.log(`obj打印***** item ***** 149行 ~/kj/gaea-fe/src/components/autoImportComps/testComps/gRemoteSearch.vue 16:47:36`); console.log(JSON.stringify(item, null, '\t')); let obj = { data: { [this.sendValue]: type === 'ADD' ? item[this.sendValue] : item.data[this.sendValue], [this.sendName]: type === 'ADD' ? item[this.sendName] : item.data[this.sendName], [this.sendLabel]: type === 'ADD' ? item[this.sendLabel] : item.data[this.sendLabel], }, opType: type, } return obj; }, changeVal(val1, val2) { this.isSelect = true; }, _handleValue(val) { if (val.length === 0) { this.sValue = [] this.tableData = []; return } let copyList = this.$pub.deepClone(val); this.sValue = []; copyList.forEach(v => { this.sValue.push(v.data.id); let obj = {} obj[this.sendLabel] = v.data[this.sendLabel] obj[this.sendValue] = v.data[this.sendValue] obj[this.sendName] = v.data[this.sendName]; this.tableData.push(obj); this.saveData = this.$pub.deepClone(this.tableData); }) }, async remoteMethod(query) { if (query !== '') { let sendParams = { size: 100, "queries": [ { "queryType": "like", "field": "word", "queryData": query } ], "current": 1, } let reqUrl = '' if (this.sendType === 'cusUserList') { reqUrl = cusUserList } this.$pub.initPage(this, sendParams, reqUrl) } else { this.tableData = []; } } } } .select_box ::v-deep .el-select { width: 400px !important; }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3