V587phenix
V587phenix
  • 发布:2020-12-09 10:39
  • 更新:2020-12-09 10:39
  • 阅读:698

【报Bug】mousemove事件 v-model绑定更新input卡顿不流畅

分类:uni-app

产品分类: uniapp/H5

PC开发环境操作系统: Windows

PC开发环境操作系统版本号: win 10家庭中文版

HBuilderX类型: 正式

HBuilderX版本号: 2.9.8

浏览器平台: Chrome

浏览器版本: 版本 87.0.4280.88(正式版本) (64 位)

项目创建方式: HBuilderX

示例代码:

组件 number-box.vue

<template>  
    <view class="uni-numbox" v-if="mode === 'drag'">  
        <!-- 可拖拽式标签 -->  
        <view @mousedown="touchstart" @touchmove="touchmove">  
            <slot>  
                <text class="drag-label" :style="cptFontSize">{{label}}</text>  
            </slot>  
        </view>  
        <input :disabled="disabled" @blur="_onBlur" class="uni-numbox__value-drag" type="number"  v-model="inputValue" :placeholder="`${inputValue}`"  
         :style="cptValueStyle" />  
        <view class="action">  
            <view class="action-item" @click="_calcValue('plus')" :style="cptDragButtonStyle">  
                <text class="uni-numbox__text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }">▲</text>  
            </view>  
            <view class="action-item" @click="_calcValue('minus')" :style="cptDragButtonStyle">  
                <text class="uni-numbox__text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }">▼</text>  
            </view>  
        </view>  
        <view v-if="show" class="drag-range--mask"></view>  
    </view>  
    <view class="uni-numbox" v-else>  
        <view @click="_calcValue('minus')" class="uni-numbox__minus" :style="cptButtonStyle">  
            <text class="uni-numbox__text" :class="{ 'uni-numbox--disabled': inputValue <= min || disabled }">-</text>  
        </view>  
        <input :disabled="disabled" @blur="_onBlur" class="uni-numbox__value" type="number" v-model="inputValue" :style="cptValueStyle" />  
        <view @click="_calcValue('plus')" class="uni-numbox__plus" :style="cptButtonStyle">  
            <text class="uni-numbox__text" :class="{ 'uni-numbox--disabled': inputValue >= max || disabled }">+</text>  
        </view>  
    </view>  
</template>  
<script>  
    const sizeDef = ['small', 'normal', 'big']  
    const sizeDefMap = [8, 10, 14]  
    /**  
     * NumberBox 数字输入框  
     * @description 带加减按钮的数字输入框  
     * @tutorial https://ext.dcloud.net.cn/plugin?id=31  
     * @property {Number} value 输入框当前值  
     * @property {Number} min 最小值  
     * @property {Number} max 最大值  
     * @property {String, Number} size=[small|normal|big|Number] 设置组件大小size 【注意】显示空间不够请设置width  
     *   @value small  small -base:8  
     *   @value normal  normal -base:10  
     *   @value big  big -base:14  
     *   @value Number  任意数字 -base: number  
     * @property {Number} step 每次点击改变的间隔大小  
     * @property {Boolean} disabled = [true|false] 是否为禁用状态  
     * @property {String} mode = [button|drag]  显示样式  
     *  @value button 左右按键式  
     *  @value drag   可拖拽按键式  
     * @event {Function} change 输入框值改变时触发的事件,参数为输入框当前的 value  
     *   
     */  
    export default {  
        name: "NumberBox",  
        props: {  
            value: {  
                type: [Number, String],  
                default: 1  
            },  
            min: {  
                type: Number,  
                default: 0  
            },  
            max: {  
                type: Number,  
                default: 100  
            },  
            step: {  
                type: Number,  
                default: 1  
            },  
            disabled: {  
                type: Boolean,  
                default: false  
            },  
            mode: {  
                type: String,  
                default: 'button'  
            },  
            size: {  
                type: [String, Number],  
                default: 'normal'  
            },  
            label: String  
        },  
        data() {  
            return {  
                inputValue: 0,  
                show: false  
            };  
        },  
        watch: {  
            value(val) {  
                this.inputValue = +val;  
            },  
            inputValue(newVal, oldVal) {  
                if (+newVal !== +oldVal) {  
                    this.$emit("change", newVal);  
                }  
            }  
        },  
        computed: {  
            cptBase() {  
                let index = sizeDef.indexOf(this.size)  
                if (index > -1) {  
                    return sizeDefMap[index]  
                } else {  
                    return this.size  
                }  
            },  
            cptButtonStyle() {  
                return {  
                    width: 3 * this.cptBase + 'px',  
                    height: 3 * this.cptBase + 'px',  
                    fontSize: 2 * this.cptBase + 'px',  
                }  
            },  
            cptDragButtonStyle() {  
                return {  
                    fontSize: this.cptBase + 'px',  
                }  
            },  
            cptFontSize() {  
                return {  
                    fontSize: 1.5 * this.cptBase + 'px'  
                }  
            },  
            cptValueStyle() {  
                return {  
                    width: '100%',  
                    height: 3 * this.cptBase + 'px',  
                    ...this.cptFontSize  
                }  
            }  
        },  
        created() {  
            this.inputValue = +this.value;  
        },  
        methods: {  
            _calcValue(type) {  
                if (this.disabled) {  
                    return;  
                }  
                const scale = this._getDecimalScale();  
                let value = this.inputValue * scale;  
                let step = this.step * scale;  
                if (type === "minus") {  
                    value -= step;  
                    if (value < (this.min * scale)) {  
                        return;  
                    }  
                    if (value > (this.max * scale)) {  
                        value = this.max * scale  
                    }  
                } else if (type === "plus") {  
                    value += step;  
                    if (value > (this.max * scale)) {  
                        return;  
                    }  
                    if (value < (this.min * scale)) {  
                        value = this.min * scale  
                    }  
                }  

                this.inputValue = String(value / scale);  
            },  
            _getDecimalScale() {  
                let scale = 1;  
                // 浮点型  
                if (~~this.step !== this.step) {  
                    scale = Math.pow(10, (this.step + "").split(".")[1].length);  
                }  
                return scale;  
            },  
            _onBlur(event) {  
                let value = event.detail.value;  
                if (!value) {  
                    // this.inputValue = 0;  
                    return;  
                }  
                value = +value;  
                if (value > this.max) {  
                    value = this.max;  
                } else if (value < this.min) {  
                    value = this.min;  
                }  
                this.inputValue = value;  
            },  

            touchstart(e) {  
                const self = this  
                this.startX = e.clientX  
                this.show = true  

                function removeEventListeners() {  
                    document.removeEventListener('mousemove', self.touchmove)  
                    document.removeEventListener('mouseup', removeEventListeners)  
                    self.show = false  
                }  
                document.addEventListener('mousemove', this.touchmove)  
                document.addEventListener('mouseup', removeEventListeners)  
            },  
            touchmove(e) {  
                let dx = e.clientX - this.startX  
                this.lastDx = dx  
                this._calcValue(dx < 0 ? 'minus' : 'plus')  

            }  
        }  
    };  
</script>  
<style lang="scss" scoped>  
    /* #ifdef APP-NVUE */  
    /* #endif */  
    .uni-numbox {  
        $sizeBase: 8;  
        $N3NumberSize: 3*$sizeBase + px;  
        $N3NumberFontSize: 2*$sizeBase + px;  
        /* #ifndef APP-NVUE */  
        display: flex;  
        /* #endif */  
        flex-direction: row;  
        justify-content: space-around;  
        align-items: center;  
        border-radius: 3px;  
        border: 1px solid transparent;  
        box-sizing: border-box;  
        transition: 0.3s;  

        &:hover {  
            border-color: rgb(235, 235, 235);  
        }  

        &:focus-within {  
            border: 1px solid rgb(41, 141, 248);  
        }  

        &:hover .action,  
        &:focus-within .action {  
            visibility: visible;  
        }  

        .drag-label {  
            display: flex;  
            -webkit-box-align: center;  
            align-items: center;  
            -webkit-box-pack: center;  
            justify-content: center;  
            padding: 0px 3px 0px 5px;  
            width: max-content;  
            height: 100%;  
            color: rgb(141, 158, 167);  
        }  

        .action {  
            display: flex;  
            flex-direction: column;  
            width: 2em;  
            text-align: center;  
            transition: background 0.2s ease-out 0s, border, opacity;  
            visibility: hidden;  

            .action-item {  
                width: 100%;  
                height: 100%;  
                flex: 1;  
                line-height: 0;  
                cursor: pointer;  
                color: rgb(141, 158, 167);  
                transition: all 0.1s ease-out 0s;  

                .uni-numbox__text {  
                    transform: scale(0.7);  
                    display: inline-block;  
                }  

            }  

            .action-item:hover {  
                color: rgb(91, 107, 115);  
            }  
        }  

        .uni-numbox__text {  
            font-weight: bold;  
        }  

        .uni-numbox__minus {  
            /* #ifndef APP-NVUE */  
            display: flex;  
            /* #endif */  
            flex-direction: row;  
            align-items: center;  
            justify-content: center;  
            width: $N3NumberSize;  
            height: $N3NumberSize;  
            font-size: $N3NumberFontSize;  
            color: #333;  
            background-color: #f8f8f8;  
            border-width: 1px;  
            border-style: solid;  
            border-color: #e5e5e5;  
            border-top-left-radius: 3px;  
            border-bottom-left-radius: 3px;  
            border-right-width: 0;  

            &:hover {  
                background-color: #cccccc;  
            }  
        }  

        .uni-numbox__plus {  
            /* #ifndef APP-NVUE */  
            display: flex;  
            /* #endif */  
            flex-direction: row;  
            align-items: center;  
            justify-content: center;  
            width: $N3NumberSize;  
            height: $N3NumberSize;  
            border-width: 1px;  
            border-style: solid;  
            border-color: #e5e5e5;  
            border-top-right-radius: 3px;  
            border-bottom-right-radius: 3px;  
            background-color: #f8f8f8;  
            border-left-width: 0;  
            transition: 0.3s;  

            &:hover {  
                background-color: #cccccc;  
            }  
        }  

        .uni-numbox__value {  
            background-color: transparent;  
            width: $N3NumberSize;  
            height: $N3NumberSize;  
            text-align: center;  
            font-size: 1.6* $sizeBase+px;  
            border-width: 1px;  
            border-style: solid;  
            border-color: #e5e5e5;  
            border-left-width: 0;  
            border-right-width: 0;  
            box-sizing: border-box;  
            flex-grow: 1;  
        }  

        .uni-numbox__value-drag {  
            background-color: transparent;  
            width: $N3NumberSize;  
            height: $N3NumberSize;  
            text-align: center;  
            font-size: 1.6* $sizeBase+px;  
            border: none;  
            box-sizing: border-box;  
            flex-grow: 1;  
        }  

        .uni-numbox--disabled {  
            color: #c0c0c0;  
        }  

    }  

    .drag-range {  
        cursor: e-resize;  
        user-select: none;  
    }  

    .drag-range--mask{  
        cursor: e-resize;  
        user-select: none;  
        position: fixed;  
        left: 0;  
        top: 0;  
        right: 0;  
        bottom: 0;  
        background-color: transparent;  
        z-index: 9999;  
    }  
</style>  

使用

<number-box :min="0" value="0" size="small" mode="drag" label="W"> </number-box>

操作步骤:

pc 环境:正常引入组件即可
如需查看正常效果, 将number-box.vue 组件中 v-model="inputValue"去掉即可

预期结果:

如附件2中效果

实际结果:

待答复

bug描述:

mousemove事件 v-model绑定更新input卡顿不流畅

<input type="number" v-model="inputValue" :placeholder="`${inputValue}`"  />

效果如附件1

更新placeholder 则没有问题

<input  type="number"  :placeholder="`${inputValue}`"  />

效果如附件2

2020-12-09 10:39 负责人:无 分享
已邀请:

该问题目前已经被锁定, 无法添加新回复