<template> <div ref="toolbarMainFrame" class="toolbar_main_frame"> <div ref="toolbarFrame" class="toolbar_frame"> <Poptip placement="bottom-start" popper-class="toolbar-item-proper" v-for="btn in toolbarData" :key="btn.key" v-model="btn.expandChild" :disabled="disableBtns.includes(btn.key)" > <Button type="text" @click.stop="handleClick(btn)" :disabled="disableBtns.includes(btn.key)" > {{ btn.toggle ? btn.replace : btn.name }} <!-- <Icon class="expand iconfont-acct icon-expand-down expand-icon" v-if="((btn.children && btn.children.length > 0) || btn.pattern === 'custom') && $config.systemName === '1318'" @click.native.stop="handleArrowDownClick(btn)" :class="{ 'is-expanded': btn.expandChild }" /> --> <Icon type="ios-arrow-down" v-if="(btn.children && btn.children.length > 0) || btn.pattern === 'custom'" @click.native.stop="handleArrowDownClick(btn)" :class="{ 'is-expanded': btn.expandChild }" /> </Button> <!--<div class="btnMask" v-if="btn.hasMask"></div>--> <div class="toolbar-sub-frame" slot="content"> <div class="custom-frame" v-if="btn.pattern === 'custom' && btn.expandChild"> <slot :name="btn.key"></slot> </div> <!-- 多选 --> <div v-if="btn.children && btn.children.length > 0 && btn.expandChild && btn.pattern === 'multiple'" class="toolbar-sub-items" > <div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index"> <Checkbox v-for="list in group" :key="list.key" v-model="list.checked" :disabled="list.isDisabled" @on-change="handleMultipleCheckChange(btn, list)" >{{ list.checked ? list.replace : list.name }}</Checkbox> <div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div> </div> </div> <!-- 单选 --> <div v-if="btn.children && btn.children.length > 0 && btn.expandChild && btn.pattern === 'single'" class="toolbar-sub-items" > <div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index"> <RadioGroup :value="btn.groupChecked[name]" @on-change="handleSingleCheckClick($event, name, btn)"> <Radio :class="{'radio-checked': btn.groupChecked[name] === list.key}" v-for="list in group" :key="list.key" :label="list.checked ? list.replace : list.name" :disabled="list.isDisabled" ><Icon v-if="btn.groupChecked[name] === list.key" type="md-checkmark" />{{ list.checked ? list.replace : list.name }}</Radio> </RadioGroup> <div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div> </div> </div> <ul v-if="btn.children && btn.children.length > 0 && btn.expandChild && !btn.pattern" class="toolbar-sub-items" > <li class="sub-item" v-for="item in btn.children" :key="item.key" :class="{ 'sub-item-disabled': disableChildrenItems[btn.key] && disableChildrenItems[btn.key].includes(item.key) }" @click="handleSubItemClick(btn, item)" > {{ item.switch || item.toggle ? item.replace : item.name }} </li> </ul> </div> </Poptip> </div> <Icon type="ios-more" class="expand_right_toolbar" @click="showRight = !showRight" v-if="rightData.length > 0" /> <div ref="rightToolbar" class="toolbar_frame toolbar_frame_right" v-if="rightData.length > 0 && showRight"> <Poptip placement="right-start" popper-class="toolbar-item-proper" v-for="btn in rightData" :key="btn.key" v-model="btn.expandChild"> <Button type="text" @click.stop="handleClick(btn)" :disabled="disableBtns.includes(btn.key)" > {{ btn.toggle ? btn.replace : btn.name }} <!-- <Icon class="expand-btn iconfont-acct icon-expand-down expand-icon" v-if="((btn.children && btn.children.length > 0) || btn.pattern === 'custom') && $config.systemName === '1318'" @click.native.stop="handleArrowDownClick(btn)" :class="{ 'is-expanded': btn.expandChild }" /> --> <Icon type="ios-arrow-down" class="expand-btn" v-if="(btn.children && btn.children.length > 0) || btn.pattern === 'custom'" @click.native.stop="handleArrowDownClick(btn)" :class="{ 'is-expanded': btn.expandChild }" /> </Button> <!--<div class="btnMask" v-if="btn.hasMask"></div>--> <div class="toolbar-sub-frame" slot="content"> <div class="custom-frame" v-if="btn.pattern === 'custom' && btn.expandChild"> <slot :name="btn.key"></slot> </div> <!-- 多选 --> <div v-if="btn.children && btn.children.length > 0 && btn.expandChild && btn.pattern === 'multiple'" class="toolbar-sub-items" > <div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index"> <Checkbox v-for="list in group" :key="list.key" v-model="list.checked" :disabled="list.isDisabled" @on-change="handleMultipleCheckChange(btn, list)" >{{ list.checked ? list.replace : list.name }}</Checkbox> <div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div> </div> </div> <div v-if="btn.children && btn.children.length > 0 && btn.expandChild && btn.pattern === 'single'" class="toolbar-sub-items" > <div class="toolbar-group" v-for="(group, name, index) in btn.groups" :key="index"> <RadioGroup v-model="btn.groupChecked[name]" @on-change="handleSingleCheckClick($event, name, btn)"> <Radio :class="{'radio-checked': btn.groupChecked[name] === list.key}" v-for="list in group" :key="list.key" :label="list.checked ? list.replace : list.name" :disabled="list.isDisabled" ><Icon v-if="btn.groupChecked[name] === list.key" type="md-checkmark" />{{ list.checked ? list.replace : list.name }}</Radio> </RadioGroup> <div class="group-divider" v-if="Object.keys(btn.groups).length - 1 !== index"></div> </div> </div> <ul v-if="btn.children && btn.children.length > 0 && btn.expandChild && !btn.pattern" class="toolbar-sub-items" > <li class="sub-item" v-for="item in btn.children" :key="item.key" :class="{ 'sub-item-disabled': disableChildrenItems[btn.key] && disableChildrenItems[btn.key].includes(item.key) }" @click="handleSubItemClick(btn, item)" > {{ item.switch || item.toggle ? item.replace : item.name }} </li> </ul> </div> </Poptip> </div> </div> </template> <script> const elementResizeDetectorMaker = require('element-resize-detector') export default { name: 'Toolbar', props: { buttons: { type: Array, required: true, default () { return [] } }, disables: { type: Array, required: false, default () { return [] } }, // 所有事件作为一个事件发布 together: { type: Boolean, default: false }, /* btnsMaskArr:{ type: Array, required: false, default () { return [] } }, */ // 是否在点击菜单时展开子选项,默认点右侧下拉展开 expandOnClick: { type: Boolean, default: false } }, data () { return { toolbarData: [], disableBtns: [], disableChildrenItems: {}, resizeDom: null, rightData: [], // 当toolbar长度超出屏幕宽度时,显示在右侧的数据 showRight: false // btnsMasks:[], } }, methods: { handleClick (btn) { // this.$store.commit('setShezhiDropdownVisible', false) // this.$store.commit('setDropdownVisible', false) if (btn.expandOnClick) { this.toolbarData.forEach(item => { if (item.key !== btn.key) item.expandChild = false else item.expandChild = !item.expandChild }) this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) return } if (this.together) { this.$emit('on-click', btn.key, btn.toggle) } else { if (btn.pattern === 'toggle') { return this.$emit(`on-${btn.key}`, btn.toggle) } this.$emit(`on-${btn.key}`, btn.key) } }, hiddenSelectItems () { }, initToolbar () { this.toolbarData.forEach(btn => { btn.expandOnClick = btn.expandOnClick || false btn.expandChild = btn.expandChild || false if (btn.pattern === 'toggle') { btn.toggle = false btn.replace = btn.replace || '取消' + btn.name } else if (btn.pattern === 'switch') { btn.children.forEach(child => { child.switch = false child.replace = child.replace || '取消' + child.name }) } else if (btn.pattern === 'multiple') { btn.groups = {} let lastChecked = null btn.children.forEach(child => { child.checked = child.checked || false child.isDisabled = child.isDisabled || false child.replace = child.replace || child.name if (child.checked) lastChecked = child let groupname = child.group || 'group' if (!btn.groups[groupname]) { btn.groups[groupname] = [] // btn.groups[groupname].checkes = [] // btn.groups[groupname].items = [] } btn.groups[groupname].push(child) // child.checked = false }) if (lastChecked) { this.handleMultipleCheckChange(btn, lastChecked) } } else if (btn.pattern === 'single') { btn.groups = {} btn.groupChecked = {} btn.children.forEach(child => { child.checked = child.checked || false child.isDisabled = child.isDisabled || false child.replace = child.replace || child.name let groupname = child.group || 'group' if (!btn.groups[groupname]) { btn.groups[groupname] = [] // btn.groups[groupname].checkes = [] // btn.groups[groupname].items = [] } btn.groups[groupname].push(child) if (child.checked) { btn.groupChecked[groupname] = child.key } // child.checked = false }) } /* if(this.btnsMasks.findIndex(item=>item == btn.key) != -1){ btn.hasMask = true }else{ btn.hasMask = false } */ }) }, toggleItemsByKey (key) { let expand = this.toolbarData.find(item => item.key === key).expandChild this.toolbarData.find(item => item.key === key).expandChild = !expand this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) }, closeItemsByKey (key) { this.toolbarData.find(item => item.key === key).expandChild = false }, // 把展开的下拉收起来 closeExpandItems () { this.toolbarData.forEach(item => { item.expandChild = false }) this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) }, toggleButtonByKey (key, flag) { this.toolbarData.find(item => item.key === key).toggle = flag this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) }, toggleChildByKey (key, childKey, flag) { let tempItem = this.toolbarData.find(item => item.key === key) tempItem.children.find(item => item.key === childKey).toggle = flag this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) }, checkDisabled (name) { return this.disableBtns.includes(name) }, checkChildDisabled (key) { }, disableButtons (names) { names.forEach(name => { if (!this.disableBtns.includes(name)) { this.disableBtns.push(name) } }) }, enableButtons (names) { names.forEach(name => { const index = this.disableBtns.findIndex(item => item === name) if (index !== -1) { this.disableBtns.splice(index, 1) } }) }, disableChildren (key, childKeys) { if (!this.disableChildrenItems[key]) this.disableChildrenItems[key] = [] childKeys.forEach(name => { if (!this.disableChildrenItems[key].includes(name)) { this.disableChildrenItems[key].push(name) } }) }, enableChildren (key, childKeys) { if (this.disableChildrenItems[key]) { childKeys.forEach(name => { const index = this.disableChildrenItems[key].findIndex(item => item === name) if (index !== -1) { this.disableChildrenItems[key].splice(index, 1) } }) } }, // 除了这个数组中的按钮其他都禁用 disableButtonsExcept (names) { // this.disableBtns = [] this.buttons.forEach(item => { let keyIndex = this.disableBtns.findIndex(k => item.key === k) // 如果该 key不在传进来的数组中,并且也不在 禁用数组 中,则将其加入禁用数组中 if (!names.includes(item.key) && keyIndex === -1) { this.disableBtns.push(item.key) } // 如果该 key在传进来的数组中,并且也在 禁用数组 中,则将其从禁用数组中删除 if (names.includes(item.key) && keyIndex !== -1) { this.disableBtns.splice(keyIndex, 1) } }) }, // 设置多选框的选中或不选 setMultipleChecked (key, childKey, check) { this.toolbarData.forEach(item => { if (item.key === key && item.children) { item.children.forEach(child => { if (childKey === child.key) child.checked = check }) } if (item.key === key && item.groups) { for (let tempGroup in item.groups) { item.groups[tempGroup].forEach(child => { if (childKey === child.key) child.checked = check }) } } }) }, // 设置某一项禁用,目前支持复选框禁用 setMultipleDisabled (key, childKey, isDisabled) { this.toolbarData.forEach(item => { if (item.key === key && item.children) { item.children.forEach(child => { if (childKey === child.key) child.isDisabled = isDisabled }) } if (item.key === key && item.groups) { for (let tempGroup in item.groups) { item.groups[tempGroup].forEach(child => { if (childKey === child.key) child.isDisabled = isDisabled }) } } }) }, handleArrowDownClick (btn) { if (this.disableBtns.includes(btn.key)) return this.toolbarData.forEach(item => { if (item.key !== btn.key) item.expandChild = false }) btn.expandChild = !btn.expandChild this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) this.$emit('on-expand', btn.key, btn.expandChild) }, handleSubItemClick (menu, item) { if (this.disableChildrenItems[menu.key] && this.disableChildrenItems[menu.key].includes(item.key)) return if (menu.pattern === 'switch') { item.switch = !item.switch this.$emit(`on-${menu.key}`, item.key, item.switch) } else { this.$emit(`on-${menu.key}`, item.key, item.toggle) } this.closeItemsByKey(menu.key) }, handleMultipleCheckChange (menu, item) { let checkes = {} if (!checkes[item.group]) checkes[item.group] = [] Object.keys(menu.groups).forEach(name => { checkes[name] = [] menu.groups[name].forEach(list => { if (list.checked) checkes[name].push(list.key) }) }) this.$emit(`on-${menu.key}`, checkes, item.key) }, handleSingleCheckClick (label, groupName, menu) { let tempKey = menu.groups[groupName].find(item => item.name === label).key if (menu.groupChecked[groupName] === tempKey) return menu.groupChecked[groupName] = tempKey let groupList = menu.groups[groupName] groupList.forEach(list => { let tempList = menu.children.find(ch => ch.key === list.key) if (list.key === menu.groupChecked[groupName]) { list.checked = true tempList.checked = true } else { list.checked = false tempList.checked = false } }) menu.expandChild = false this.$emit(`on-${menu.key}`, groupName, menu.groupChecked[groupName]) }, // 重新布局toolbar layoutToolBar () { if (!this.$refs.toolbarFrame || !this.$refs.toolbarMainFrame) return let nodes = this.$refs.toolbarFrame.children let mainWidth = this.$refs.toolbarMainFrame.offsetWidth - 20 let sumWidth = 0 let offsetIndex = 0 // console.log(this.$refs.toolbarFrame.childNodes) // console.log(this.$refs.toolbarMainFrame.offsetWidth) for (let i = 0, len = nodes.length; i < len; i++) { nodes[i].style.display = 'inline-block' if (sumWidth + nodes[i].offsetWidth > mainWidth) { offsetIndex = i break } sumWidth += nodes[i].offsetWidth } if (offsetIndex === 0) { this.rightData = [] return this.rightData } for (let j = offsetIndex, len = nodes.length; j < len; j++) { nodes[j].style.display = 'none' } this.rightData = this.toolbarData.slice(offsetIndex) }, // 防抖函数 debounce (fn, wait) { var timeout = null return function () { if (timeout !== null) clearTimeout(timeout) timeout = setTimeout(fn, wait) } }, updatePoppers () { this.toolbarData = JSON.parse(JSON.stringify(this.toolbarData)) this.rightData = JSON.parse(JSON.stringify(this.rightData)) }, changeTagFunc (resolve) { this.updatePoppers() resolve(true) } }, created () { this.disableBtns = this.disables this.toolbarData = JSON.parse(JSON.stringify(this.buttons)) // this.btnsMasks = JSON.parse(JSON.stringify(this.btnsMaskArr)) this.initToolbar() }, mounted () { this.layoutToolBar() this.resizeDom = elementResizeDetectorMaker() this.resizeDom.listenTo(this.$refs.toolbarMainFrame, this.debounce(this.layoutToolBar, 300)) this.$portalAPI.on("change-tag", this.changeTagFunc) }, beforeDestroy () { this.resizeDom.removeListener(this.$refs.toolbarMainFrame, this.debounce(this.layoutToolBar, 300)) /* 事件销毁 */ this.$portalAPI.off("change-tag", this.changeTagFunc) if (this.$portalAPI.events['change-tag'] && this.$portalAPI.events['change-tag'].length == 0) { delete this.$portalAPI.events['change-tag'] } }, computed: { calcMainWidth () { return this.$refs.toolbarMainFrame && this.$refs.toolbarMainFrame.offsetWidth } }, watch: { buttons: { handler (data) { this.toolbarData = JSON.parse(JSON.stringify(data)) this.initToolbar() /* this.toolbarData.forEach(btn=>{ if(this.btnsMasks.findIndex(item=>item == btn.key) != -1){ btn.hasMask = true }else{ btn.hasMask = false } }) */ }, deep: true }, // closeCurrentExpandKey: { // handler(newVal, oldVal) { // this.currentExpandKey = this.currentExpandKey ? '' : newVal // }, // deep: true // }, disables (disables) { this.disableBtns = disables } // calcMainWidth (width) { // console.log(width) // } /* btnsMaskArr(btnsMaskArr){ this.btnsMasks = btnsMaskArr this.toolbarData.forEach(btn=>{ if(this.btnsMasks.findIndex(item=>item == btn.key) != -1){ btn.hasMask = true }else{ btn.hasMask = false } }) }, */ } } </script> <style lang="less"> @toolbarHeight: 32px; @fontSize: 12px; @sub-color: #555; .toolbar_main_frame { border-bottom: 1px solid #DDDDDD; background-color: #fff; height: @toolbarHeight; position: relative; } .toolbar_frame { height: 100%; display: inline-flex; // border-bottom: 1px solid #DDDDDD; // background-color: #fff; display: flex; // flex-wrap: nowrap; li { list-style: none; } .ivu-poptip { // float: left; .ivu-poptip-rel { padding: 7px 0; box-sizing: border-box; .ivu-btn { float: left; height: 16px; line-height: 16px; padding: 0 16px; border-left: 1px solid #DDDDDD; border-radius: 0; box-shadow: none; // margin-top: 2px; > span { display: inline-block; height: 16px; line-height: 16px; vertical-align: top; font-size: @fontSize; } .is-expanded { transform: rotate(180deg); } } .ivu-btn[disabled] .ivu-icon { color: #C6C6C6; } } &:first-child { .ivu-btn { border-left: none; } } .toolbar-item-proper { padding: 1px 0 0 0; .ivu-poptip-arrow { display: none; } .ivu-poptip-body { padding: 0; .custom-frame { min-width: 100%; position: absolute; left: 2px; top: 2px; // top: calc(100% + 2px); z-index: 78; margin-bottom: 0; background-color: #ffffff; box-shadow: 0 0 3px 0.5px; } .toolbar-sub-items { min-width: 100%; padding: 5px 0; position: absolute; left: 2px; top: 2px; // top: calc(100% + 2px); z-index: 78; margin-bottom: 0; background-color: #ffffff; box-shadow: 0 0 3px 0.5px; // transition: height 5s; .sub-item { padding: 0 10px 0 30px; font-size: @fontSize; line-height: 24px; white-space: nowrap; display: flex; align-items: center; user-select: none; } .sub-item:hover { // background-color: #F4F9FF; color: #4880FF; cursor: pointer; } .sub-item.sub-item-disabled { color: #C6C6C6; cursor: not-allowed; } .toolbar-group { padding: 0; .ivu-checkbox-wrapper { display: block; margin: 0; height: 24px; line-height: 24px; padding: 0 10px; white-space: nowrap; font-size: 13px; font-weight: 400; .ivu-checkbox { margin-top: -2px; margin-right: 6px; } } .ivu-checkbox-wrapper:hover { color: #4880FF; } .group-divider { // padding-left: 10px; margin: 0 10px 5px 10px; border-bottom: 1px solid #DDDDDD; } .ivu-radio-wrapper { display: block; margin: 0; height: 24px; line-height: 24px; padding: 0 10px 0 30px; white-space: nowrap; font-size: 13px; font-weight: 400; position: relative; .ivu-radio { display: none; } .ivu-icon { position: absolute; top: 5px; left: 6px; } &.radio-checked { color: #4880FF; .ivu-icon { color: #4880FF; } } } .ivu-radio-wrapper:hover { color: #4880FF; } } } } } } } .toolbar_frame_right { height: auto; position: absolute; right: 2px; top: calc(100% + 3px); z-index: 250; background-color: #fff; display: flex; flex-direction: column; align-items: stretch; // border: 1px solid #DDDDDD; box-shadow: 0 0 3px 0.5px; .ivu-poptip { height: 30px; .ivu-poptip-rel { padding: 0; width: 100%; position: relative; .ivu-btn { width: 100%; padding: 7px 16px 7px 36px; text-align: right; border-left: none; &:not([disabled]):hover { background-color: rgb(244, 249, 255); } .is-expanded { transform: rotate(90deg); } .expand-btn { position: absolute; left: 7px; top: 8px; z-index: 251; transform: rotate(90deg); } } } } } .expand_right_toolbar { position: absolute; top: 3px; right: 3px; font-size: 24px; z-index: 201; } .toolbar_main_frame{ height: 37px; border-bottom: 1px solid #BEC5C8; background-color: transparent; background: url("./assets/img/toorbar_background.png"); background-position: left; .toolbar_frame { .ivu-poptip { height: 37px; .ivu-poptip-rel { position: relative; height: 100%; padding: 10px 0; .ivu-btn { border-left: 1px solid #91999D; background-color: transparent; span { font-size: 14px; // color: #16344C; &:hover { color: #3CC2AC; } } .is-expanded { transform: rotate(180deg) translate(0, 1px); } .expand-icon { font-size: 14px; color: #444; &:hover { color: #3CC2AC; } } } .ivu-btn:disabled { span { color: #797b7e; } .expand-icon { color: #797b7e; } } /* .btnMask{ position: absolute; left: 0; top: 0; z-index: 78; background-color: skyblue; height: 100%; width: 90%; }*/ } &:first-child { .ivu-btn { border-left: none; } } .toolbar-item-proper { margin-top: -3px; .ivu-poptip-body { .custom-frame { // background-color: #D9DCE0; span { font-size: 14px; &:hover { color: #3CC2AC; } } .ivu-btn-group{ .ivu-btn{ // &:focus{ // outline: none; // } box-shadow: none; } } } .toolbar-sub-items { // background-color: #D9DCE0; .sub-item { font-size: 13px; color: @sub-color; } .sub-item:hover { // background-color: rgba(60,194,172,0.12); color: #3CC2AC; } .toolbar-group { .ivu-checkbox-wrapper { color: @sub-color; .ivu-checkbox { .ivu-checkbox-inner { border-color: @sub-color; } } } .ivu-radio-wrapper { &.radio-checked { color: #3CC2AC; .ivu-icon { color: #3CC2AC; } } } .ivu-checkbox-wrapper:hover { // color: #3CC2AC; } .ivu-checkbox-wrapper-checked { .ivu-checkbox { .ivu-checkbox-inner { border-color: #3CC2AC; } } } .group-divider { border-color: @sub-color; } .ivu-radio-wrapper:hover { color: #3CC2AC; } } } } } } } .expand_right_toolbar { top: 4px; right: 4px; font-size: 28px; } .toolbar_frame_right { background-color: #fff; // background-size: cover; box-shadow: 0 0 3px 0.5px; .ivu-poptip { height: 30px; .ivu-poptip-rel { padding: 0; .ivu-btn { &:not([disabled]):hover { background: url("./assets/img/toorbar_background.png") left; } border-left: none; .is-expanded { transform: rotate(90deg) translate(0, 0); } } } } } } </style>