对比一
- 抽离前
<template> <div class="import-config-container" v-show="isShow"> <div class="import-config-alert"> <div class="close-import-config-alert" @click="closeAlert"></div> <div class="import-config-alert-title">导入配置</div> <div class="import-config-alert-remind">说明:需要上传之前保存导出的xxx.json配置文件,文件中的信息会完全覆盖当前信息</div> <form action="" class="form"> <label for="import_config_input" class="import-config-label"> 上传配置文件 <i v-if="hasFile == 1" class="fas fa-times-circle uploadErr uploadIcon"/> <i v-else-if="hasFile == 2" class="fas fa-check-circle uploadSuccess uploadIcon"/> </label> <input id="import_config_input" type="file" class="select-file" ref="inputFile" @change="fileChange"> </form> <lp-button type="primary" class="import-config-btn" @_click="importConfig">确认上传</lp-button> </div> </div> </template> <script> import {ref, inject} from 'vue' import lpButton from '../../public/lp-button/lp-button' export default { props: { isShow: { type: Boolean, default: true } }, components: { lpButton }, setup(props, {emit}) { const result = ref('none') // 导入的结果 const isUpload = ref(false) // 判断是否上传配置文件 const isImport = ref(false) // 判断配置是否导入成功 const isLoading = ref(false) // 判断按钮是否处于加载状态 const inputFile = ref(null) // 获取文件标签 const hasFile = ref(0) // 判断文件的传入情况。0:未传入 1: 格式错误 2:格式正确 const $message = inject('message') // 导入配置 function importConfig() { let reader = new FileReader() let files = inputFile.value.files if(hasFile.value == 0) { $message({ type: 'warning', content: '请先上传配置文件' }) } else if(hasFile.value == 1) { $message({ type: 'warning', content: '请上传正确格式的文件,例如xx.json' }) } else if(hasFile.value == 2) { reader.readAsText(files[0]) reader.onload = function() { let data = this.result window.localStorage.navInfos = data location.reload() } } } // 关闭弹窗 function closeAlert() { emit('closeImportConfigAlert', false) hasFile.value = 0 } function fileChange(e) { let files = e.target.files if(files.length === 0) { $message({ type: 'warning', content: '请先上传配置文件' }) } else { let targetFile = files[0] if(!/\.json$/.test(targetFile.name)) { hasFile.value = 1 $message({ type: 'warning', content: '请确认文件格式是否正确' }) } else { hasFile.value = 2 $message({ type: 'success', content: '文件格式正确' }) } } } return { result, isUpload, isImport, isLoading, importConfig, closeAlert, inputFile, fileChange, hasFile } } } </script>
- 抽离后
<template> <div class="import-config-container" v-show="isShowImportAlert"> <div class="import-config-alert"> <div class="close-import-config-alert" @click="handleImportConfigAlert(false)"></div> <div class="import-config-alert-title">导入配置</div> <div class="import-config-alert-remind">说明:需要上传之前保存导出的xxx.json配置文件,文件中的信息会完全覆盖当前信息</div> <form action="" class="form"> <label for="import_config_input" class="import-config-label"> 上传配置文件 <i v-if="hasFile == 1" class="fas fa-times-circle uploadErr uploadIcon"/> <i v-else-if="hasFile == 2" class="fas fa-check-circle uploadSuccess uploadIcon"/> </label> <input id="import_config_input" type="file" class="select-file" ref="inputFile" @change="fileChange"> </form> <lp-button type="primary" class="import-config-btn" @_click="importConfig">确认上传</lp-button> </div> </div> </template> <script> /* API */ import { inject } from 'vue' /* 组件 */ import lpButton from '@/components/public/lp-button/lp-button' /* 功能模块 */ import importConfigFunction from '@/use/importConfig' export default { components: { lpButton }, setup() { const $message = inject('message') const { isShowImportAlert, handleImportConfigAlert, result, isUpload, isImport, isLoading, importConfig, closeAlert, inputFile, fileChange, hasFile } = importConfigFunction($message) return { isShowImportAlert, handleImportConfigAlert, result, isUpload, isImport, isLoading, importConfig, closeAlert, inputFile, fileChange, hasFile } } } </script>
- 抽离出的代码文件
// 导入配置功能 import { ref } from 'vue' const isShowImportAlert = ref(false), // 导入配置弹框是否展示 result = ref('none'), // 导入的结果 isUpload = ref(false), // 判断是否上传配置文件 isImport = ref(false), // 判断配置是否导入成功 isLoading = ref(false), // 判断按钮是否处于加载状态 inputFile = ref(null), // 获取文件元素 hasFile = ref(0) // 判断文件的传入情况。0:未传入 1: 格式错误 2:格式正确 export default function importConfigFunction($message) { // 控制弹框的展示 function handleImportConfigAlert(value) { isShowImportAlert.value = value if(!value) hasFile.value = 0 } // 上传的文件内容发生改变 function fileChange(e) { let files = e.target.files if(files.length === 0) { $message({ type: 'warning', content: '请先上传配置文件' }) } else { let targetFile = files[0] if(!/\.json$/.test(targetFile.name)) { hasFile.value = 1 $message({ type: 'warning', content: '请确认文件格式是否正确' }) } else { hasFile.value = 2 $message({ type: 'success', content: '文件格式正确' }) } } } // 导入配置 function importConfig() { let reader = new FileReader() let files = inputFile.value.files if(hasFile.value == 0) { $message({ type: 'warning', content: '请先上传配置文件' }) } else if(hasFile.value == 1) { $message({ type: 'warning', content: '请上传正确格式的文件,例如xx.json' }) } else if(hasFile.value == 2) { reader.readAsText(files[0]) reader.onload = function() { let data = this.result window.localStorage.navInfos = data location.reload() } } } return { isShowImportAlert, result, isUpload, isImport, isLoading, inputFile, hasFile, handleImportConfigAlert, fileChange, importConfig, } }
对比二
- 抽离前
<template> <!-- 此处因代码太多,暂时省略,详情可以点击文末的项目源码查看 --> </template> <script> import {ref, inject} from 'vue' import {useStore} from 'vuex' import urlAlert from '../public/urlAlert/urlAlert' import tagAlert from '../public/tabAlert/tabAlert' import carousel from './childCpn/carousel' import search from './childCpn/search' import { exchangeElements } from '../../utils/utils' <script> export default { components: { urlAlert, tagAlert, carousel, search, }, setup() { const store = useStore() const catalogue = store.state.catalogue const moduleUrl = store.state.moduleUrl const moduleSearch = store.state.moduleSearch const $message = inject('message') const $confirm = inject('confirm') const editWhich = ref(-1) // 弹出添加URL的框 function addMoreUrl(id) { store.commit('changeUrlInfo', [ {key: 'isShow', value: true}, {key: 'whichTag', value: id}, {key: 'alertType', value: '新增网址'} ]) } // 处理无icon或icon加载失败的图片,令其使用默认svg图标 function imgLoadErr(e) { let el = e.target el.style.display = 'none' el.nextSibling.style.display = 'inline-block' } function imgLoadSuccess(e) { let el = e.target el.style.display = 'inline-block' el.nextSibling.style.display = 'none' } // 进入编辑状态 function enterEdit(id) { if(id != editWhich.value) { editWhich.value = id } else { editWhich.value = -1 } } // 修改标签弹框弹出 function editTagAlertShow(tab) { store.commit('changeTabInfo', [ {key: 'isShowAddTabAlert', value: true}, {key: 'tagName', value: tab.name}, {key: 'trueIcon', value: tab.icon}, {key: 'isSelected', value: true}, {key: 'currentIcon', value: tab.icon}, {key: 'id', value: tab.id}, {key: 'alertType', value: '修改标签'} ]) } // 删除标签以及标签下的所有网址 function deleteTag(id) { $confirm({ content: '确定删除该标签以及该标签下所有网址吗?' }) .then(() => { store.commit('remove', id) $message({ type: 'success', content: '标签页及子网址删除成功' }) }) .catch(() => {}) } // 删除某个网址 function deleteUrl(id) { $confirm({ content: '确定删除该网址吗?' }) .then(() => { store.commit('remove', id) $message({ type: 'success', content: '网址删除成功' }) }) .catch(() => {}) } // 弹出修改URL的弹框 function editUrl(url) { store.commit('changeUrlInfo', [ {key: 'url', value: url.url}, {key: 'icon', value: url.icon}, {key: 'id', value: url.id}, {key: 'name', value: url.name}, {key: 'isShow', value: true}, {key: 'alertType', value: '修改网址'} ]) } function judgeTabIsShow(i) { const URLS = catalogue[i]['URLS'] let length = URLS.length for(let j = 0; j < length; j++) { if(moduleSearch.searchWord == '') return false; else if(URLS[j].name.toLowerCase().indexOf(moduleSearch.searchWord.toLowerCase()) !== -1) return true; } return false } function judgeUrlIsShow(i, j) { const url = catalogue[i]['URLS'][j] if(url.name.toLowerCase().indexOf(moduleSearch.searchWord.toLowerCase()) !== -1) return true; return false; } let elementNodeDragged = null // 被移动的地址框元素 let elementNodeLocated = null // 移入的地址框元素 let draggedId = -1 // 被移动地址框的id // 地址框开始拖拽 function urlBoxDragStart(e) { const el = e.target if(el.nodeName !== 'LI') return; // 记录当前被拖拽地址框元素 elementNodeDragged = el // 将被拖拽对象隐藏 el.style.display = 'fixed' el.style.opacity = 0 } // 地址框拖拽结束 function urlBoxDragEnd(e) { let el = e.target el.style.display = 'inline-block' el.style.opacity = 1 // 获取当前正在编辑标签中所有url的排序 let timer = setTimeout(() => { const result = [] const children = elementNodeLocated.parentNode.children let length = children.length for(let i = 0; i < length - 1; i++) { result.push(children[i].getAttribute('data-id')) } store.commit('dragEndToUpdate', {tabId: editWhich.value, result}) clearTimeout(timer) }, 500) } // 被拖动的地址框触碰到其它的地址框 function urlBoxEnter(e, tabId) { if(tabId != editWhich.value) return; let el = e.target while(el.nodeName !== 'LI') el = el.parentNode; // 若子元素触发dragenter事件,则查找到父元素li标签 if(el === elementNodeDragged) return; // 避免自己拖拽进入自己的情况 if(elementNodeLocated !== el) elementNodeLocated = el // 记录被移入的地址框元素 exchangeElements(elementNodeDragged, el) // 地址框位置互换 } return { catalogue, addMoreUrl, moduleUrl, moduleSearch, imgLoadErr, imgLoadSuccess, enterEdit, editTagAlertShow, deleteTag, deleteUrl, editUrl, editWhich, judgeTabIsShow, judgeUrlIsShow, urlBoxDragStart, urlBoxDragEnd, urlBoxEnter, } } } </script>
- 抽离后
<template> <!-- 此处因代码太多,暂时省略,详情可以点击文末的项目源码查看 --> </template> <script> /* API */ import { inject } from 'vue' import { useStore } from 'vuex' /* 组件 */ import urlAlert from '@/components/public/urlAlert/index' import tabAlert from '@/components/public/tabAlert/index' import carousel from './carousel' import search from './search' /* 功能模块 */ import baseFunction from '@/use/base' import editFunction from '@/use/edit' import urlAlertFunction from '@/use/urlAlert' import tabAlertFunction from '@/use/tabAlert' import searchFunction from '@/use/search' export default { components: { urlAlert, tabAlert, carousel, search, }, setup() { const catalogue = useStore().state.catalogue const $message = inject('message') const $confirm = inject('confirm') // 一些基础的方法 let { imgLoadErr, imgLoadSuccess } = baseFunction() // url框编辑下的相关变量及功能 let { editWhich, handleEdit, deleteTab, deleteUrl, urlBoxDragStart, urlBoxDragEnd, urlBoxEnter } = editFunction($message, $confirm) // 弹出 “新增”、“修改” url弹框 let { showNewUrlAlert, showEditUrlAlert } = urlAlertFunction() // 搜索功能相关的变量及方法 let { moduleSearch, judgeTabIsShow, judgeUrlIsShow } = searchFunction() // 展示修改tab的弹框 let { showEditAddTab } = tabAlertFunction() return { catalogue, showNewUrlAlert, moduleSearch, imgLoadErr, imgLoadSuccess, handleEdit, showEditAddTab, deleteTab, deleteUrl, showEditUrlAlert, editWhich, judgeTabIsShow, judgeUrlIsShow, urlBoxDragStart, urlBoxDragEnd, urlBoxEnter, } } } </script>
- 抽离出的代码文件(此处涉及到很多个模块,因此只展示两个吧)
// 搜索功能 import { } from 'vue' import store from '@/store/index' // 变量 const moduleSearch = store.state.moduleSearch // 搜索相关的全局状态 export default function searchFunction() { // 搜索框的输入改变 function inputSearchContent(value) { store.commit('changeSearchWord', value) } // 控制搜索框的展示 function handleSearchBox() { if(moduleSearch.isSearch) { store.commit('changeIsSearch', false) store.commit('changeSearchWord', '') } else { store.commit('changeIsSearch', true) } } // 判断标签是否显示 function judgeTabIsShow(i) { return store.getters.judgeTabIsShow(i) } // 判断url是否显示 function judgeUrlIsShow(i, j) { return store.getters.judgeUrlIsShow(i, j) } return { moduleSearch, inputSearchContent, handleSearchBox, judgeTabIsShow, judgeUrlIsShow, } }
// url框的拖拽排列 import { ref } from 'vue' import { exchangeElements, debounce } from '@/utils/utils' import store from '@/store/index' //变量 let elementNodeDragged = null, // 被移动的地址框元素 elementNodeLocated = null, // 移入的地址框元素 editWhich = ref(-1) // 记录正在编辑的tab索引 export default function editFunction($message, $confirm) { // 控制编辑状态 function handleEdit(id) { if(id != editWhich.value) { editWhich.value = id } else { editWhich.value = -1 } } // 删除标签以及标签下的所有网址 function deleteTab(id) { $confirm({ content: '确定删除该标签以及该标签下所有网址吗?' }) .then(() => { store.commit('remove', id) $message({ type: 'success', content: '标签页及子网址删除成功' }) }) .catch(() => {}) } // 删除某个网址 function deleteUrl(id) { $confirm({ content: '确定删除该网址吗?' }) .then(() => { store.commit('remove', id) $message({ type: 'success', content: '网址删除成功' }) }) .catch(() => {}) } // 地址框开始拖拽 function urlBoxDragStart(e) { const el = e.target if(el.nodeName !== 'LI') return; // 记录当前被拖拽地址框元素 elementNodeDragged = el // 将被拖拽对象隐藏 el.style.display = 'fixed' el.style.opacity = 0 } // 拖拽后更新Vuex中的正确排序 let dragEndToUpdate = debounce(function() { // 获取当前正在编辑标签中所有url的排序 const result = [] const children = elementNodeLocated.parentNode.children let length = children.length for(let i = 0; i < length - 1; i++) { result.push(children[i].getAttribute('data-id')) } store.commit('dragEndToUpdate', {tabId: editWhich.value, result}) }, 500) // 地址框拖拽结束 function urlBoxDragEnd(e) { let el = e.target el.style.display = 'inline-block' el.style.opacity = 1 dragEndToUpdate() } // 被拖动的地址框触碰到其它的地址框 function urlBoxEnter(e, tabId) { if(tabId != editWhich.value) return; let el = e.target while(el.nodeName !== 'LI') el = el.parentNode; // 若子元素触发dragenter事件,则查找到父元素li标签 if(el === elementNodeDragged) return; // 避免自己拖拽进入自己的情况 if(elementNodeLocated !== el) elementNodeLocated = el // 记录被移入的地址框元素 exchangeElements(elementNodeDragged, el) // 地址框位置互换 } return { editWhich, handleEdit, deleteTab, deleteUrl, urlBoxDragStart, urlBoxDragEnd, urlBoxEnter, } }
最后
细心的小伙伴应该发现了,刚才给大家展示的代码中,有一段是各种拖拽的实现方法,没错!!我在闲暇之余给我的项目加上了编辑模式下的 拖拽排列功能 ,也算是完成了之前大家对我提的建议之一啦,欢迎各位前去体验新功能~
项目体验链接:http://lpyexplore.gitee.io/nav-infos/
在体验完后,希望有心的小伙伴们能在github
上给我提提Issues
,我看到会第一时间回复的(如果催我做账号功能的小伙伴多,我后期可能会考虑加上)
项目源码链接:https://github.com/Lpyexplore/nav-url
(欢迎各位Star,多提意见,多交流啊~)
本文所阐述的代码抽离方法是我改过很多遍后定下来的,不知道后面还会有什么问题,但目前看来,对于以后的维护和管理应该是会方便很多的,如果大家有更好的意见或想法,可以留下评论,或者加我vx:Lpyexplore333
私底下交流
最后谢谢各位的耐心观看