document.getElementById('aa').innerHTML = this.value 在 lit-element 中的等价物是什么?

What is the equivalent of document.getElementById('aa').innerHTML = this.value in lit-element?

我正在为价格实现一个双滑块 range.There 需要在用户滑动到 select 具体 range.For 时显示价值 range.For 我使用了有效的 innerHTML美好的。但是有一个错误说

"Uncaught TypeError: Cannot read property 'nodeType' of null
at NodePart._setText (lit-html.ts:657)
at NodePart.setValue (lit-html.ts:616)
at TemplateInstance.update (lit-html.ts:810)
at render (shady-render.ts:159)
at HTMLElement._applyRender (lit-element.ts:286)
at HTMLElement._propertiesChanged (lit-element.ts:218)
at HTMLElement._flushProperties (properties-changed.js:387)
at HTMLElement._flushProperties (lit-element.ts:232)
at properties-changed.js:334
at MutationObserver.microtaskFlush (async.js:41)".

我搜索了很多,得到的答案是,一个是如果函数在加载DOM之前调用,另一个是innerHTML is not used in lit-html。请帮助我摆脱那个错误。

    import {LitElement, html} from '@polymer/lit-element';
import {connect} from 'pwa-helpers/connect-mixin.js';
import {store} from '../../redux/store.js';
import {style} from './genie-flex-css.js';
import {repeat} from 'lit-html/lib/repeat';
export class GenieSlider extends connect(store)(LitElement) {
    static get is() {
        return 'genie-slider';
    }
    static get properties() {
        // TODO: declare the properties here.
        return {
            minimum: Number,
            maximum: Number
        };
    }
    constructor() {
        super();
        // TODO: Initialize the properties here
        this.minimum = 0;
        this.maximum = 10000;
    }
    requestRender() {
        this._invalidateProperties();
      }
      _invalidateProperties() {
        this.__isInvalid = true;
        super._invalidateProperties();
      }
    minPrice(e) {
        this.dispatchEvent(new CustomEvent('GG:minPriceChanged', {
            bubbles: false,
            detail: {
                event: e,
                value: e.currentTarget.value
            }
        }));
        e.stopPropagation();
        this.selectedOption = e.currentTarget.value;
        this.minimum = this.selectedOption; 
        this.requestRender();
    }
    maxPrice(e) {
        this.dispatchEvent(new CustomEvent('GG:maxPriceChanged', {
            bubbles: false,
            detail: {
                event: e,
                value: e.currentTarget.value
            }
        }));
        e.stopPropagation();
        this.selectedOption = e.currentTarget.value;
        this.maximum = this.selectedOption;
        this.requestRender(); 
    }

    _firstRendered() {

    }

    _render(properties) {

        return html `
    <style>
    ${style}
        [slider] {
            width: 270px;
            position: relative;
        }

        [slider] > div {
            position: absolute;
            left: 13px;
            right: 15px;
            height: 5px;
        }
        [slider] > div > [inverse-left],[slider] > div > [inverse-right] {
            position: absolute;
            height: 3px;
            border-radius: 10px;
            background-color: #CCC;
            margin: 0 7px;
        }

        [slider] > div > [inverse-left] {
            left: 0;
        }

        [slider] > div > [inverse-right] {
            right: 0;
        }


        [slider] > div > [range] {
            position: absolute;
            left: 0;
            height: 3px;
            border-radius: 14px;
            background-color: #d02128;
        }

        [slider] > div > [thumb] {
            position: absolute;
            top: -8px;
            z-index: 2;
            height: 20px;
            width: 20px;
            text-align: left;
            margin-left: -11px;
            cursor: pointer;
            box-shadow: 0 3px 8px rgba(0, 0, 0, 0.4);
            background-color: #FFF;
            border-radius: 50%;
            outline: none;
        }

        [slider] > input[type=range] {
            position: absolute;
            pointer-events: none;
            -webkit-appearance: none;
            z-index: 3;
            height: 14px;
            top: -2px;
            width: 100%;
            opacity: 0;
        }

        div[slider] > input[type=range]:focus::-webkit-slider-runnable-track {
            background: transparent;
            border: transparent;
        }

        div[slider] > input[type=range]:focus {
            outline: none;
        }

        div[slider] > input[type=range]::-ms-thumb {
            pointer-events: all;
            width: 28px;
            height: 28px;
            border-radius: 0px;
            border: 0 none;
            background: red;
        }

        div[slider] > input[type=range]::-moz-range-thumb {
            pointer-events: all;
            width: 28px;
            height: 28px;
            border-radius: 0px;
            border: 0 none;
            background: red;
        }

        div[slider] > input[type=range]::-webkit-slider-thumb {
            pointer-events: all;
            width: 28px;
            height: 28px;
            border-radius: 0px;
            border: 0 none;
            background: red;
            -webkit-appearance: none;
        }

        div[slider] > input[type=range]::-ms-fill-lower {
            background: transparent;
            border: 0 none;
        }

        div[slider] > input[type=range]::-ms-fill-upper {
            background: transparent;
            border: 0 none;
        }

        div[slider] > input[type=range]::-ms-tooltip {
            display: none;
        }

        [slider] > div > [sign] {
            opacity: 0;
            position: absolute;
            margin-left: -11px;
            top: -39px;
            z-index:3;
            background-color: #d02128;
            color: #fff;
            width: 28px;
            height: 28px;
            border-radius: 28px;
            -webkit-border-radius: 28px;
            align-items: center;
            -webkit-justify-content: center;
            justify-content: center;
            text-align: center;
        }

        [slider] > div > [sign]:after {
            position: absolute;
            content: '';
            left: 0;
            border-radius: 16px;
            top: 19px;
            border-left: 14px solid transparent;
            border-right: 14px solid transparent;
            border-top-width: 16px;
            border-top-style: solid;
            border-top-color: #d02128;
        }

        [slider] > div > [sign] > span {
            font-size: 10px;
            font-weight: 700;
            line-height: 28px;
        }

        [slider]:hover > div > [sign] {
            opacity: 1;
        }
    }
    </style>    
        <div slider id="slider-distance">
            <div>
                <div inverse-left style="width:70%;"></div>
                <div inverse-right style="width:70%;"></div>
                <div range style="left:${this.minimum? (this.minimum/100)+'%': 0+'%' };right:${this.maximum? 100 - (this.maximum/100)+'%': 0+'%' }"></div>
                <span thumb style="left:${this.minimum? (this.minimum/100)+'%': 0+'%' }"></span>
                <span thumb style="left:${this.maximum? (this.maximum/100)+'%': 100+'%' }"></span>
                <div sign style="left:${this.minimum? (this.minimum/100)+'%': 0+'%' }">
                    <span id="minResult">${this.minimum}</span>
                </div>
                <div sign style="left:${this.maximum? (this.maximum/100)+'%': 100+'%' }">
                    <span id="maxResult">${this.maximum}</span>
                </div>
            </div>
            <input type="range" value="0" max="${this.maximum}" min="0" step="100" oninput=" 
                this.value=Math.min(this.value,this.parentNode.childNodes[5].value-500);
                let value = (this.value/parseInt(this.max))*100
                var children = this.parentNode.childNodes[1].childNodes;
                children[1].style.width=value+'%';
                children[5].style.left=value+'%';
                children[7].style.left=value+'%';children[11].style.left=value+'%';
                children[11].childNodes[1].innerHTML=this.value;" onchange="${e => {this.minPrice(e)}}"/>

            <input type="range" value="10000" max="10000" min="${this.minimum}" step="100" oninput="  
                this.value=Math.max(this.value,this.parentNode.childNodes[3].value-(-500));
                let value = (this.value/parseInt(this.max))*100
                var children = this.parentNode.childNodes[1].childNodes;
                children[3].style.width=(100-value)+'%';
                children[5].style.right=(100-value)+'%';
                children[9].style.left=value+'%';children[13].style.left=value+'%';
                children[13].childNodes[1].innerHTML=this.value;" onchange="${e => {this.maxPrice(e)}}"/>
        </div>
    `;
    }
    _stateChanged(state) {
        // TODO Set the state dependent properties here
    }
}
customElements.define(GenieSlider.is, GenieSlider);

您应该使用 LitElement 的模板绑定语法来处理 input 事件 (@input=${...}) 并在模板中呈现所选值。简而言之:

render() {
  return html`
    <input type="range"
      value=${this.selectedValue}
      @input=${this._handleRangeChange}>
    Selected value: ${this.selectedValue}
  `;
}

_handleRangeChange(event) {
  this.selectedValue = parseInt(event.target.value);
}

您可以在下面的完整代码段中看到它的工作原理:

const { LitElement, html } = litElement;

class MyTestElement extends LitElement {
  static get properties() {
    return {
      selectedValue: { type: Number },
    };
  }

  constructor() {
    super();
    this.selectedValue = 0;
    this._handleRangeChange = this._handleRangeChange.bind(this);
  }

  render() {
    return html`
      <input type="range"
        min=0
        max=10000
        step=100
        value=${this.selectedValue}
        @input=${this._handleRangeChange}>
      Selected value: ${this.selectedValue}
    `;
  }

  _handleRangeChange(event) {
    this.selectedValue = parseInt(event.target.value);
  }
}

customElements.define('my-test', MyTestElement);
<script src="https://bundle.run/lit-element@2.2.1"></script>

<my-test></my-test>