用vue如何实现类似jQuery selectable框选元素的效果?

jQuery-UI selectable的框选元素的功能非常好用,想要在vue上也实现一个类似的。找了一轮,找到一个用指令实现的,但是有个问题,它选中后无法触发到其他组件内的方法,导致不知道它到底选了哪些元素。
请问一下有什么更好的实现方法?
图片描述

阅读 3.5k
1 个回答

http://www.cnblogs.com/mdengc... google了一下 实现这v-selectable 不知道符合要求不

export default (Vue, options = {}) =>{
    const listener = (ele, binding) =>{
        let reactArea = {
            startX: 0,
            startY: 0,
            endX: 0,
            endY: 0
        }
        //是否一直按下鼠标
        let isMouseDown = false
        let areaSelect = {}
        //将元素定位改为relative
        ele.style.position = 'relative'
        ele.addEventListener('mousedown', function(e) {
            reactArea.startX = e.layerX;
            reactArea.startY = e.layerY;
            isMouseDown = true
        })

        ele.addEventListener('mousemove', function(e) {
             if(isMouseDown){
                 let preArea = ele.getElementsByClassName('v-selected-area')
                if(preArea.length){
                    ele.removeChild(preArea[0])
                }
                reactArea.endX = e.layerX
                reactArea.endY = e.layerY
                let leftValue = 0
                let topValue = 0
                let widthValue = Math.abs(reactArea.startX - reactArea.endX)
                let heightValue =  Math.abs(reactArea.startY - reactArea.endY)

                if(reactArea.startX >= reactArea.endX){
                    leftValue = reactArea.endX
                }else{
                    leftValue = reactArea.startX
                }
                if(reactArea.startY > reactArea.endY ){
                    topValue = reactArea.endY
                }else{
                    topValue = reactArea.startY
                }

                //判断同时有宽高才开始画虚线框
                if(reactArea.startX != reactArea.endX && reactArea.startY !=reactArea.endY){
                    areaSelect = document.createElement('div')
                    areaSelect.classList.add("v-selected-area")
                    areaSelect.style.position = "absolute";
                    areaSelect.style.left = leftValue + 'px'
                    areaSelect.style.top = topValue + 'px'
                    areaSelect.style.width = widthValue + 'px'
                    areaSelect.style.height = heightValue + 'px'
                    areaSelect.style.border = "1px dashed grey"
                    ele.append(areaSelect)
                }

                let children = ele.getElementsByTagName('li')
                for(let i =0 ; i < children.length ; i ++ ){
                    let childrenHeight = children[i].getBoundingClientRect().height
                    let childrenWidth = children[i].getBoundingClientRect().width
                    //每个li元素的位置
                    let offsetLeft = children[i].offsetLeft
                    let offsetTop = children[i].offsetTop
                    //每个li元素的宽高
                    let endPositionH = childrenHeight + offsetTop
                    let endPositionW = childrenWidth + offsetLeft
                    //五个条件满足一个就可以判断被选择
                    //一是右下角在选择区域内
                    let require1 = endPositionH > topValue && endPositionW > leftValue && endPositionH < topValue + heightValue && endPositionW < leftValue + widthValue
                    //二是左上角在选择区域内
                    let require2 = offsetTop > topValue && offsetLeft > leftValue && offsetTop < topValue + heightValue && offsetLeft < leftValue + widthValue
                    //三是右上角在选择区域内
                    let require3 = offsetTop > topValue && offsetLeft + childrenWidth > leftValue && offsetTop < topValue + heightValue && offsetLeft + childrenWidth< leftValue + widthValue
                    //四是左下角在选择区域内
                    let require4 = offsetTop + childrenHeight > topValue && offsetLeft > leftValue && offsetTop + childrenHeight < topValue + heightValue && offsetLeft < leftValue + widthValue
                    //五选择区域在元素体内
                    let require5 = offsetTop < topValue && offsetLeft < leftValue && offsetTop + childrenHeight > topValue + heightValue && offsetLeft + childrenWidth > leftValue + widthValue

                    if(require1 || require2 || require3 || require4 || require5){
                        children[i].classList.add('active')
                    }else{
                        children[i].classList.remove('active')
                    }
                }
             }
        })

        ele.addEventListener('mouseup', function(e) {
            isMouseDown = false
            if(areaSelect && areaSelect.childNodes && ele.contains(areaSelect)){
                ele.removeChild(areaSelect)
            }
            areaSelect = null
        })
    }

     Vue.directive('selectable',{
        inserted:listener,
        updated:listener
    })
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题