Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
W
weixin-vue
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
weixin-vue
Commits
a9a7d704
Commit
a9a7d704
authored
Jan 30, 2019
by
fangzhipeng
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
初步让 ele-ui tabs 支持拖拽排序
parent
b66b054a
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
515 additions
and
8 deletions
+515
-8
.babelrc
.babelrc
+3
-2
index.html
index.html
+2
-1
package.json
package.json
+11
-5
src/components/Drag.vue
src/components/Drag.vue
+70
-0
src/components/tabs/tab-bar.vue
src/components/tabs/tab-bar.vue
+45
-0
src/components/tabs/tab-nav.vue
src/components/tabs/tab-nav.vue
+194
-0
src/components/tabs/tab-pane.vue
src/components/tabs/tab-pane.vue
+52
-0
src/components/tabs/tabs.vue
src/components/tabs/tabs.vue
+132
-0
src/router/index.js
src/router/index.js
+6
-0
No files found.
.babelrc
View file @
a9a7d704
{
"presets": [
["env", { "modules": false }],
"stage-2"
"stage-2",
"es2015"
],
"plugins": ["transform-runtime"],
"plugins": ["transform-runtime"
, "transform-vue-jsx"
],
"comments": false,
"env": {
"test": {
...
...
index.html
View file @
a9a7d704
...
...
@@ -7,7 +7,8 @@
<script
src=
"https://cdn.bootcss.com/jquery.scrollbar/0.2.11/jquery.scrollbar.js"
></script>
<link
href=
"https://cdn.bootcss.com/jquery.scrollbar/0.2.11/jquery.scrollbar.css"
rel=
"stylesheet"
>
</head>
<body
style=
"height: 100%; margin: 0px; background: #F9FAFC; overflow: hidden; background: #f5f5f5 url(/static/bg.jpg) no-repeat center; background-size: cover;"
>
<!--<body style="height: 100%; margin: 0px; background: #F9FAFC; overflow: hidden; background: #f5f5f5 url(/static/bg.jpg) no-repeat center; background-size: cover;">-->
<dody>
<div
id=
"app"
></div>
<!-- built files will be auto injected -->
</body>
...
...
package.json
View file @
a9a7d704
...
...
@@ -10,17 +10,23 @@
"build"
:
"node build/build.js"
},
"dependencies"
:
{
"
axios
"
:
"
^0.16.2
"
,
"
element-ui
"
:
"
^1.0.0
"
,
"
sortablejs
"
:
"
^1.8.1
"
,
"
vue
"
:
"
^2.2.6
"
,
"
vue-router
"
:
"
^2.3.1
"
,
"
axios
"
:
"
^0.16.2
"
,
"
element-ui
"
:
"
^1.0.0
"
"
vuedraggable
"
:
"
^2.17.0
"
},
"devDependencies"
:
{
"
autoprefixer
"
:
"
^6.7.2
"
,
"
babel-core
"
:
"
^6.22.1
"
,
"
babel-helper-vue-jsx-merge-props
"
:
"
^2.0.3
"
,
"
babel-loader
"
:
"
^6.2.10
"
,
"
babel-plugin-syntax-jsx
"
:
"
^6.18.0
"
,
"
babel-plugin-transform-runtime
"
:
"
^6.22.0
"
,
"
babel-plugin-transform-vue-jsx
"
:
"
^3.7.0
"
,
"
babel-preset-env
"
:
"
^1.3.2
"
,
"
babel-preset-es2015
"
:
"
^6.24.1
"
,
"
babel-preset-stage-2
"
:
"
^6.22.0
"
,
"
babel-register
"
:
"
^6.22.0
"
,
"
chalk
"
:
"
^1.1.3
"
,
...
...
@@ -34,18 +40,18 @@
"
friendly-errors-webpack-plugin
"
:
"
^1.1.3
"
,
"
html-webpack-plugin
"
:
"
^2.28.0
"
,
"
http-proxy-middleware
"
:
"
^0.17.3
"
,
"
webpack-bundle-analyzer
"
:
"
^2.2.1
"
,
"
semver
"
:
"
^5.3.0
"
,
"
shelljs
"
:
"
^0.7.6
"
,
"
opn
"
:
"
^4.0.2
"
,
"
optimize-css-assets-webpack-plugin
"
:
"
^1.3.0
"
,
"
ora
"
:
"
^1.2.0
"
,
"
rimraf
"
:
"
^2.6.0
"
,
"
semver
"
:
"
^5.3.0
"
,
"
shelljs
"
:
"
^0.7.6
"
,
"
url-loader
"
:
"
^0.5.8
"
,
"
vue-loader
"
:
"
^11.3.4
"
,
"
vue-style-loader
"
:
"
^2.0.5
"
,
"
vue-template-compiler
"
:
"
^2.2.6
"
,
"
webpack
"
:
"
^2.3.3
"
,
"
webpack-bundle-analyzer
"
:
"
^2.2.1
"
,
"
webpack-dev-middleware
"
:
"
^1.10.0
"
,
"
webpack-hot-middleware
"
:
"
^2.18.0
"
,
"
webpack-merge
"
:
"
^4.1.0
"
...
...
src/components/Drag.vue
0 → 100644
View file @
a9a7d704
<
template
>
<div>
<my-tabs
type=
"border-card"
v-model=
"editableTabsValue"
editable
@
edit=
"handleTabsEdit"
>
<my-tab-pane
label=
"用户管理"
>
用户管理
</my-tab-pane>
<my-tab-pane
label=
"配置管理"
>
配置管理
</my-tab-pane>
<my-tab-pane
label=
"角色管理"
>
角色管理
</my-tab-pane>
<my-tab-pane
label=
"定时任务补偿"
>
定时任务补偿
</my-tab-pane>
</my-tabs>
</div>
</
template
>
<
script
>
import
draggable
from
'
vuedraggable
'
import
Sortable
from
'
sortablejs
'
import
MyTabs
from
'
./tabs/tabs
'
import
MyTabPane
from
'
./tabs/tab-pane
'
export
default
{
name
:
"
drag
"
,
components
:
{
draggable
,
Sortable
,
MyTabPane
,
MyTabs
},
data
:
function
()
{
return
{
myArray
:
[{
id
:
1
,
name
:
"
用户管理
"
},
{
id
:
1
,
name
:
"
配置管理
"
},
{
id
:
1
,
name
:
"
角色管理
"
},
{
id
:
1
,
name
:
"
定时任务补偿
"
,
active
:
true
}]
}
},
methods
:
{
getClass
:
function
(
item
)
{
return
"
el-tabs__item is-top
"
+
(
item
.
active
?
"
is-active
"
:
""
)
},
clickTab
:
function
(
target
)
{
if
(
target
.
active
)
{
return
;
}
this
.
myArray
.
forEach
((
item
,
index
)
=>
{
item
.
active
=
false
;
this
.
$set
(
this
.
myArray
,
index
,
item
);
});
console
.
log
(
this
.
myArray
)
target
.
active
=
true
;
}
}
}
</
script
>
<
style
>
*
{
outline
:
none
;
}
</
style
>
src/components/tabs/tab-bar.vue
0 → 100644
View file @
a9a7d704
<
template
>
<div
class=
"el-tabs__active-bar"
:style=
"barStyle"
></div>
</
template
>
<
script
>
export
default
{
name
:
'
TabBar
'
,
props
:
{
tabs
:
Array
},
computed
:
{
barStyle
:
{
cache
:
false
,
get
()
{
if
(
!
this
.
$parent
.
$refs
.
tabs
)
return
{};
let
style
=
{};
let
offset
=
0
;
let
tabWidth
=
0
;
this
.
tabs
.
every
((
tab
,
index
)
=>
{
let
$el
=
this
.
$parent
.
$refs
.
tabs
[
index
];
if
(
!
$el
)
{
return
false
;
}
if
(
!
tab
.
active
)
{
offset
+=
$el
.
clientWidth
;
return
true
;
}
else
{
tabWidth
=
$el
.
clientWidth
;
return
false
;
}
});
const
transform
=
`translateX(
${
offset
}
px)`
;
style
.
width
=
tabWidth
+
'
px
'
;
style
.
transform
=
transform
;
style
.
msTransform
=
transform
;
style
.
webkitTransform
=
transform
;
return
style
;
}
}
}
};
</
script
>
src/components/tabs/tab-nav.vue
0 → 100644
View file @
a9a7d704
<
script
>
import
TabBar
from
'
./tab-bar
'
;
import
{
addResizeListener
,
removeResizeListener
}
from
'
element-ui/src/utils/resize-event
'
;
import
draggable
from
'
vuedraggable
'
;
import
Sortable
from
'
sortablejs
'
;
function
noop
()
{}
export
default
{
name
:
'
TabNav
'
,
components
:
{
TabBar
,
draggable
,
Sortable
},
props
:
{
panes
:
Array
,
currentName
:
String
,
editable
:
Boolean
,
onTabClick
:
{
type
:
Function
,
default
:
noop
},
onTabRemove
:
{
type
:
Function
,
default
:
noop
},
type
:
String
},
data
()
{
return
{
scrollable
:
false
,
navStyle
:
{
transform
:
''
}
};
},
methods
:
{
scrollPrev
()
{
const
containerWidth
=
this
.
$refs
.
navScroll
.
offsetWidth
;
const
currentOffset
=
this
.
getCurrentScrollOffset
();
if
(
!
currentOffset
)
return
;
let
newOffset
=
currentOffset
>
containerWidth
?
currentOffset
-
containerWidth
:
0
;
this
.
setOffset
(
newOffset
);
},
scrollNext
()
{
const
navWidth
=
this
.
$refs
.
nav
.
offsetWidth
;
const
containerWidth
=
this
.
$refs
.
navScroll
.
offsetWidth
;
const
currentOffset
=
this
.
getCurrentScrollOffset
();
if
(
navWidth
-
currentOffset
<=
containerWidth
)
return
;
let
newOffset
=
navWidth
-
currentOffset
>
containerWidth
*
2
?
currentOffset
+
containerWidth
:
(
navWidth
-
containerWidth
);
this
.
setOffset
(
newOffset
);
},
scrollToActiveTab
()
{
if
(
!
this
.
scrollable
)
return
;
const
nav
=
this
.
$refs
.
nav
;
const
activeTab
=
this
.
$el
.
querySelector
(
'
.is-active
'
);
const
navScroll
=
this
.
$refs
.
navScroll
;
const
activeTabBounding
=
activeTab
.
getBoundingClientRect
();
const
navScrollBounding
=
navScroll
.
getBoundingClientRect
();
const
navBounding
=
nav
.
getBoundingClientRect
();
const
currentOffset
=
this
.
getCurrentScrollOffset
();
let
newOffset
=
currentOffset
;
if
(
activeTabBounding
.
left
<
navScrollBounding
.
left
)
{
newOffset
=
currentOffset
-
(
navScrollBounding
.
left
-
activeTabBounding
.
left
);
}
if
(
activeTabBounding
.
right
>
navScrollBounding
.
right
)
{
newOffset
=
currentOffset
+
activeTabBounding
.
right
-
navScrollBounding
.
right
;
}
if
(
navBounding
.
right
<
navScrollBounding
.
right
)
{
newOffset
=
nav
.
offsetWidth
-
navScrollBounding
.
width
;
}
this
.
setOffset
(
Math
.
max
(
newOffset
,
0
));
},
getCurrentScrollOffset
()
{
const
{
navStyle
}
=
this
;
return
navStyle
.
transform
?
Number
(
navStyle
.
transform
.
match
(
/translateX
\(
-
(\d
+
(\.\d
+
)
*
)
px
\)
/
)[
1
])
:
0
;
},
setOffset
(
value
)
{
this
.
navStyle
.
transform
=
`translateX(-
${
value
}
px)`
;
},
update
()
{
const
navWidth
=
this
.
$refs
.
nav
.
offsetWidth
;
const
containerWidth
=
this
.
$refs
.
navScroll
.
offsetWidth
;
const
currentOffset
=
this
.
getCurrentScrollOffset
();
if
(
containerWidth
<
navWidth
)
{
const
currentOffset
=
this
.
getCurrentScrollOffset
();
this
.
scrollable
=
this
.
scrollable
||
{};
this
.
scrollable
.
prev
=
currentOffset
;
this
.
scrollable
.
next
=
currentOffset
+
containerWidth
<
navWidth
;
if
(
navWidth
-
currentOffset
<
containerWidth
)
{
this
.
setOffset
(
navWidth
-
containerWidth
);
}
}
else
{
this
.
scrollable
=
false
;
if
(
currentOffset
>
0
)
{
this
.
setOffset
(
0
);
}
}
}
},
updated
()
{
this
.
update
();
},
render
(
h
)
{
const
{
type
,
panes
,
editable
,
onTabClick
,
onTabRemove
,
navStyle
,
scrollable
,
scrollNext
,
scrollPrev
}
=
this
;
const
scrollBtn
=
scrollable
?
[
<
span
class
=
{[
'
el-tabs__nav-prev
'
,
scrollable
.
prev
?
''
:
'
is-disabled
'
]}
on
-
click
=
{
scrollPrev
}
><
i
class
=
"
el-icon-arrow-left
"
><
/i></
span
>
,
<
span
class
=
{[
'
el-tabs__nav-next
'
,
scrollable
.
next
?
''
:
'
is-disabled
'
]}
on
-
click
=
{
scrollNext
}
><
i
class
=
"
el-icon-arrow-right
"
><
/i></
span
>
]
:
null
;
const
tabs
=
this
.
_l
(
panes
,
(
pane
,
index
)
=>
{
let
tabName
=
pane
.
name
||
pane
.
index
||
index
;
const
closable
=
pane
.
isClosable
||
editable
;
pane
.
index
=
`
${
index
}
`
;
const
btnClose
=
closable
?
<
span
class
=
"
el-icon-close
"
on
-
click
=
{(
ev
)
=>
{
onTabRemove
(
pane
,
ev
);
}}
><
/span
>
:
null
;
const
tabLabelContent
=
pane
.
$slots
.
label
||
pane
.
label
;
return
(
<
div
class
=
{{
'
el-tabs__item
'
:
true
,
'
is-active
'
:
pane
.
active
,
'
is-disabled
'
:
pane
.
disabled
,
'
is-closable
'
:
closable
}}
ref
=
"
tabs
"
refInFor
on
-
click
=
{(
ev
)
=>
{
onTabClick
(
pane
,
tabName
,
ev
);
}}
>
{
tabLabelContent
}
{
btnClose
}
<
/div
>
);
});
return
(
<
div
class
=
{[
'
el-tabs__nav-wrap
'
,
scrollable
?
'
is-scrollable
'
:
''
]}
>
{
scrollBtn
}
<
div
class
=
{[
'
el-tabs__nav-scroll
'
]}
ref
=
"
navScroll
"
>
<
draggable
class
=
"
el-tabs__nav
"
ref
=
"
nav
"
style
=
{
navStyle
}
>
{
!
type
?
<
tab
-
bar
tabs
=
{
panes
}
><
/tab-bar> : null
}
{
tabs
}
<
/draggable
>
<
/div
>
<
/div
>
);
},
mounted
()
{
addResizeListener
(
this
.
$el
,
this
.
update
);
},
beforeDestroy
()
{
if
(
this
.
$el
&&
this
.
update
)
removeResizeListener
(
this
.
$el
,
this
.
update
);
}
};
</
script
>
src/components/tabs/tab-pane.vue
0 → 100644
View file @
a9a7d704
<
template
>
<div
class=
"el-tab-pane"
v-show=
"active"
>
<slot></slot>
</div>
</
template
>
<
script
>
export
default
{
name
:
'
MyTabPane
'
,
componentName
:
'
MyTabPane
'
,
props
:
{
label
:
String
,
labelContent
:
Function
,
name
:
String
,
closable
:
Boolean
,
disabled
:
Boolean
},
data
()
{
return
{
index
:
null
};
},
computed
:
{
isClosable
()
{
return
this
.
closable
||
this
.
$parent
.
closable
;
},
active
()
{
return
this
.
$parent
.
currentName
===
(
this
.
name
||
this
.
index
);
}
},
mounted
()
{
this
.
$parent
.
addPanes
(
this
);
},
destroyed
()
{
if
(
this
.
$el
&&
this
.
$el
.
parentNode
)
{
this
.
$el
.
parentNode
.
removeChild
(
this
.
$el
);
}
this
.
$parent
.
removePanes
(
this
);
},
watch
:
{
label
()
{
this
.
$parent
.
$forceUpdate
();
}
}
};
</
script
>
src/components/tabs/tabs.vue
0 → 100644
View file @
a9a7d704
<
script
>
import
TabNav
from
'
./tab-nav
'
;
export
default
{
name
:
'
MyTabs
'
,
components
:
{
TabNav
},
props
:
{
type
:
String
,
activeName
:
String
,
closable
:
Boolean
,
addable
:
Boolean
,
value
:
{},
editable
:
Boolean
},
data
()
{
return
{
currentName
:
this
.
value
||
this
.
activeName
,
panes
:
[]
};
},
watch
:
{
activeName
(
value
)
{
this
.
setCurrentName
(
value
);
},
value
(
value
)
{
this
.
setCurrentName
(
value
);
},
currentName
(
value
)
{
if
(
this
.
$refs
.
nav
)
{
this
.
$nextTick
(
_
=>
{
this
.
$refs
.
nav
.
scrollToActiveTab
();
});
}
}
},
methods
:
{
handleTabClick
(
tab
,
tabName
,
event
)
{
if
(
tab
.
disabled
)
return
;
this
.
setCurrentName
(
tabName
);
this
.
$emit
(
'
tab-click
'
,
tab
,
event
);
},
handleTabRemove
(
pane
,
ev
)
{
if
(
pane
.
disabled
)
return
;
ev
.
stopPropagation
();
this
.
$emit
(
'
edit
'
,
pane
.
name
,
'
remove
'
);
this
.
$emit
(
'
tab-remove
'
,
pane
.
name
);
},
handleTabAdd
()
{
this
.
$emit
(
'
edit
'
,
null
,
'
add
'
);
this
.
$emit
(
'
tab-add
'
);
},
setCurrentName
(
value
)
{
this
.
currentName
=
value
;
this
.
$emit
(
'
input
'
,
value
);
},
addPanes
(
item
)
{
const
index
=
this
.
$slots
.
default
.
indexOf
(
item
.
$vnode
);
this
.
panes
.
splice
(
index
,
0
,
item
);
},
removePanes
(
item
)
{
const
panes
=
this
.
panes
;
const
index
=
panes
.
indexOf
(
item
);
if
(
index
>
-
1
)
{
panes
.
splice
(
index
,
1
);
}
}
},
render
(
h
)
{
let
{
type
,
handleTabClick
,
handleTabRemove
,
handleTabAdd
,
currentName
,
panes
,
editable
,
addable
}
=
this
;
const
newButton
=
editable
||
addable
?
(
<
span
class
=
"
el-tabs__new-tab
"
on
-
click
=
{
handleTabAdd
}
>
<
i
class
=
"
el-icon-plus
"
><
/i
>
<
/span
>
)
:
null
;
const
navData
=
{
props
:
{
currentName
,
onTabClick
:
handleTabClick
,
onTabRemove
:
handleTabRemove
,
editable
,
type
,
panes
},
ref
:
'
nav
'
};
return
(
<
div
class
=
{{
'
el-tabs
'
:
true
,
'
el-tabs--card
'
:
type
===
'
card
'
,
'
el-tabs--border-card
'
:
type
===
'
border-card
'
}}
>
<
div
class
=
"
el-tabs__header
"
>
{
newButton
}
<
tab
-
nav
{
...
navData
}
><
/tab-nav
>
<
/div
>
<
div
class
=
"
el-tabs__content
"
>
{
this
.
$slots
.
default
}
<
/div
>
<
/div
>
);
},
created
()
{
if
(
!
this
.
currentName
)
{
this
.
setCurrentName
(
'
0
'
);
}
}
};
</
script
>
src/router/index.js
View file @
a9a7d704
...
...
@@ -3,6 +3,7 @@ import Router from 'vue-router'
import
Hello
from
'
@/components/Hello
'
import
Ele
from
'
@/components/Ele
'
import
ChatWin
from
'
@/components/ChatWin
'
import
Drag
from
'
@/components/Drag
'
Vue
.
use
(
Router
)
...
...
@@ -22,6 +23,11 @@ export default new Router({
path
:
'
/chatWin
'
,
name
:
'
ChatWin
'
,
component
:
ChatWin
},
{
path
:
'
/drag
'
,
name
:
'
Drag
'
,
component
:
Drag
}
]
})
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment