@leevan/jtui 2.0.34 → 2.0.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "el-cascader-multi",
3
+ "version": "1.1.8",
4
+ "description": "基于element-ui的级联多选",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1",
8
+ "build": "cross-env NODE_ENV=production webpack --progress "
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/Charming2015/el-cascader-multi.git"
13
+ },
14
+ "keywords": [
15
+ "element",
16
+ "multi",
17
+ "cascader"
18
+ ],
19
+ "author": "charming <2019.02>",
20
+ "license": "ISC",
21
+ "bugs": {
22
+ "url": "https://github.com/Charming2015/el-cascader-multi/issues"
23
+ },
24
+ "homepage": "https://github.com/Charming2015/el-cascader-multi#readme",
25
+ "devDependencies": {
26
+ "babel-core": "^6.26.3",
27
+ "babel-loader": "^7.1.5",
28
+ "css-loader": "^1.0.0",
29
+ "express": "^4.16.3",
30
+ "mini-css-extract-plugin": "^0.5.0",
31
+ "node-sass": "^4.9.2",
32
+ "sass-loader": "^7.0.3",
33
+ "vue-loader": "^15.2.6",
34
+ "vue-style-loader": "^4.1.1",
35
+ "vue-template-compiler": "^2.5.16",
36
+ "webpack": "^4.16.3",
37
+ "webpack-cli": "^3.2.3",
38
+ "webpack-command": "^0.4.1",
39
+ "webpack-dev-server": "^3.1.5",
40
+ "webpack-hot-middleware": "^2.22.3"
41
+ },
42
+ "dependencies": {
43
+ "cross-env": "^5.2.0",
44
+ "element-ui": "^2.4.11",
45
+ "vue": "^2.5.16"
46
+ }
47
+ }
@@ -0,0 +1,9 @@
1
+ import multiCascader from './multi-cascader/multi-cascader.vue'
2
+
3
+ const install = (Vue) => {
4
+ Vue.component(multiCascader.name, multiCascader)
5
+ }
6
+ if (typeof window !== 'undefined' && window.Vue) {
7
+ install(window.Vue)
8
+ }
9
+ export default { install }
@@ -0,0 +1,331 @@
1
+ <template>
2
+ <div class="">
3
+ <el-select
4
+ style="width:100%;height:100%;"
5
+ v-model="selectedLabels"
6
+ multiple
7
+ :popper-class="innerPopperClass"
8
+ @remove-tag="removeOne"
9
+ :filterable="filterable"
10
+ :filter-method="innerFilterMethod"
11
+ :reserve-keyword="reserveKeyword"
12
+ @change="changeLabel"
13
+ v-bind="$attrs"
14
+ @blur="handleBlur"
15
+ @visible-change="visibleChange"
16
+ @focus="handleFocus"
17
+ @clear="handleClear"
18
+ :allow-create="false"
19
+ >
20
+ <span slot="prefix" v-if="$slots.prefix">
21
+ <slot name="prefix"></slot>
22
+ </span>
23
+ <template v-if="!isSearching">
24
+ <el-option value="__root">
25
+ <div class="ground" @click.stop>
26
+ <render-list
27
+ :only-last="onlyLast"
28
+ :list="root.childNodes"
29
+ :level="1"
30
+ :active-list="activeList"
31
+ @handle-click="handleClick"
32
+ @handle-check="handleCheck"
33
+ :label-key="labelKey"
34
+ :expand-trigger="expandTrigger"
35
+ ></render-list>
36
+ <template v-for="item in maxLevellist">
37
+ <div
38
+ :class="`floor-item floor-position-left-${item.id + 1}`"
39
+ :key="item.id"
40
+ v-if="item.rendered"
41
+ v-show="activeList.length >= item.id"
42
+ >
43
+ <render-list
44
+ :only-last="onlyLast"
45
+ :list="showData[item.id]"
46
+ :level="item.id + 1"
47
+ :active-list="activeList"
48
+ @handle-click="handleClick"
49
+ @handle-check="handleCheck"
50
+ :label-key="labelKey"
51
+ :expand-trigger="expandTrigger"
52
+ ></render-list>
53
+ </div>
54
+ </template>
55
+ </div>
56
+ </el-option>
57
+ </template>
58
+ <template v-if="isSearching">
59
+ <el-option
60
+ v-for="item in searchResult"
61
+ :value="item.showLabel"
62
+ :key="getKey(item)"
63
+ >
64
+ <div style="width:100%;height:100%" @click.stop="selectOne(item)">
65
+ {{item.totalLabel}}
66
+ </div>
67
+ </el-option>
68
+ </template>
69
+ </el-select>
70
+ </div>
71
+ </template>
72
+
73
+ <script>
74
+ import TreeStore from './lib/Tree.js'
75
+ import renderList from './render-list.vue'
76
+ import _ from 'lodash'
77
+ import { _findByObj } from './tool/unit'
78
+ export default {
79
+ name: 'el-cascader-multi',
80
+ components: {
81
+ renderList
82
+ },
83
+ props: {
84
+ data: {
85
+ type: Array,
86
+ default: () => [],
87
+ required: true
88
+ },
89
+ value: {
90
+ type: Array,
91
+ default: () => [],
92
+ required: true
93
+ },
94
+ separator: {
95
+ type: String,
96
+ default: '-'
97
+ },
98
+ filterable: {
99
+ type: Boolean,
100
+ default: false
101
+ },
102
+ filterMethod: {
103
+ type: Function
104
+ },
105
+ popperClass: {
106
+ type: String,
107
+ default: ''
108
+ },
109
+ reserveKeyword: {
110
+ type: Boolean,
111
+ default: true
112
+ },
113
+ valueKey: {
114
+ type: String,
115
+ default: 'value'
116
+ },
117
+ labelKey: {
118
+ type: String,
119
+ default: 'label'
120
+ },
121
+ childrenKey: {
122
+ type: String,
123
+ default: 'children'
124
+ },
125
+ expandTrigger: {
126
+ type: String,
127
+ default: 'click'
128
+ },
129
+ onlyLast: {
130
+ type: Boolean,
131
+ default: false
132
+ },
133
+ isTwoDimensionValue: {
134
+ type: Boolean,
135
+ default: true
136
+ },
137
+ showLeafLabel: {
138
+ type: Boolean,
139
+ default: false
140
+ }
141
+ },
142
+ data () {
143
+ return {
144
+ selectedLabels: [],
145
+ selectedIds: [],
146
+ selectedNodes: [],
147
+ activeClass: 'floor-width-1',
148
+ store: {},
149
+ root: [],
150
+ maxLevellist: [],
151
+ showData: {},
152
+ activeList: [],
153
+ searchText: '',
154
+ searchResult: []
155
+ }
156
+ },
157
+ computed: {
158
+ isSearching () {
159
+ return !(this.searchText.trim() === '')
160
+ },
161
+ innerPopperClass () {
162
+ return `${this.popperClass} multi-cascader ${this.isSearching ? '' : 'multi-cascader-style'} ${this.activeClass}`
163
+ }
164
+ },
165
+ watch: {
166
+ data: {
167
+ deep: true,
168
+ handler () {
169
+ this.init()
170
+ }
171
+ },
172
+ value: {
173
+ deep: true,
174
+ handler () {
175
+ // this.init()
176
+ this.updateSelect(this.value, true, true)
177
+ }
178
+ },
179
+ selectedNodes () {
180
+ this.$emit('change', this.selectedNodes.map(o => o[this.isTwoDimensionValue ? '_idArr' : this.valueKey]))
181
+ }
182
+ },
183
+ methods: {
184
+ visibleChange (v) {
185
+ this.activeList = []
186
+ this.activeClass = 'floor-width-1'
187
+ if (!v) {
188
+ this.searchText = ''
189
+ }
190
+ this.$emit('visible-change', v)
191
+ },
192
+ handleBlur (e) {
193
+ this.searchText = ''
194
+ this.$emit('blur', e)
195
+ },
196
+ handleFocus (e) {
197
+ this.$emit('focus', e)
198
+ },
199
+ handleClear () {
200
+ this.selectedNodes.forEach(node => {
201
+ node.check(false)
202
+ })
203
+ this.$emit('input', [])
204
+ this.$emit('clear')
205
+ },
206
+ selectOne (item) {
207
+ item.checked = !item.checked
208
+ this.handleCheck(item)
209
+ },
210
+ changeLabel (v) {
211
+ this.store.nodeList.forEach(node => {
212
+ node.check(v.includes(node.showLabel))
213
+ })
214
+ },
215
+ innerFilterMethod (v) {
216
+ this.searchText = v
217
+ let tempResult = this.store.nodeList
218
+ if (v.trim() !== '') {
219
+ this.activeClass = ''
220
+ if (typeof this.filterMethod === 'function') {
221
+ this.searchResult = this.filterMethod(tempResult, v)
222
+ } else {
223
+ tempResult = tempResult.filter(o => o.isLeaf)
224
+ tempResult = tempResult.filter(o => o.showLabel.includes(v))
225
+ this.searchResult = tempResult
226
+ }
227
+ } else {
228
+ this.activeClass = 'floor-width-1'
229
+ }
230
+ },
231
+ getKey () {
232
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
233
+ let r = Math.random() * 16 | 0
234
+ let v = c === 'x' ? r : (r & 0x3 | 0x8)
235
+ return v.toString(16)
236
+ })
237
+ },
238
+ handleClick (node, levelIndex, level) {
239
+ if (this.maxLevellist[level - 1]) {
240
+ this.maxLevellist[level - 1].rendered = true
241
+ }
242
+ this.activeClass = `floor-width-${node.isLeaf ? level : level + 1}`
243
+ let tempList = [...this.activeList]
244
+ if (level < tempList.length) {
245
+ tempList.splice(level)
246
+ }
247
+ tempList[level - 1] = node.id
248
+ this.showData[level] = node.childNodes
249
+ this.activeList = tempList
250
+ },
251
+ handleCheck (node) {
252
+ node.check(node.checked)
253
+ this.selectedIds = this.store.selectedIds
254
+ this.updateSelect(this.store.selectedIds)
255
+ this.$emit('input', this.selectedNodes.map(o => o[this.isTwoDimensionValue ? '_idArr' : this.valueKey]))
256
+ },
257
+ removeOne (v) {
258
+ let targetNode = this.selectedNodes.find(o => o.showLabel === v) || {}
259
+ targetNode.checked = false
260
+ this.handleCheck(targetNode)
261
+ this.$emit('remove-tag', v)
262
+ },
263
+ updateSelect (data = [], needCheckNode = false, setValue = false) {
264
+ let tempSelectedNodes = []
265
+ let tempSelectedLabels = []
266
+ let tempSelectedIds = []
267
+ this.store.nodeList.forEach(node => {
268
+ node.checked && node.check(false)
269
+ })
270
+ data.forEach(o => {
271
+ let targetNode
272
+ if (setValue) {
273
+ targetNode = _findByObj(this.store.nodeList, { [this.isTwoDimensionValue ? '_idArr' : this.valueKey]: o }) || {}
274
+ // targetNode = _.find(this.store.nodeList, { [this.isTwoDimensionValue ? '_idArr' : this.valueKey]: o }) || {}
275
+ tempSelectedIds.push(targetNode.id)
276
+ } else {
277
+ targetNode = this.store.nodesMap[o]
278
+ tempSelectedIds.push(o)
279
+ }
280
+ if (targetNode) {
281
+ needCheckNode && targetNode.check(true)
282
+ tempSelectedNodes.push(targetNode)
283
+ tempSelectedLabels.push(targetNode.showLabel)
284
+ }
285
+ })
286
+ this.selectedNodes = tempSelectedNodes
287
+ this.selectedLabels = tempSelectedLabels
288
+ this.selectedIds = tempSelectedIds
289
+ },
290
+ init () {
291
+ this.store = new TreeStore({
292
+ data: this.data,
293
+ separator: this.separator,
294
+ valueKey: this.valueKey,
295
+ labelKey: this.labelKey,
296
+ childrenKey: this.childrenKey,
297
+ showLeafLabel: this.showLeafLabel
298
+ })
299
+ this.root = this.store.root
300
+ this.maxLevellist = Array.from({ length: this.store.maxLevel - 1 }, (v, i) => {
301
+ this.showData[i + 1] = []
302
+ return {
303
+ id: i + 1,
304
+ rendered: false
305
+ }
306
+ })
307
+ this.updateSelect(this.value, true, true)
308
+ }
309
+ },
310
+ mounted () {
311
+ this.init()
312
+ }
313
+ }
314
+ </script>
315
+
316
+ <style lang="scss">
317
+ .multi-cascader{
318
+ min-width:auto !important;
319
+ }
320
+ .multi-cascader .el-select-dropdown__item{
321
+ height:100%;
322
+ padding:0 !important;
323
+ }
324
+ .multi-cascader .el-select-dropdown__wrap{
325
+ max-height: 540px;
326
+ }
327
+
328
+ .ground{
329
+ display:flex;
330
+ }
331
+ </style>
@@ -0,0 +1,179 @@
1
+ <template>
2
+ <ul class="ul-style">
3
+ <li class="li-style"
4
+ v-for="(node, nodeIndex) in list"
5
+ :key="guid(node)"
6
+ @click="handleClick(node, nodeIndex, level)"
7
+ :class="{'active-li': activeList[level - 1] === node.id}"
8
+ @mousemove="handleMouseMove(node, nodeIndex, level)"
9
+ @mouseout="handleMouseOut"
10
+ >
11
+ <p class="li-label-style" v-toolTip>
12
+ <span @click.stop v-show="!onlyLast || (onlyLast && node.isLeaf)">
13
+ <el-checkbox
14
+ @change="handleCheck($event, node)"
15
+ v-model="node.checked"
16
+ :disabled="node.disabled"
17
+ ></el-checkbox>
18
+ </span>
19
+ <span style="margin-left:5px">{{node[labelKey]}}</span>
20
+ <i v-if="node.childNodes && node.childNodes.length > 0" class="li-label-icon el-icon-arrow-right"></i>
21
+ </p>
22
+ </li>
23
+ </ul>
24
+ </template>
25
+
26
+ <script>
27
+ export default {
28
+ directives: {
29
+ toolTip: {
30
+ inserted: function (el) {
31
+ el.title = el.scrollWidth > el.offsetWidth ? el.innerText : ''
32
+ }
33
+ }
34
+ },
35
+ props: {
36
+ activeList: {
37
+ type: Array,
38
+ default: () => []
39
+ },
40
+ list: {
41
+ type: Array,
42
+ default: () => []
43
+ },
44
+ level: {
45
+ type: [Number, String]
46
+ },
47
+ labelKey: {
48
+ type: String,
49
+ default: 'label'
50
+ },
51
+ expandTrigger: {
52
+ type: String,
53
+ default: 'click'
54
+ },
55
+ onlyLast: {
56
+ type: Boolean,
57
+ default: false
58
+ }
59
+ },
60
+ data () {
61
+ return {
62
+ oldValue: {
63
+ oldNode: null,
64
+ oldLevelIndex: null,
65
+ oldLevel: null
66
+ }
67
+ }
68
+ },
69
+ methods: {
70
+ handleMouseOut () {
71
+ this.oldValue = {
72
+ oldNode: null,
73
+ oldLevelIndex: null,
74
+ oldLevel: null
75
+ }
76
+ },
77
+ // mouseEnter会一直触发,然后阻止了click事件,改为mouseMove事件
78
+ handleMouseMove (node, levelIndex, level) {
79
+ if (this.expandTrigger !== 'hover') {
80
+ return false
81
+ }
82
+ let { oldNode, oldLevelIndex, oldLevel } = this.oldValue
83
+ if (
84
+ (node === oldNode) &&
85
+ (oldLevelIndex === levelIndex) &&
86
+ (oldLevel === level)
87
+ ) {
88
+ return false
89
+ } else {
90
+ this.oldValue = {
91
+ oldNode: node,
92
+ oldLevelIndex: levelIndex,
93
+ oldLevel: level
94
+ }
95
+ }
96
+ this.$emit('handle-click', node, levelIndex, level)
97
+ },
98
+ handleClick (node, levelIndex, level) {
99
+ if (this.expandTrigger === 'click') {
100
+ this.$emit('handle-click', node, levelIndex, level)
101
+ }
102
+ },
103
+ handleCheck (v, node) {
104
+ node.checked = v
105
+ this.$emit('handle-check', node)
106
+ },
107
+ guid () {
108
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
109
+ let r = Math.random() * 16 | 0
110
+ let v = c === 'x' ? r : (r & 0x3 | 0x8)
111
+ return v.toString(16)
112
+ })
113
+ }
114
+ }
115
+ }
116
+ </script>
117
+
118
+ <style lang="scss">
119
+ .ul-style{
120
+ padding-left:0 !important;
121
+ list-style: none;
122
+ max-height:500px;
123
+ overflow-y: auto;
124
+ &::-webkit-scrollbar {
125
+ width: 8px;
126
+ height: 8px;
127
+ display: none;
128
+ }
129
+ &:hover::-webkit-scrollbar{
130
+ display: block;
131
+ }
132
+ &::-webkit-scrollbar-thumb {
133
+ border-radius: 10px;
134
+ background:#d4d3d3;
135
+ }
136
+ }
137
+ .li-style {
138
+ height: 34px;
139
+ padding-right:20px;
140
+ box-sizing: border-box;
141
+ list-style: none;
142
+ max-width: 240px;
143
+ cursor: pointer;
144
+ white-space: nowrap;
145
+ overflow: hidden;
146
+ text-overflow: ellipsis;
147
+ line-height: 34px;
148
+ &:hover{
149
+ background-color: #c8e3fe;
150
+ }
151
+ &.selected {
152
+ color: #46a0fc;
153
+ }
154
+ &.active-li {
155
+ background-color: #c8e3fe;
156
+ color: #46a0fc;
157
+ }
158
+ .li-label-style{
159
+ text-align: left;
160
+ width: 100%;
161
+ box-sizing: border-box;
162
+ padding:0 15px;
163
+ position: relative;
164
+ text-overflow: ellipsis;
165
+ white-space: nowrap;
166
+ overflow: hidden;
167
+ margin: 0;
168
+ .li-label-icon {
169
+ position: absolute;
170
+ right: 0px;
171
+ top: 50%;
172
+ transform: translate(0, -50%);
173
+ }
174
+ .el-checkbox {
175
+ margin-right: 10px;
176
+ }
177
+ }
178
+ }
179
+ </style>
@@ -0,0 +1,14 @@
1
+ export function _uniq (arr) {
2
+ let result = []
3
+ arr.forEach(item => {
4
+ if (!result.includes(item)) {
5
+ result.push(item)
6
+ }
7
+ })
8
+ return result
9
+ }
10
+
11
+ export function _findByObj (arr, obj) {
12
+ let keys = Object.keys(obj)
13
+ return arr.find(item => keys.every(key => JSON.stringify(item[key]) === JSON.stringify(obj[key])))
14
+ }
@@ -0,0 +1,88 @@
1
+ const path = require('path')
2
+ // 插件
3
+ const MiniCssExtractPlugin = require("mini-css-extract-plugin");
4
+ const VueLoaderPlugin = require('vue-loader/lib/plugin')
5
+ // 路径
6
+ const ENTRY_PATH = resolve('./src/index.js')
7
+ const DIST_DIR = resolve('./dist')
8
+
9
+ module.exports = (env, argv) => {
10
+ return {
11
+ // 入口
12
+ entry: [
13
+ resolve('src/index.js')
14
+ ],
15
+ // 出口
16
+ output: {
17
+ path: resolve('dist'),
18
+ filename: 'index.js',
19
+ },
20
+ resolve: {
21
+ // 定义模块查找的后缀,方便在代码引用时可省略后缀
22
+ extensions: ['.js', '.vue', '.json'],
23
+ // 定义路径简写
24
+ alias: {
25
+ 'vue$': 'vue/dist/vue.esm.js',
26
+ 'src' : resolve('src'),
27
+ '@' : resolve('src'),
28
+ }
29
+ },
30
+ module: {
31
+ // 文件的loader
32
+ rules: [
33
+ {
34
+ test: /\.js$/,
35
+ loader:"babel-loader",
36
+ exclude: /node_modules/
37
+ },
38
+ {
39
+ test: /\.vue$/,
40
+ loader: 'vue-loader'
41
+ },
42
+ {
43
+ test: /\.css$/,
44
+ use: [
45
+ 'vue-style-loader',
46
+ 'css-loader'
47
+ ]
48
+ },
49
+ {
50
+ test: /\.scss$/,
51
+ use: [
52
+ 'vue-style-loader',
53
+ 'css-loader',
54
+ 'sass-loader'
55
+ ]
56
+ },
57
+ {
58
+ test: /\.sass$/,
59
+ use: [
60
+ 'vue-style-loader',
61
+ 'css-loader',
62
+ {
63
+ loader: 'sass-loader',
64
+ options: {
65
+ indentedSyntax: true
66
+ }
67
+ }
68
+ ]
69
+ }
70
+ ]
71
+ },
72
+ plugins: [
73
+ // 处理css,可以把vue中提取css为单独文件
74
+ new MiniCssExtractPlugin({
75
+ filename: "css/[name].[hash].css"
76
+ }),
77
+ // webpack4下,vue-loader需要这样引入
78
+ new VueLoaderPlugin()
79
+ ],
80
+
81
+ devtool: 'source-map'
82
+ }
83
+ }
84
+
85
+ function resolve(dir) {
86
+ return path.join(__dirname, './', dir);
87
+ }
88
+