700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > vue + element 与 vue element admin 中 tab标签视图 页拖拽(拖动) sortablejs 插件案例

vue + element 与 vue element admin 中 tab标签视图 页拖拽(拖动) sortablejs 插件案例

时间:2022-07-21 08:57:25

相关推荐

vue + element 与 vue element admin 中 tab标签视图 页拖拽(拖动) sortablejs 插件案例

业务需求

公司有一堆tab签,每个tab签里展示对应的数据,方便拖拽更换位置实现el-tabs标签页下的el-tab-pane拖拽效果,可以使用第三方插件sortable进行实现

效果图

原位置

拖动

拖动后的位置

因为csdn不会上传gif动图,所以就截取几张图片来展示实现的成果,可以看后两张红色框圈中的数据,是我按下鼠标还没放开时候的位置,证明已经实现动态拖拽。废话不多说,直接贴代码。

npm安装sortable.js

npm install sortablejs --save

小案例

<!--tabOptionList为遍历的数组 手动给el-tabs添加class,方便找到拖拽的哪一行--><el-tabs class="tabSign"><el-tab-panev-for="item in tabOptionList":key="item.name":name="item.name" ></el-tab-pane></el-tabs>

//在script下导入import Sortable from "sortablejs"; //插件引入data() {return {tabOptionList: ['XXX','XXXX']}},mounted() {this.rowDrop()},//js逻辑片段(const el 必须找到自己拖拽的那一列 )methods: {//拖拽方法rowDrop() {const el = document.querySelector(".tabSign .el-tabs__nav"); //找到想要拖拽的那一列const _this = this;Sortable.create(el, {onEnd({newIndex, oldIndex }) {//oldIIndex拖放前的位置, newIndex拖放后的位置 //tabOptionList为遍历的tab签const currRow = _this.tabOptionList.splice(oldIndex, 1)[0]; //鼠标拖拽当前的el-tabs-pane_this.tabOptionList.splice(newIndex, 0, currRow); //tableData 是存放所以el-tabs-pane的数组},});},}

注意:

const el = document.querySelector('.tags-view-wrapper .el-scrollbar__wrap .el-scrollbar__view') // 自己项目里找到要拖拽的列。console.log(el) //打印一下,查看是否找对了

给 vue element admin 的标签视图添加拖拽功能

<template><div id="tags-view-container" class="tags-view-container"><scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll"><router-linkv-for="tag in visitedViews"ref="tag":key="tag.path":class="isActive(tag)?'active':''":to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"tag="span"class="tags-view-item"@click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"@contextmenu.prevent.native="openMenu(tag,$event)">{{ generateTitle(tag.title) }}<span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" /></router-link></scroll-pane><ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu"><li @click="refreshSelectedTag(selectedTag)">{{ $t('tagsView.refresh') }}</li><li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)">{{ $t('tagsView.close') }}</li><li @click="closeOthersTags">{{ $t('tagsView.closeOthers') }}</li><li @click="closeAllTags(selectedTag)">{{ $t('tagsView.closeAll') }}</li></ul></div></template><script>import ScrollPane from './ScrollPane'import {generateTitle } from '@/utils/i18n'import path from 'path'import Sortable from 'sortablejs' // 插件引入export default {components: {ScrollPane },data() {return {visible: false,top: 0,left: 0,selectedTag: {},affixTags: []}},computed: {visitedViews() {return this.$store.state.tagsView.visitedViews},routes() {return this.$store.state.permission.routes}},watch: {$route() {this.addTags()this.moveToCurrentTag()},visible(value) {if (value) {document.body.addEventListener('click', this.closeMenu)} else {document.body.removeEventListener('click', this.closeMenu)}}},mounted() {this.initTags()this.addTags()this.rowDrop()},methods: {// 拖拽方法rowDrop() {const el = document.querySelector('.tags-view-wrapper .el-scrollbar__wrap .el-scrollbar__view') // 找到想要拖拽的那一列console.log(el)const _this = thisSortable.create(el, {draggable: '.tags-view-item',onEnd({newIndex, oldIndex }) {// oldIIndex拖放前的位置, newIndex拖放后的位置 //visitedViews为遍历的tab签const currRow = _this.visitedViews.splice(oldIndex, 1)[0] // 鼠标拖拽当前的el-tabs-pane_this.visitedViews.splice(newIndex, 0, currRow) // tableData 是存放所以el-tabs-pane的数组}})},generateTitle, // generateTitle by vue-i18nisActive(route) {return route.path === this.$route.path},isAffix(tag) {return tag.meta && tag.meta.affix},filterAffixTags(routes, basePath = '/') {let tags = []routes.forEach(route => {if (route.meta && route.meta.affix) {const tagPath = path.resolve(basePath, route.path)tags.push({fullPath: tagPath,path: tagPath,name: route.name,meta: {...route.meta }})}if (route.children) {const tempTags = this.filterAffixTags(route.children, route.path)if (tempTags.length >= 1) {tags = [...tags, ...tempTags]}}})return tags},initTags() {const affixTags = this.affixTags = this.filterAffixTags(this.routes)for (const tag of affixTags) {// Must have tag nameif (tag.name) {this.$store.dispatch('tagsView/addVisitedView', tag)}}},addTags() {const {name } = this.$routeif (name) {this.$store.dispatch('tagsView/addView', this.$route)}return false},moveToCurrentTag() {const tags = this.$refs.tagthis.$nextTick(() => {for (const tag of tags) {if (tag.to.path === this.$route.path) {this.$refs.scrollPane.moveToTarget(tag)// when query is different then updateif (tag.to.fullPath !== this.$route.fullPath) {this.$store.dispatch('tagsView/updateVisitedView', this.$route)}break}}})},refreshSelectedTag(view) {this.$store.dispatch('tagsView/delCachedView', view).then(() => {const {fullPath } = viewthis.$nextTick(() => {this.$router.replace({path: '/redirect' + fullPath})})})},closeSelectedTag(view) {this.$store.dispatch('tagsView/delView', view).then(({visitedViews }) => {if (this.isActive(view)) {this.toLastView(visitedViews, view)}})},closeOthersTags() {this.$router.push(this.selectedTag)this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {this.moveToCurrentTag()})},closeAllTags(view) {this.$store.dispatch('tagsView/delAllViews').then(({visitedViews }) => {if (this.affixTags.some(tag => tag.path === view.path)) {return}this.toLastView(visitedViews, view)})},toLastView(visitedViews, view) {const latestView = visitedViews.slice(-1)[0]if (latestView) {this.$router.push(latestView.fullPath)} else {// now the default is to redirect to the home page if there is no tags-view,// you can adjust it according to your needs.if (view.name === 'Dashboard') {// to reload home pagethis.$router.replace({path: '/redirect' + view.fullPath })} else {this.$router.push('/')}}},openMenu(tag, e) {const menuMinWidth = 105const offsetLeft = this.$el.getBoundingClientRect().left // container margin leftconst offsetWidth = this.$el.offsetWidth // container widthconst maxLeft = offsetWidth - menuMinWidth // left boundaryconst left = e.clientX - offsetLeft + 15 // 15: margin rightif (left > maxLeft) {this.left = maxLeft} else {this.left = left}this.top = e.clientYthis.visible = truethis.selectedTag = tag},closeMenu() {this.visible = false},handleScroll() {this.closeMenu()}}}</script><style lang="scss" scoped>.tags-view-container {height: 34px;width: 100%;background: #fff;border-bottom: 1px solid #d8dce5;box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);.tags-view-wrapper {.tags-view-item {display: inline-block;position: relative;cursor: pointer;height: 26px;line-height: 26px;border: 1px solid #d8dce5;color: #495060;background: #fff;padding: 0 8px;font-size: 12px;margin-left: 5px;margin-top: 4px;&:first-of-type {margin-left: 15px;}&:last-of-type {margin-right: 15px;}&.active {background-color: #42b983;color: #fff;border-color: #42b983;&::before {content: '';background: #fff;display: inline-block;width: 8px;height: 8px;border-radius: 50%;position: relative;margin-right: 2px;}}}}.contextmenu {margin: 0;background: #fff;z-index: 3000;position: absolute;list-style-type: none;padding: 5px 0;border-radius: 4px;font-size: 12px;font-weight: 400;color: #333;box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);li {margin: 0;padding: 7px 16px;cursor: pointer;&:hover {background: #eee;}}}}</style><style lang="scss">//reset element css of el-icon-close.tags-view-wrapper {.tags-view-item {.el-icon-close {width: 16px;height: 16px;vertical-align: 2px;border-radius: 50%;text-align: center;transition: all .3s cubic-bezier(.645, .045, .355, 1);transform-origin: 100% 50%;&:before {transform: scale(.6);display: inline-block;vertical-align: -3px;}&:hover {background-color: #b4bccc;color: #fff;}}}}</style>

推荐看 很详细 -> sortable.js中文文档

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。