触发重排,但元素值未更新

trigger reflow but element value not updated

提问人:Ageis 提问时间:9/17/2023 最后编辑:Ageis 更新时间:9/17/2023 访问量:31

问:

function countString(str, letter) {
    let count = 0;

    // looping through the items
    for (let i = 0; i < str.length; i++) {

        // check if the character is at that position
        if (str.charAt(i) == letter) {
            count += 1;
        }
    }
    return count;
}
function reflow(elt){
    console.log(elt.offsetHeight);
}
(() => {
 var clickedOnNumber = false;
 var qtyStars =0;
    var Connection = (url, handlers) => {
        offline()
        var ws
        var autoRetry = Timer(() => {
            console.log('connection timeout')
            ws.close()
            start()
        }, 5000)
        var keepAlive = Timer(() => {
            console.log('connection lost')
            offline()
            start()
        }, 5000)
        function isConnected() {
            return ws && ws.readyState === WebSocket.OPEN
        }
        function online() {
            handlers.onOnline && handlers.onOnline()
        }
        function offline() {
            handlers.onOffline && handlers.onOffline()
        }
        function message(data) {
            handlers.onMessage && handlers.onMessage(data)
        }
        function start() {
            if (isConnected()) {
                console.log('already connected')
            } else {
                console.log('establishing connection')
                ws = new WebSocket(url)
                autoRetry.start()
                ws.onopen = () => {
                    console.log('connection established')
                    autoRetry.stop()
                    keepAlive.start()
                    online()
                    send('?') // request current status
                }
                ws.onerror = err => {
                    console.log('connection error', err)
                    autoRetry.restart()
                }
                ws.onclose = () => {
                    console.log('connection closed')
                    offline()
                }
                ws.onmessage = evt => {
                    keepAlive.restart()
                    message(evt.data)
                }
            }
        }
        function stop() {
            if (isConnected()) {
                console.log('closing connection')
                keepAlive.stop()
                ws.close()
                offline()
            } else {
                console.log('already disconnected')
            }
        }
        function send(msg) {
            ws.send(msg)
        }
        return {
            start: start,
            stop: stop,
            send: send
        }
    }

    const Timer = (callback, timeout) => {
        let timer
        const start = () => {
            if (!timer) {
                timer = setTimeout(callback, timeout)
            }
        }
        const stop = () => {
            if (timer) {
                clearTimeout(timer)
                timer = null
            }
        }
        const restart = () => {
            stop()
            start()
        }
        return {
            start: start,
            stop: stop,
            restart: restart
        }
    }

    const Lcd = callback => {
    // https://dawes.wordpress.com/2010/01/05/hd44780-instruction-set/
        var display
        var pos
        var cmd = false
        var cursor = false
        var timer
        const show = () => {
            callback(display)
        }
        const write = char => {
            if (char >= ' ') {
                var row, col
                if (pos < 16) {
                    row = 0
                    col = pos
                } else {
                    row = 1
                    col = pos - 64
                }
                var previousChar = display[row].substr(col, 1)
                display[row] = display[row].substr(0, col) + char + display[row].substr(col + 1)
                return previousChar
            }
        }
        const advance = () => {
            pos++
        }
        const start = () => {
            var cursorChar = '_'
            if (cursor) {
                timer = setInterval(function () {
                    cursorChar = write(cursorChar)
                    show()
                }, 400)
            }
        }
        const stop = () => {
            if (timer) {
                clearInterval(timer)
            }
        }
        const refresh = () => {
            stop()
            show()
            start()
        }
        const offline = () => {
            display = ['Connecting...   ', '                ']
            show()
        }
        const reset = () => {
            display = ['                ', '                ']
            pos = 0
            refresh()
        }
        const ingest = data => {
            for (var i = 0; i < data.length; i++) {
                var char = data.charCodeAt(i)
                if (cmd) {
                    if (char >= 0x80) { // set position
                        pos = char - 0x80
                    } else {
                        console.log('unknown command: ', char.toString(16))
                    }
                    cmd = false
                } else {
                    switch (char) {
                    // case 0x03: // unknown
                    //   break;
                    case 0x04: // command
                        cmd = true; break
                    case 0x05: // hide cursor
                        cursor = false; break
                    case 0x06: // show cursor
                        cursor = true; break
                    case 0x07: // cursor right
                        pos++; break
                    case 0x0a: // newline
                        pos = 64; break
                    case 0x0c: // clear
                        reset(); break
                        // case 0x0d: // unknown
                        //   break;
                        // case 0x10: // unknown
                        //   break;
                        // case 0x16: // unknown
                        //   break;
                    default:
                        if (char >= 0x20 && char <= 0x7f) {
                          
                            if(data.charAt(i) =='*' && countString(document.getElementById('row1').innerText,'*') < qtyStars)
                            { 
                                 alert(document.getElementById('row1').innerText);
                                write(data.charAt(i))
                                advance()
                            (document.getElementById('row1'))
                            }
                            else{
                                
                            write(data.charAt(i))
                            advance()
                            }
                        } else {
                            console.log('unprintable character: ', char.toString(16))
                        }
                    }
                }
            }
            refresh()
        }
        reset()
        return {
            offline: offline,
            ingest: ingest,
            reset: reset
        }
    }

    const Led = (attr, values) => {
        const length = values.length
        return {
            ingest: data => {
                for (var i = 0; i < length; i++) {
                    var led = values.charAt(i)
                    $('[' + attr + '~="' + led + '"]').toggleClass('active', data.indexOf(led) !== -1)
                }
            },
            reset: () => {
                $('[' + attr + ']').removeClass('active')
            }
        }
    }

    const Auto = attr => {
        return {
            ingest: data => {
                const hour = parseInt(data)
                const time = hour === -1
                    ? 'OFF'
                    : `${hour < 10 ? '0' : ''}${hour}:00`
                $('[' + attr + ']').html(time)
            }
        }
    }

    const Days = () => {
        const weekDays = ['SUN', 'MON', 'TUE', 'WED', 'THU', 'FRI', 'SAT']
        return {
            ingest: data => {
                const days = data
                for (let i = 0; i < 7; i++) {
                    if (days.charAt(i) === '1') {
                        $('#' + weekDays[i]).removeClass('inactive')
                    } else {
                        $('#' + weekDays[i]).addClass('inactive')
                    }
                }
            }
        }
    }

    const Air = callback => {
        return {
            ingest: data => {
                const [temperature, relativeHumidity, tvoc, co2] = data.split(':')
                callback({
                    temperature: parseFloat(temperature).toFixed(1),
                    relativeHumidity: parseFloat(relativeHumidity).toFixed(1),
                    tvoc: parseInt(tvoc),
                    co2: parseInt(co2)
                })
            }
        }
    }

    $(() => {
        var lcd = Lcd(rows => {
            $('#row0', '.lcd').html(rows[0])
            $('#row1', '.lcd').html(rows[1])
            
        })

        var air = Air(({temperature, relativeHumidity, tvoc, co2}) => {
            $('#temperature').html(temperature)
            $('#relativeHumidity').html(relativeHumidity)
            $('#tvoc').html(tvoc)
            $('#co2').html(co2)
        })

        var keypadLed = Led('data-keypad', '12345678UTSP')
        var panelLed = Led('data-panel', 'SAIP')
        var autoArm = Auto('data-autoarm')
        var autoDisarm = Auto('data-autodisarm')
        var days = Days()

        var url = location.protocol === 'https:' ?
            'wss://' + location.hostname + ':8443' :
            'ws://' + location.hostname + ':8443'

        var connection = Connection(url, {
            onMessage: msg => {
                if (msg) {
                    $('.lcd').removeClass('lost')
                    var type = msg.substring(0, 3)
                    var data = msg.substring(4)
                    switch (type) {
                    case '+': // heartbeat
                        $('.lcd').addClass('heartbeat')
                        setTimeout(() => $('.lcd').removeClass('heartbeat'), 100)
                        break
                    case 'SIG': // panel signals
                        $('body').toggleClass('active', /[IP]/.test(data))
                        panelLed.ingest(data)
                        break
                    case 'LED': // keypad messages
                        keypadLed.ingest(data)
                        break
                    case 'LCD': // LCD messages
                        lcd.ingest(data)
                        break
                    case 'AIR': // sensors
                        air.ingest(data)
                        break
                    case 'ARM': // auto arm
                        autoArm.ingest(data)
                        break
                    case 'DIS': // auto disarm
                        autoDisarm.ingest(data)
                        break
                    case 'DAY': // auto arm/disarm days
                        days.ingest(data)
                        break
                    default:
                        break
                    }
                }
            },
            onOnline: () => {
                lcd.reset()
            },
            onOffline: () => {
                panelLed.reset()
                keypadLed.reset()
                lcd.offline()
            }
        })

        // bind click commands
        $('[data-click]').click(e => {
            if($.isNumeric($(e.target).data('click'))){
                qtyStars++;
            }
            connection.send($(e.target).data('click'))
        })

        // bind dbl-click commands
        $('[data-dblclick]').dblclick(e => {
            connection.send($(e.target).data('dblclick'))
        })

        // connect/disconnect based on page visibility
        // $(document).on({
        //     show: connection.start,
        //     hide: connection.stop
        // })

        $('.lcd').on('click', () => {
            $('.keyboard').toggle()
            $('.auto').toggle()
        })
        // $('.auto').on('click', () => $('.auto').hide())

        connection.start()
    })

})()

所以这是 WebSocket 实现的一部分。这个想法是入侵一个 Web 界面来控制一些控制警报面板的电子设备。

使用键盘时,可以键入元素 row1。当您单击键盘上的数字时,它会被发送到后端以控制防盗报警面板。然后 row1 将更新为星号。每位数字一个星号。

但是,警报面板会发送多条消息来更新自己的显示。不要问我为什么在我看来愚蠢。因此,我需要逻辑来忽略额外的消息,这样每次按键我都不会得到很多星号。

该逻辑不起作用,因为 dom 是异步的。第一次运行时,值为空,这是正确的。但是出现了第二个 Web 套接字消息,它仍然是一个空字符串,所以我得到了无限数量的星号,直到警报面板超时,然后将显示更新到当前日期和时间。$('#row1').val()

如您所见,我尝试进行重排,但 row1 的值显然没有更新。

我试图拱门的东西甚至可能吗?我正在使用最新版本的 Firefox,但如果可能的话,我希望它能够跨浏览器兼容。

javascript jquery dom

评论

0赞 Barmar 9/17/2023
你是如何触发这个的?您不应该使用循环,而应使用在用户键入 .row1
0赞 Ageis 9/17/2023
我正在使用 WebSocket 客户端的 onMessage 事件处理程序。每次单击键盘上的数字时,都会显示 qtyStars。但是我无法获取Val()命令来更新值
0赞 Barmar 9/17/2023
该函数除了记录消息外不执行任何操作,它与呈现显示有什么关系?每当 JS 返回到主事件循环时,显示都应自动呈现。reflow()
0赞 Barmar 9/17/2023
它应该在哪里更新输入值? 没有参数读取值,更改值。.val().val(newvalue)
0赞 Ageis 9/17/2023
我从这里的另一篇帖子中得到了回流函数。它说访问该属性会导致浏览器重新绘制页面。

答: 暂无答案