|
@@ -0,0 +1,940 @@
|
|
|
+<template>
|
|
|
+ <div v-clickoutside="handleClose" :class="classes" ref='pSelect'>
|
|
|
+ <div
|
|
|
+ :disabled="disabled"
|
|
|
+ :class="headerClass"
|
|
|
+ @click="handleOpen"
|
|
|
+ @mouseenter.stop="handleHideShowClearIcon(true)"
|
|
|
+ @mouseleave.stop="handleHideShowClearIcon(false)"
|
|
|
+ :style="headerStyle" >
|
|
|
+ <span class="p-select-title" ref="caption" v-if="caption" >{{caption}}</span>
|
|
|
+ <span class="p-select-selected-box" >
|
|
|
+ <input
|
|
|
+ :class="[this.prefixCls + '-input']"
|
|
|
+ :style="placeholderStyle"
|
|
|
+ :disabled='disabled'
|
|
|
+ @blur="handleBlur"
|
|
|
+ @input="handleInput"
|
|
|
+ @focus.stop="handleFocus"
|
|
|
+ type="text"
|
|
|
+ ref="input"
|
|
|
+ autocomplete="off"
|
|
|
+ spellcheck="false"
|
|
|
+ v-model="selectedItem"
|
|
|
+ />
|
|
|
+ <span
|
|
|
+ class="p-select-fakePlaceholder"
|
|
|
+ :style="placeholderStyle"
|
|
|
+ v-show="showPlaceholder"
|
|
|
+ v-html="fakePlaceholder">
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+ <Triangle v-show="!clearable" :class="triangleClass"></Triangle>
|
|
|
+ <Remove class="p-select-clear" @click.stop="clearAll" v-show="!hideClear && clearable"></Remove>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import createPopover from './popover'
|
|
|
+import Drop from './Drop.vue'
|
|
|
+import Triangle from './static/iconSvg/triangle.svg'
|
|
|
+import Remove from './static/iconSvg/clear2.svg'
|
|
|
+import iconClose from './static/iconSvg/icon_close.svg'
|
|
|
+import clickoutside from './clickoutside.js'
|
|
|
+import Options from './dropdown'
|
|
|
+import {zIndexIncrease, zIndex} from './dispatchZindex'
|
|
|
+
|
|
|
+export default {
|
|
|
+ name: "pSelect",
|
|
|
+ inheritAttrs: false,
|
|
|
+ directives: {
|
|
|
+ 'clickoutside':clickoutside,
|
|
|
+ },
|
|
|
+ components: { Triangle, Drop, iconClose,Remove},
|
|
|
+ computed:{
|
|
|
+ classes () {
|
|
|
+ return [
|
|
|
+ `${this.prefixCls}`,
|
|
|
+ {
|
|
|
+ [`${this.prefixCls}-multiple`]: this.multiple,
|
|
|
+ }
|
|
|
+ ];
|
|
|
+ },
|
|
|
+ headerClass () {
|
|
|
+ return [
|
|
|
+ 'p-select-header',
|
|
|
+ {
|
|
|
+ ['p-select-header-radius']:this.radius,
|
|
|
+ ['p-select-header-focused']: this.focused && !this.disabled,
|
|
|
+ ['p-select-header-disabled']: this.disabled
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ headerStyle () {
|
|
|
+ return {
|
|
|
+ width : this.width + 'px',
|
|
|
+ borderRadius: this.radius ? '16px' : '4px',
|
|
|
+ backgroundColor: this.disabled ? '#EFF0F1' :'white',
|
|
|
+ }
|
|
|
+ },
|
|
|
+ triangleClass () {
|
|
|
+ return [ 'p-select-triangle', this.dropInstance && this.dropInstance.dropVisible ? 'p-select-triangle-up' : 'p-select-triangle-down']
|
|
|
+ },
|
|
|
+
|
|
|
+ placeholderStyle () {
|
|
|
+ let code = 0
|
|
|
+ if (this.caption) {
|
|
|
+ code = this.caption.charCodeAt(this.caption.length - 1)
|
|
|
+ if (code === 65306) {
|
|
|
+ return {
|
|
|
+ paddingLeft : 0,
|
|
|
+ transform: 'translateX(-2px)',
|
|
|
+ cursor:this.disabled ? 'not-allowed': 'pointer'
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return {
|
|
|
+ paddingLeft: code === 58 ? '8px' : '12px', // 中文冒号还是英文冒号
|
|
|
+ cursor:this.disabled ? 'not-allowed': 'pointer'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tipText:{
|
|
|
+ get(){
|
|
|
+ const data=JSON.parse(JSON.stringify(this.confirmedItems));
|
|
|
+ const len=data.length-1;
|
|
|
+ let text='';
|
|
|
+ data.forEach((d, i) => {
|
|
|
+ if (i<len) {
|
|
|
+ text+=d.name+'、';
|
|
|
+ } else {
|
|
|
+ text+=d.name;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return text;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ fakePlaceholder () {
|
|
|
+ if (this.multiple) {
|
|
|
+ const len =this.confirmedItems.length
|
|
|
+ if (len) {
|
|
|
+ if (this.dropInstance && this.dropInstance.dropVisible) {
|
|
|
+ return `已选择<span style="margin:0 4px">${len}</span>项`
|
|
|
+ } else {
|
|
|
+ return `<span style="color:#1F2329">已选择<span style="margin:0 4px; color:#0091FF">${len}</span>项</span>`
|
|
|
+ }
|
|
|
+
|
|
|
+ } else {
|
|
|
+ return this.placeholder
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.currentSelectedItem) {
|
|
|
+ const name = this.currentSelectedItem.name
|
|
|
+ if (this.dropInstance && this.dropInstance.dropVisible) {
|
|
|
+ return name
|
|
|
+ } else {
|
|
|
+ return `<span style="color:#1F2329">${name}</span>`
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return this.placeholder
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch : {
|
|
|
+ query (n,o) {
|
|
|
+ if (n === o) return;
|
|
|
+ if (!n && this.dropInstance) {
|
|
|
+ this.selectedItem = ''
|
|
|
+ }
|
|
|
+ },
|
|
|
+ selectedItem(n, o) {
|
|
|
+ if (n === o) return;
|
|
|
+ this.showPlaceholder = !n;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 下拉列表数据
|
|
|
+ */
|
|
|
+ selectdata:{
|
|
|
+ handler (n, o) {
|
|
|
+ if (n !== o) {
|
|
|
+ console.log("data change...........")
|
|
|
+ this.dropData = this.cloneDeep(n)
|
|
|
+ this.dropData.forEach(item => {
|
|
|
+ this.$set(item,'selected',false)
|
|
|
+ })
|
|
|
+ this.defaultSelect()
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.data = this.dropData
|
|
|
+ this.resetDropPanelPos()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep:true,
|
|
|
+ immediate: true
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 默认选中项
|
|
|
+ */
|
|
|
+ value:{
|
|
|
+ handler(n, o) {
|
|
|
+ if (n !== o && n) {
|
|
|
+ this.defaultSelect()
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.value=n
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate:true
|
|
|
+ },
|
|
|
+ },
|
|
|
+ props: {
|
|
|
+ placeholder:{
|
|
|
+ type:String,
|
|
|
+ default:''
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 是否多选
|
|
|
+ */
|
|
|
+ multiple:{
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ count:{
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 绑定的v-model值
|
|
|
+ */
|
|
|
+ value: {
|
|
|
+ type: [String, Number, Array],
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 下拉列表数据
|
|
|
+ */
|
|
|
+ selectdata: {
|
|
|
+ type: Array,
|
|
|
+ default: () => []
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 宽度
|
|
|
+ */
|
|
|
+ width: {
|
|
|
+ type: [String, Number],
|
|
|
+ default: '200'
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 是否设置圆角
|
|
|
+ */
|
|
|
+ radius: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ /**是否设置标题 */
|
|
|
+ caption:{
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ /**是否是禁止选中 */
|
|
|
+ disabled:{
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ // 提示框位置
|
|
|
+ tipPlace: {
|
|
|
+ type: String,
|
|
|
+ default: ''
|
|
|
+ },
|
|
|
+ // 是否显示触发器上的清空图标
|
|
|
+ hideClear: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
+ },
|
|
|
+ transfer:{ // 需要监听滚动的dom元素的ID
|
|
|
+ type:String,
|
|
|
+ default:''
|
|
|
+ }
|
|
|
+
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ prefixCls:'p-select',
|
|
|
+ selectedItems:[], // 多选条件下被选项集合
|
|
|
+ selectedItem:'', // 单选条件下被选选
|
|
|
+ selectedItemsText:'', // 多选条件下已选项提示框
|
|
|
+ dropVisible:false, // 控制下拉列表的显示隐藏,
|
|
|
+ getScroll:null,
|
|
|
+ queryItems:[], // 搜索下拉框
|
|
|
+ query:'', // 搜索项
|
|
|
+ showPlaceholder: true, // 是否显示占位符
|
|
|
+ showInputText:false, //控制输入文字的显示隐藏
|
|
|
+ showCount:false, // 控制显示隐藏已选项的提示文本
|
|
|
+ dropData:[], // 下拉框绑定数据
|
|
|
+ dropInstance:null, // 下拉框实例
|
|
|
+ popoverInstance:null, // 弹出框
|
|
|
+ currentSelectedItem: null,
|
|
|
+ confirmedItems: [], // 点击确认所提交的数据
|
|
|
+ focused:false, // 判断当前是否处于获取焦点的状态
|
|
|
+ storeInput: '',
|
|
|
+ storePlaceholder:'',
|
|
|
+ selectedTipStyle: { bottom: 0, left: 0 },
|
|
|
+ clearable:false,
|
|
|
+ timer:null,
|
|
|
+ timer2:null,
|
|
|
+ scrollDom:null
|
|
|
+ }
|
|
|
+ },
|
|
|
+ created(){
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted () {
|
|
|
+ document.addEventListener('mousewheel', this.throttleWheel, false);
|
|
|
+ if (this.transfer) {
|
|
|
+ let transfer = this.transfer
|
|
|
+ if (!transfer.startsWith("#")) {
|
|
|
+ transfer = "#" + transfer
|
|
|
+ }
|
|
|
+ this.scrollDom = document.querySelector(transfer)
|
|
|
+ if (this.scrollDom) {
|
|
|
+ this.scrollDom.addEventListener('mousewheel', this.listenDomScroll, false)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ listenDomScroll(){
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ throttleWheel () {
|
|
|
+ if (this.timer2) clearTimeout(this.timer2);
|
|
|
+ this.timer2 = setTimeout(()=>{
|
|
|
+ this.wheelListenter()
|
|
|
+ this.timer2 = null
|
|
|
+ }, 300)
|
|
|
+ },
|
|
|
+ handleHideShowClearIcon (bool) {
|
|
|
+ this.handleTipShow(bool)
|
|
|
+ if (this.hideClear) return;
|
|
|
+ if (this.multiple) {
|
|
|
+ if (this.confirmedItems.length) {
|
|
|
+ this.clearable = bool
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.currentSelectedItem) {
|
|
|
+ this.clearable = bool
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ clearAll () {
|
|
|
+ if (this.multiple) {
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.popoverInstance.showTip = false
|
|
|
+ }
|
|
|
+ this.confirmedItems = []
|
|
|
+ this.selectedItems = []
|
|
|
+ this.clearable = false
|
|
|
+ this.selectConfirmData(this.selectedItems)
|
|
|
+ if (this.dropInstance) {
|
|
|
+ if (this.dropInstance.dropVisible) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.$emit('input', [])
|
|
|
+ } else {
|
|
|
+ this.clearable = false
|
|
|
+ this.currentSelectedItem = null
|
|
|
+ this.selectSingleItem()
|
|
|
+ if (this.dropInstance) {
|
|
|
+ if (this.dropInstance.dropVisible) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.$emit('input', '')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ handleTipShow (bool) {
|
|
|
+ if(!this.confirmedItems.length) return;
|
|
|
+ if (this.dropInstance) {
|
|
|
+ if (this.dropInstance.showCascader) return;
|
|
|
+ }
|
|
|
+ if (this.tipText && this.tipPlace) {
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.resetPopoverPos()
|
|
|
+ this.popoverInstance.showTip = bool
|
|
|
+ } else {
|
|
|
+ if (this.caption) {
|
|
|
+ this.captionW = this.$refs.caption.getBoundingClientRect().width
|
|
|
+ }
|
|
|
+ this.leftW = this.caption ? this.captionW + 68 : 68
|
|
|
+ if (this.confirmedItems.length > 9) {
|
|
|
+ this.leftW = this.leftW + 8
|
|
|
+ }
|
|
|
+ this.popoverInstance = createPopover({
|
|
|
+ tag: this.$refs.pSelect ,
|
|
|
+ props:{
|
|
|
+ innertext: this.tipText,
|
|
|
+ leftW:this.leftW,
|
|
|
+ tipPlace:this.tipPlace
|
|
|
+ }
|
|
|
+ }).$on('sotrePOs', (pos) => {
|
|
|
+ this.tDom = pos
|
|
|
+ this.popoverInstance.$nextTick(()=>{
|
|
|
+ this.popoverInstance.showTip = true
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ resetPopoverPos ( ) {
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.popoverInstance.innertext = this.tipText
|
|
|
+ const pDom = this.$refs.pSelect.getBoundingClientRect()
|
|
|
+ this.leftW = this.caption ? this.captionW + 68 : 68
|
|
|
+ if (this.confirmedItems.length > 9) {
|
|
|
+ this.leftW = this.leftW + 8
|
|
|
+ }
|
|
|
+ const pos = createPopover.resetPosition(pDom, this.tDom, this.leftW, this.tipPlace, 12)
|
|
|
+ if (pos.finalBottom) {
|
|
|
+ this.popoverInstance.popoverStyle={
|
|
|
+ left: pos.finalLeft + 'px',
|
|
|
+ bottom: pos.finalBottom + 'px'
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.popoverInstance.popoverStyle={
|
|
|
+ top: pos.finalTop+ 'px',
|
|
|
+ left: pos.finalLeft + 'px',
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (pos.tranigleBottom) {
|
|
|
+ this.popoverInstance.tranigleStyle = {
|
|
|
+ bottom: pos.tranigleBottom+ 'px',
|
|
|
+ left: pos.tranigleLeft + 'px'
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ this.popoverInstance.tranigleStyle = {
|
|
|
+ top: pos.tranigleTop+ 'px',
|
|
|
+ left: pos.tranigleLeft + 'px'
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ wheelListenter () {
|
|
|
+ this.$refs.input.blur()
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ }
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.popoverInstance.showTip = false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ defaultSelect () {
|
|
|
+ if (!this.value) return;
|
|
|
+ if (this.multiple) {
|
|
|
+ if (Array.isArray(this.value) && this.value.length) {
|
|
|
+ this.confirmedItems = []
|
|
|
+ this.selectedItems= []
|
|
|
+ this.value.forEach(val => {
|
|
|
+ const index = this.dropData.findIndex(item => {return item.id === val})
|
|
|
+ if (index > -1) {
|
|
|
+ this.confirmedItems.push(this.dropData[index])
|
|
|
+ this.selectedItems.push(this.dropData[index])
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if (this.confirmedItems.length) {
|
|
|
+ this.showPlaceholder = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if (this.value.toString().trim()) {
|
|
|
+ this.dropData.forEach(item => {
|
|
|
+ if (item.id === this.value.toString().trim()) {
|
|
|
+ this.currentSelectedItem = item
|
|
|
+ }
|
|
|
+ })
|
|
|
+ this.showPlaceholder = true
|
|
|
+ this.selectSingleItem()
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * description 深度克隆对象
|
|
|
+ * params obj 需要克隆的对象
|
|
|
+ */
|
|
|
+ cloneDeep(obj) {
|
|
|
+ if (typeof obj !=='object' || obj === null) {
|
|
|
+ return obj
|
|
|
+ }
|
|
|
+ const newObj = Array.isArray(obj) ? [] : {}
|
|
|
+ for (const key in obj) {
|
|
|
+ if (typeof obj[key] === 'object') {
|
|
|
+ newObj[key] = this.cloneDeep(obj[key] )
|
|
|
+ } else {
|
|
|
+ newObj[key] = obj[key]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return newObj
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 处理用户输入事件
|
|
|
+ * params event事件对象
|
|
|
+ */
|
|
|
+ handleInput (event) {
|
|
|
+ this.query = event.target.value || event.data || ''
|
|
|
+ this.showPlaceholder = !this.query
|
|
|
+ if (!this.dropInstance) return
|
|
|
+ if (this.query) {
|
|
|
+ this.dropInstance.query = this.query
|
|
|
+ this.dropInstance.data = this.findSelectedItem()
|
|
|
+ } else {
|
|
|
+ if (!this.multiple) {
|
|
|
+ this.selectSingleItem()
|
|
|
+ } else {
|
|
|
+ this.dropData.forEach(item => {delete item.display})
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ selectSingleItem () {
|
|
|
+ if (this.currentSelectedItem) {
|
|
|
+ this.dropData.forEach(item => {
|
|
|
+ delete item.display
|
|
|
+ if (item.id === this.currentSelectedItem.id) {
|
|
|
+ item.selected = true
|
|
|
+ } else {
|
|
|
+ item.selected = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ this.dropData.forEach(item => {
|
|
|
+ delete item.display
|
|
|
+ item.selected = false
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if ( this.dropInstance) {
|
|
|
+ this.dropInstance.data = this.dropData
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 处理点击事件
|
|
|
+ * params option 选中项
|
|
|
+ */
|
|
|
+ optionClick (option) {
|
|
|
+ if (option.disabled) return
|
|
|
+ if (this.multiple) {
|
|
|
+ if (option.selected) {
|
|
|
+ this.selectedItems.push(option)
|
|
|
+ this.$emit('change', option)
|
|
|
+ } else {
|
|
|
+ const index = this.selectedItems.findIndex((item) => {return item.id===option.id})
|
|
|
+ if (index > -1) {
|
|
|
+ this.selectedItems.splice(index,1)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.disableConfirmBtn()
|
|
|
+ } else {
|
|
|
+ if (!this.dropInstance) return
|
|
|
+ this.currentSelectedItem = option
|
|
|
+ this.query = ''
|
|
|
+ this.selectSingleItem()
|
|
|
+ this.dropInstance.data = this.dropData
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ const emitData = this.cloneDeep(option)
|
|
|
+ delete emitData.index
|
|
|
+ delete emitData.selected
|
|
|
+ this.$emit('input', emitData.id)
|
|
|
+ this.$emit('change', emitData)
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ /**
|
|
|
+ * description 根据输入内容筛选匹配项
|
|
|
+ */
|
|
|
+ findSelectedItem () {
|
|
|
+ const selections = []
|
|
|
+ this.dropData.forEach(item => {
|
|
|
+ item.display = item.name
|
|
|
+ selections.push(item)
|
|
|
+ })
|
|
|
+ const foundItems = selections.filter(item => {
|
|
|
+ return item.name ? item.name.indexOf(this.query) > -1 : false
|
|
|
+ }).map(item => {
|
|
|
+ item.display = item.display.replace(new RegExp(this.query, 'g'), `<span style="color:#0091FF">${this.query}</span>`)
|
|
|
+ return item
|
|
|
+ })
|
|
|
+ if(foundItems.length ) {
|
|
|
+ foundItems.forEach(item => {
|
|
|
+ const index = this.selectedItems.findIndex(option => {return item.id === option.id})
|
|
|
+ if (index > -1) {
|
|
|
+ item.selected = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ return foundItems
|
|
|
+ },
|
|
|
+ resetDropPanelPos () {
|
|
|
+ const props = {
|
|
|
+ data: this.dropData,
|
|
|
+ multiple: this.multiple
|
|
|
+ }
|
|
|
+ Options.resetPos(this.dropInstance, this.$refs.pSelect, document.body,props)
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 下拉框在打开和合上之间切换状态
|
|
|
+ */
|
|
|
+ handleOpen () {
|
|
|
+ if (this.disabled) return
|
|
|
+ if (this.dropInstance) {
|
|
|
+ if (this.multiple && this.confirmedItems.length) {
|
|
|
+ this.disableConfirmBtn()
|
|
|
+ }
|
|
|
+ this.dropInstance.dropVisible=true
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.popoverInstance.showTip = false
|
|
|
+ }
|
|
|
+ this.resetDropPanelPos()
|
|
|
+ } else {
|
|
|
+ zIndexIncrease()
|
|
|
+ const data=this.dropData, value=this.value, multiple = this.multiple
|
|
|
+ // 初始化实例
|
|
|
+ this.dropInstance=Options({
|
|
|
+ tag: this.$refs.pSelect, data:{value, zIndex}, props:{multiple, query: this.query, value, data}
|
|
|
+ }).$on('change', (option) => {
|
|
|
+ this.optionClick(option)
|
|
|
+ }).$on('cancel' ,() => {
|
|
|
+ this.emitCancel()
|
|
|
+ }).$on('confirm' ,() => {
|
|
|
+ this.emitConfirm()
|
|
|
+ })
|
|
|
+ if (this.multiple && this.confirmedItems.length) {
|
|
|
+ this.selectConfirmData(this.confirmedItems)
|
|
|
+ } else {
|
|
|
+ this.selectSingleItem()
|
|
|
+ }
|
|
|
+ this.dropInstance.$nextTick(() => {
|
|
|
+ this.dropInstance.dropVisible=true
|
|
|
+ if (this.popoverInstance) {
|
|
|
+ this.popoverInstance.showTip = false
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 处理获取焦点的事件
|
|
|
+ */
|
|
|
+ handleFocus () {
|
|
|
+ this.focused = true
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ *description 输入框失去焦点的事件
|
|
|
+ */
|
|
|
+ handleBlur () {
|
|
|
+ this.focused = false
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 向父组件传递取消并关闭下拉框
|
|
|
+ */
|
|
|
+ emitCancel () {
|
|
|
+ if(this.dropInstance){
|
|
|
+ this.query = ''
|
|
|
+ this.selectedItems = []
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ this.selectConfirmData(this.confirmedItems)
|
|
|
+ this.disableConfirmBtn()
|
|
|
+ this.$emit('cancel')
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 向父组件传递确认事件并关闭下拉框
|
|
|
+ */
|
|
|
+ emitConfirm () {
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ this.confirmedItems = this.cloneDeep(this.selectedItems)
|
|
|
+ this.query = ''
|
|
|
+ const emitData = this.cloneDeep(this.selectedItems)
|
|
|
+ const ids = []
|
|
|
+ emitData.forEach(item=>{
|
|
|
+ delete item.index
|
|
|
+ delete item.selected
|
|
|
+ ids.push(item.id)
|
|
|
+ })
|
|
|
+ this.$emit('input', ids)
|
|
|
+ this.$emit('confirm', emitData)
|
|
|
+
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 关闭下拉列表
|
|
|
+ */
|
|
|
+ handleClose () {
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ this.query = ''
|
|
|
+ if (this.multiple) {
|
|
|
+ this.selectedItems = []
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.selectConfirmData(this.confirmedItems)
|
|
|
+ },500)
|
|
|
+ } else {
|
|
|
+ setTimeout(()=>{
|
|
|
+ this.selectSingleItem()
|
|
|
+ },500)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ *
|
|
|
+ */
|
|
|
+ selectConfirmData (data) {
|
|
|
+ if (!this.dropInstance) return
|
|
|
+ this.dropData.forEach(option => {
|
|
|
+ const index = data.findIndex((item) => {return item.id===option.id})
|
|
|
+ if (index > -1) {
|
|
|
+ option.selected = true
|
|
|
+ } else {
|
|
|
+ option.selected = false
|
|
|
+ }
|
|
|
+ delete option.display
|
|
|
+ })
|
|
|
+ if (this.confirmedItems.length) {
|
|
|
+ this.selectedItems = this.cloneDeep(this.confirmedItems)
|
|
|
+ }
|
|
|
+ this.selectedItem = ''
|
|
|
+ this.dropInstance.data = this.dropData
|
|
|
+ },
|
|
|
+ disableConfirmBtn () {
|
|
|
+ if (!this.dropInstance) return
|
|
|
+ if( (this.confirmedItems.length !== this.selectedItems.length) ) {
|
|
|
+ this.dropInstance.disableConfirm = false
|
|
|
+ } else {
|
|
|
+ let flag = this.confirmedItems.every((item) => {
|
|
|
+ return this.selectedItems.findIndex(option => { return option.id === item.id}) > -1
|
|
|
+ })
|
|
|
+ if (!this.confirmedItems.length && this.selectedItems.length) {
|
|
|
+ flag = false
|
|
|
+ }
|
|
|
+ if (!this.confirmedItems.length && !this.selectedItems.length) {
|
|
|
+ flag = true
|
|
|
+ }
|
|
|
+ if (flag) {
|
|
|
+ this.dropInstance.disableConfirm = true
|
|
|
+ } else {
|
|
|
+ this.dropInstance.disableConfirm = false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * description 组件销毁
|
|
|
+ */
|
|
|
+ beforeDestroy() {
|
|
|
+ if (this.dropInstance) {
|
|
|
+ this.dropInstance.dropVisible = false
|
|
|
+ Options.remove(this.dropInstance)
|
|
|
+ createPopover.remove(this.popoverInstance)
|
|
|
+ }
|
|
|
+ document.removeEventListener('mousewheel',this.throttleWheel)
|
|
|
+ if (this.transfer) {
|
|
|
+ this.scrollDom.removeEventListener('mousewheel', this.listenDomScroll)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="stylus">
|
|
|
+ @import "./static/stylus/animate/selectDownUp.styl"
|
|
|
+ @import "./static/stylus/palette.styl"
|
|
|
+ .p-select
|
|
|
+ position relative
|
|
|
+ display inline-block
|
|
|
+ vertical-align middle
|
|
|
+ cursor pointer
|
|
|
+ outline none
|
|
|
+ .p-select-drop-down
|
|
|
+ position fixed;
|
|
|
+ .p-select-not-found
|
|
|
+ height 54px
|
|
|
+ padding 16px 0 16px 12px
|
|
|
+ border 1px solid $grey-300
|
|
|
+ border-radius 4px
|
|
|
+ line-height 22px
|
|
|
+ font-size 14px
|
|
|
+ color $grey-400
|
|
|
+ background:$white
|
|
|
+ box-shadow $box-shadow-bottom
|
|
|
+ box-sizing border-box
|
|
|
+ .p-select-header
|
|
|
+ position relative
|
|
|
+ display flex
|
|
|
+ min-height 32px
|
|
|
+ height 32px
|
|
|
+ width 100%
|
|
|
+ box-sizing border-box
|
|
|
+ border 1px solid $grey-400
|
|
|
+ border-radius 4 px
|
|
|
+ cursor pointer
|
|
|
+ text-align left
|
|
|
+ .p-select-count
|
|
|
+ color $grey-900
|
|
|
+ font-size 14px
|
|
|
+ line-height 30px
|
|
|
+ padding-left 12px
|
|
|
+ .p-select-count-active
|
|
|
+ color $blue-500
|
|
|
+ margin 0 4px
|
|
|
+ .p-select-title
|
|
|
+ display inline-block
|
|
|
+ padding 0 0 0 12px
|
|
|
+ height 30px
|
|
|
+ line-height 30px
|
|
|
+ font-size 14px
|
|
|
+ flex-shrink 0
|
|
|
+ color $grey-500
|
|
|
+ pointer-events none
|
|
|
+ .p-select-selected-box
|
|
|
+ position relative
|
|
|
+ flex-shrink 1
|
|
|
+ display inline-block
|
|
|
+ width 100%
|
|
|
+ box-sizing border-box
|
|
|
+ color $grey-900
|
|
|
+ font-size 14px
|
|
|
+ .p-select-input, .p-select-fakePlaceholder
|
|
|
+ display inline-block
|
|
|
+ position absolute
|
|
|
+ left 0
|
|
|
+ top 0
|
|
|
+ padding-left 12px
|
|
|
+ line-height 30px
|
|
|
+ width 100%
|
|
|
+ font-size 14px
|
|
|
+ border none
|
|
|
+ outline none
|
|
|
+ .p-select-fakePlaceholder
|
|
|
+ //z-index 999
|
|
|
+ pointer-events none
|
|
|
+ color $grey-400
|
|
|
+ line-height 30px
|
|
|
+ padding-right 32px
|
|
|
+ overflow hidden
|
|
|
+ text-overflow ellipsis
|
|
|
+ white-space nowrap
|
|
|
+ .p-select-input
|
|
|
+ //z-index 1
|
|
|
+ line-height 30px
|
|
|
+ height 30px
|
|
|
+ padding-right 32px
|
|
|
+ background transparent
|
|
|
+ .p-select-input-fakePlaceholder
|
|
|
+ color $grey-900
|
|
|
+ .p-select-triangle
|
|
|
+ position absolute
|
|
|
+ //z-index 999
|
|
|
+ top 8px
|
|
|
+ right 10px
|
|
|
+ width 16px
|
|
|
+ height 16px
|
|
|
+ transform-origin center center
|
|
|
+ transform rotate(180deg)
|
|
|
+ transition transform 0.3s
|
|
|
+ will-change rotate
|
|
|
+ .p-select-clear
|
|
|
+ position absolute
|
|
|
+ //z-index 999
|
|
|
+ top 8px
|
|
|
+ right 10px
|
|
|
+ width 14px
|
|
|
+ height 14px
|
|
|
+ path
|
|
|
+ fill $grey-300
|
|
|
+ transition fill 0.5s
|
|
|
+ &:hover
|
|
|
+ path
|
|
|
+ fill $blue-500
|
|
|
+ .p-select-triangle-up
|
|
|
+ transform rotate(0deg)
|
|
|
+ .p-select-triangle-down
|
|
|
+ transform rotate(180deg)
|
|
|
+ &:hover
|
|
|
+ border 1px solid $blue-500
|
|
|
+ transition 0.3s
|
|
|
+ .p-select-input-tip
|
|
|
+ position: absolute
|
|
|
+ padding: 16px 20px
|
|
|
+ background-color: $white
|
|
|
+ border-radius: 4px
|
|
|
+ pointer-events: none
|
|
|
+ max-width: 280px
|
|
|
+ max-height: 104px
|
|
|
+ z-index: 100
|
|
|
+ &:after
|
|
|
+ position: absolute
|
|
|
+ display: inline-block
|
|
|
+ border-style: solid
|
|
|
+ border-width: 4px
|
|
|
+ width: 0
|
|
|
+ height: 0
|
|
|
+ transform: rotate(-45deg)
|
|
|
+ z-index: 0
|
|
|
+ content: ''
|
|
|
+ .p-select-input-tip-item
|
|
|
+ position: relative
|
|
|
+ overflow: hidden
|
|
|
+ max-height: 66px
|
|
|
+ line-height: 22px
|
|
|
+ font-size: 14px
|
|
|
+ word-wrap: break-word
|
|
|
+ word-break: break-all
|
|
|
+ .p-select-input-tip-overflow
|
|
|
+ &:after
|
|
|
+ position: absolute
|
|
|
+ right: 0
|
|
|
+ bottom: 0
|
|
|
+ display: inline-block
|
|
|
+ width: 20px
|
|
|
+ height: 22px
|
|
|
+ background-color: $white
|
|
|
+ content: '...'
|
|
|
+ .p-select-input-tip-top
|
|
|
+ box-shadow: $box-shadow-bottom
|
|
|
+ &:after
|
|
|
+ bottom: -4px
|
|
|
+ left: 58px
|
|
|
+ border-color: transparent transparent $white $white
|
|
|
+ box-shadow: $box-shadow-min-top
|
|
|
+ z-index: -1
|
|
|
+ .p-select-input-tip-bottom
|
|
|
+ box-shadow: $box-shadow-left
|
|
|
+ &:after
|
|
|
+ top: -4px
|
|
|
+ left: 58px
|
|
|
+ border-color: $white $white transparent transparent
|
|
|
+ box-shadow: $box-shadow-min-bottom
|
|
|
+ .p-select-input-tip-left
|
|
|
+ box-shadow: $box-shadow-right
|
|
|
+ &:after
|
|
|
+ top: 49%
|
|
|
+ right: -4px
|
|
|
+ border-color: transparent $white $white transparent
|
|
|
+ box-shadow: $box-shadow-min-right
|
|
|
+ .p-select-input-tip-right
|
|
|
+ box-shadow: $box-shadow-top
|
|
|
+ &:after
|
|
|
+ top: 49%
|
|
|
+ left: -4px
|
|
|
+ border-color: $white transparent transparent $white
|
|
|
+ box-shadow: $box-shadow-min-left
|
|
|
+ .p-select-header-radius
|
|
|
+ border 1px solid $grey-400
|
|
|
+ border-radius 12px
|
|
|
+ .p-select-header-focused
|
|
|
+ border 1px solid $blue-500
|
|
|
+ box-shadow $box-shadow-blue
|
|
|
+ transition 0.3s
|
|
|
+ .p-select-header-disabled
|
|
|
+ background:$red-200
|
|
|
+ cursor:not-allowed
|
|
|
+ &:hover
|
|
|
+ border 1px solid $grey-300
|
|
|
+</style>
|