लाइट-एलिमेंट की मदद से ब्रिक व्यूअर बनाएं

1. परिचय

वेब कॉम्पोनेंट

वेब कॉम्पोनेंट, उन वेब स्टैंडर्ड का कलेक्शन हैं जिनकी मदद से डेवलपर, कस्टम एलिमेंट वाले एचटीएमएल का इस्तेमाल कर सकते हैं. इस कोडलैब में, आपको <brick-viewer> एलिमेंट तय करना होगा, जिससे ब्रिक के मॉडल दिखाए जा सकेंगे!

लाइट-एलिमेंट

अपने कस्टम एलिमेंट <brick-viewer> को तय करने में हमारी मदद करने के लिए, हम lit-element इस्तेमाल करेंगे. lit-element एक लाइटवेट बेस क्लास है, जो स्टैंडर्ड तौर पर वेब कॉम्पोनेंट में कुछ सिंटैक्टिक शुगर जोड़ता है. इससे हमारे लिए, कस्टम एलिमेंट का इस्तेमाल करना आसान हो जाएगा.

शुरू करें

हम ऑनलाइन स्टैकब्लिट्ज़ के एनवायरमेंट में कोडिंग करेंगे, इसलिए इस लिंक को नई विंडो में खोलें:

stackblitz.com/edit/brick-viewer

आइए, शुरू करें!

2. कस्टम एलिमेंट तय करें

क्लास की परिभाषा

कस्टम एलिमेंट तय करने के लिए, LitElement को बड़ा करने वाली क्लास बनाएं और उसे @customElement से सजाएं. @customElement का आर्ग्युमेंट, कस्टम एलिमेंट का नाम होगा.

ब्रिक-व्यूअर.t में, रखें:

@customElement('brick-viewer')
export class BrickViewer extends LitElement {
}

अब <brick-viewer></brick-viewer> एलिमेंट, एचटीएमएल में इस्तेमाल किए जाने के लिए तैयार है. हालांकि, अगर आपने इसे आज़माया है, तो कुछ भी रेंडर नहीं होगा. चलिए, इसे ठीक करते हैं।

रेंडर करने का तरीका

कॉम्पोनेंट के व्यू को लागू करने के लिए, रेंडर नाम का तरीका तय करें. इस तरीके से, html फ़ंक्शन के साथ टैग किया गया टेंप्लेट मिलना चाहिए. टैग किए गए टेंप्लेट में अपनी पसंद का कोई भी एचटीएमएल डालें. यह <brick-viewer> का इस्तेमाल करने पर रेंडर होगा.

render तरीका जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`<div>Brick viewer</div>`;
  }
}

3. LDraw फ़ाइल तय करना

प्रॉपर्टी तय करना

अगर <brick-viewer> का उपयोगकर्ता यह तय कर सके कि एट्रिब्यूट का इस्तेमाल करके ब्रिक का कौनसा मॉडल दिखाना है, तो बहुत अच्छा होगा, जैसे कि:

<brick-viewer src="path/to/model.ldraw"></brick-viewer>

हम एक एचटीएमएल एलिमेंट बना रहे हैं. इसलिए, हम डिक्लेरेटिव एपीआई का फ़ायदा ले सकते हैं और <img> या <video> टैग की तरह ही सोर्स एट्रिब्यूट तय कर सकते हैं. लिट-एलिमेंट की मदद से, यह @property की मदद से क्लास प्रॉपर्टी को सजाने जितना आसान है. type विकल्प से आप यह तय कर सकते हैं कि lit-element, एचटीएमएल एट्रिब्यूट के तौर पर इस्तेमाल करने के लिए, प्रॉपर्टी को कैसे पार्स करता है.

src प्रॉपर्टी और एट्रिब्यूट तय करें:

export class BrickViewer extends LitElement {
  @property({type: String})
  src: string|null = null;
}

<brick-viewer> में अब src एट्रिब्यूट जोड़ दिया गया है, जिसे एचटीएमएल में सेट किया जा सकता है! lit-element की वजह से, हमारी BrickViewer क्लास में इसकी वैल्यू को पहले ही पढ़ा जा सकता है.

वैल्यू दिखाई जा रही हैं

हम src एट्रिब्यूट की वैल्यू को, रेंडर करने के तरीके के टेंप्लेट में इस्तेमाल करके दिखा सकते हैं. ${value} सिंटैक्स का इस्तेमाल करके, वैल्यू को टेंप्लेट की लिटरल वैल्यू में बदलें.

export class BrickViewer extends LitElement {
  render() {
    return html`<div>Brick model: ${this.src}</div>`;
  }
}

अब हमें विंडो के <brick-viewer> एलिमेंट में, src एट्रिब्यूट की वैल्यू दिखती है. इसे आज़माएं: अपने ब्राउज़र के डेवलपर टूल खोलें और src एट्रिब्यूट को मैन्युअल तरीके से बदलें. आगे बढ़ें, इसे आज़माएं...

...क्या आपने ध्यान दिया कि एलिमेंट में मौजूद टेक्स्ट अपने-आप अपडेट हो जाता है? lit-element, @property से सजी क्लास प्रॉपर्टी को देखता है और आपके लिए व्यू को फिर से रेंडर करता है! लिट-एलिमेंट भारी-भरकम वज़न को उठाने में मदद करता है, इसलिए आपको नहीं करना पड़ता.

4. तीन.js के साथ सीन सेट करें

लाइट, कैमरा, रेंडर!

हमारे 3D ब्रिक मॉडल को रेंडर करने के लिए, कस्टम एलिमेंट तीन.js का इस्तेमाल करेगा. कुछ ऐसी चीज़ें हैं जिन्हें हम <brick-viewer> एलिमेंट के हर इंस्टेंस के लिए, सिर्फ़ एक बार करना चाहते हैं, जैसे कि Three.js सीन, कैमरा, और लाइटिंग सेट अप करना. हम इन्हें कंस्ट्रक्टर की BrickViewer क्लास में जोड़ेंगे. हम कुछ ऑब्जेक्ट को क्लास प्रॉपर्टी के तौर पर रखेंगे, ताकि बाद में उनका इस्तेमाल किया जा सके: कैमरा, सीन, कंट्रोल, और रेंडरर.

तीन.js सीन सेटअप में जोड़ें:

export class BrickViewer extends LitElement {

  private _camera: THREE.PerspectiveCamera;
  private _scene: THREE.Scene;
  private _controls: OrbitControls;
  private _renderer: THREE.WebGLRenderer;

  constructor() {
    super();

    this._camera = new THREE.PerspectiveCamera(45, this.clientWidth/this.clientHeight, 1, 10000);
    this._camera.position.set(150, 200, 250);

    this._scene = new THREE.Scene();
    this._scene.background = new THREE.Color(0xdeebed);

    const ambientLight = new THREE.AmbientLight(0xdeebed, 0.4);
    this._scene.add( ambientLight );

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(-1000, 1200, 1500);
    this._scene.add(directionalLight);

    this._renderer = new THREE.WebGLRenderer({antialias: true});
    this._renderer.setPixelRatio(window.devicePixelRatio);
    this._renderer.setSize(this.offsetWidth, this.offsetHeight);

    this._controls = new OrbitControls(this._camera, this._renderer.domElement);
    this._controls.addEventListener("change", () =>
      requestAnimationFrame(this._animate)
    );

    this._animate();

    const resizeObserver = new ResizeObserver(this._onResize);
    resizeObserver.observe(this);
  }

  private _onResize = (entries: ResizeObserverEntry[]) => {
    const { width, height } = entries[0].contentRect;
    this._renderer.setSize(width, height);
    this._camera.aspect = width / height;
    this._camera.updateProjectionMatrix();
    requestAnimationFrame(this._animate);
  };

  private _animate = () => {
    this._renderer.render(this._scene, this._camera);
  };
}

WebGLRenderer ऑब्जेक्ट, एक DOM एलिमेंट उपलब्ध कराता है, जो रेंडर किया गया Three.js सीन दिखाता है. इसे domElement प्रॉपर्टी से ऐक्सेस किया जाता है. हम ${value} सिंटैक्स का इस्तेमाल करके, इस वैल्यू को रेंडर टेंप्लेट के लिटरल में शामिल कर सकते हैं.

टेंप्लेट में मौजूद src मैसेज को हटाएं और रेंडरर का डीओएम एलिमेंट शामिल करें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      ${this._renderer.domElement}
    `;
  }
}

रेंडरर के डॉम एलिमेंट को पूरी तरह से दिखाने के लिए, हमें <brick-viewer> एलिमेंट को भी display: block पर सेट करना होगा. हम styles नाम की स्टैटिक प्रॉपर्टी में स्टाइल दे सकते हैं, जिसे css टेंप्लेट लिटरल पर सेट किया गया है.

यह स्टाइलिंग क्लास में जोड़ें:

export class BrickViewer extends LitElement {
  static styles = css`
    /* The :host selector styles the brick-viewer itself! */
    :host {
      display: block;
    }
  `;
}

अब <brick-viewer> में, रेंडर किया गया तीन.js सीन दिखाया जा रहा है:

ब्रिक व्यूअर एलिमेंट में रेंडर किया गया, लेकिन खाली सीन दिख रहा है.

लेकिन... यह खाली है. चलिए, इसे मॉडल उपलब्ध कराते हैं.

ब्रिक लोडर

हम उस src प्रॉपर्टी को पास करेंगे जो हमने पहले LDrawLoader में दिया था, जिसे तीन.js की मदद से शिप किया गया है.

Lड्रॉ फ़ाइलों की मदद से, ब्रिक मॉडल को बिल्डिंग के अलग-अलग चरणों में बांटा जा सकता है. LDrawLoader API की मदद से, कदमों की कुल संख्या और ब्रिक दिखाने की हर सुविधा ऐक्सेस की जा सकती है.

इन प्रॉपर्टी, _loadModel के नए तरीके, और कंस्ट्रक्टर की नई लाइन को कॉपी करें:

@customElement('brick-viewer')
export class BrickViewer extends LitElement {
  private _loader = new LDrawLoader();
  private _model: any;
  private _numConstructionSteps?: number;
  step?: number;

  constructor() {
    // ...
    // Add this line right before this._animate();
    (this._loader as any).separateObjects = true;
    this._animate();
  }

  private _loadModel() {
    if (this.src === null) {
      return;
    }
    this._loader
        .setPath('')
        // Using our src property!
        .load(this.src, (newModel) => {

          if (this._model !== undefined) {
            this._scene.remove(this._model);
            this._model = undefined;
          }

          this._model = newModel;

          // Convert from LDraw coordinates: rotate 180 degrees around OX
          this._model.rotation.x = Math.PI;
          this._scene.add(this._model);

          this._numConstructionSteps = this._model.userData.numConstructionSteps;
          this.step = this._numConstructionSteps!;

          const bbox = new THREE.Box3().setFromObject(this._model);
          this._controls.target.copy(bbox.getCenter(new THREE.Vector3()));
          this._controls.update();
          this._controls.saveState();
        });
  }
}

_loadModel को कब कॉल करना है? हर बार src एट्रिब्यूट में बदलाव होने पर, इसे शुरू करना ज़रूरी है. src प्रॉपर्टी को @property से डेकोर करने का मतलब है कि हमने प्रॉपर्टी को लिट-एलिमेंट अपडेट की लाइफ़साइकल में शामिल किया है. जब भी इन सजी हुई प्रॉपर्टी में से कोई एक वैल्यू में बदलाव होता है, तो उन तरीकों की सीरीज़ कॉल की जाती है जो प्रॉपर्टी की नई और पुरानी वैल्यू को ऐक्सेस कर सकती हैं. हम जिस लाइफ़साइकल तरीके में दिलचस्पी रखते हैं उसे update कहा जाता है. update तरीके में PropertyValues आर्ग्युमेंट इस्तेमाल किया जाता है. इसमें, हाल ही में बदली गई सभी प्रॉपर्टी की जानकारी होती है. _loadModel को कॉल करने के लिए यह बिलकुल सही जगह है.

update तरीका जोड़ें:

export class BrickViewer extends LitElement {
  update(changedProperties: PropertyValues) {
    if (changedProperties.has('src')) {
      this._loadModel();
    }
    super.update(changedProperties);
  }
}

हमारा <brick-viewer> एलिमेंट अब ब्रिक फ़ाइल दिखा सकता है, जिसे src एट्रिब्यूट के साथ तय किया गया है.

ब्रिक व्यूअर एलिमेंट की इमेज, जिसमें कार का मॉडल दिखाया गया है.

5. आंशिक मॉडल प्रदर्शित करना

अब कंस्ट्रक्शन के मौजूदा चरण को कॉन्फ़िगर किया जा सकता है. हमें <brick-viewer step="5"></brick-viewer> के बारे में बताना है. हमें पता चलेगा कि पांचवें चरण पर ब्रिक मॉडल कैसा दिखता है. ऐसा करने के लिए, आइए step प्रॉपर्टी को @property से सजाकर निगरानी की गई प्रॉपर्टी बनाएं.

step प्रॉपर्टी को सजाएं:

export class BrickViewer extends LitElement {
  @property({type: Number})
  step?: number;
}

अब हम एक हेल्पर तरीका जोड़ेंगे, जिससे मौजूदा बिल्ड चरण तक के चरण ही दिखाई देंगे. हम अपडेट के तरीके में हेल्पर को कॉल करेंगे, ताकि हर बार step प्रॉपर्टी बदलने पर यह प्रोसेस चलती रहे.

update वाला तरीका अपडेट करें और _updateBricksVisibility का नया तरीका जोड़ें:

export class BrickViewer extends LitElement {
  update(changedProperties: PropertyValues) {
    if (changedProperties.has('src')) {
      this._loadModel();
    }
    if (changedProperties.has('step')) {
      this._updateBricksVisibility();
    }
    super.update(changedProperties);
  }

  private _updateBricksVisibility() {
    this._model && this._model.traverse((c: any) => {
      if (c.isGroup && this.step) {
        c.visible = c.userData.constructionStep <= this.step;
      }
    });
    requestAnimationFrame(this._animate);
  }
}

ठीक है, अब अपने ब्राउज़र के devtools को खोलें और <brick-viewer> एलिमेंट की जांच करें. उसमें step एट्रिब्यूट जोड़ें, जैसे:

ब्रिक व्यूअर एलिमेंट का एचटीएमएल कोड, जिसमें चरण एट्रिब्यूट की वैल्यू 10 पर सेट की गई है.

देखें कि रेंडर किए गए मॉडल का क्या होता है! हम step एट्रिब्यूट का इस्तेमाल करके, यह तय कर सकते हैं कि मॉडल का कितना हिस्सा दिखाया जाए. यहां बताया गया है कि जब step एट्रिब्यूट को "10" पर सेट किया जाता है, तो यह कैसा दिखना चाहिए:

ईंटों का एक मॉडल, जिसमें सिर्फ़ दस सीढ़ियां बनी हैं.

6. ब्रिक सेट नेविगेशन

एमडब्ल्यूसी-आइकॉन-बटन

हमारे <brick-viewer> के असली उपयोगकर्ता के पास, यूज़र इंटरफ़ेस (यूआई) के ज़रिए बिल्ड के चरणों पर नेविगेट करने की सुविधा होनी चाहिए. अगले चरण, पिछले चरण, और पहले चरण पर जाने के लिए बटन जोड़ें. हम इसे आसान बनाने के लिए मटीरियल डिज़ाइन के बटन वेब कॉम्पोनेंट का इस्तेमाल करेंगे. @material/mwc-icon-button को पहले ही इंपोर्ट किया जा चुका है. इसलिए, हम <mwc-icon-button></mwc-icon-button> को शामिल करने के लिए तैयार हैं. हम आइकॉन एट्रिब्यूट के साथ इस्तेमाल करने के लिए, पसंदीदा आइकॉन तय कर सकते हैं, जैसे कि: <mwc-icon-button icon="thumb_up"></mwc-icon-button>. सभी संभावित आइकॉन यहां मिल सकते हैं: material.io/resources/icons.

अब रेंडर करने के तरीके में कुछ आइकॉन बटन जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      ${this._renderer.domElement}
      <div id="controls">
        <mwc-icon-button icon="replay"></mwc-icon-button>
        <mwc-icon-button icon="navigate_before"></mwc-icon-button>
        <mwc-icon-button icon="navigate_next"></mwc-icon-button>
      </div>
    `;
  }
}

वेब कॉम्पोनेंट की वजह से हमारे पेज पर मटीरियल डिज़ाइन का इस्तेमाल करना बेहद आसान है!

इवेंट बाइंडिंग

इन बटन से हमें कुछ काम करना चाहिए. "जवाब" बटन को सेट अप करने के चरण को रीसेट करके 1 पर सेट करना चाहिए. "nav_before" का नाम बटन से निर्माण चरण कम हो जाना चाहिए और "nav_next" बटन को बढ़ाना चाहिए. lit-element, इवेंट बाइंडिंग के साथ इस सुविधा को जोड़ना आसान बनाता है. अपने एचटीएमएल टेंप्लेट की लिटरल वैल्यू में, सिंटैक्स @eventname=${eventHandler} का इस्तेमाल एलिमेंट एट्रिब्यूट के तौर पर करें. eventHandler अब तब चलेगा, जब उस एलिमेंट पर eventname इवेंट का पता चलेगा! उदाहरण के लिए, आइए हमारे तीन आइकॉन बटन में क्लिक इवेंट हैंडलर जोड़ देते हैं:

export class BrickViewer extends LitElement {
  private _restart() {
    this.step! = 1;
  }

  private _stepBack() {
    this.step! -= 1;
  }

  private _stepForward() {
    this.step! += 1;
  }

  render() {
    return html`
      ${this._renderer.domElement}
      <div id="controls">
        <mwc-icon-button @click=${this._restart} icon="replay"></mwc-icon-button>
        <mwc-icon-button @click=${this._stepBack} icon="navigate_before"></mwc-icon-button>
        <mwc-icon-button @click=${this._stepForward} icon="navigate_next"></mwc-icon-button>
      </div>
    `;
  }
}

अब बटनों पर क्लिक करके देखें. बहुत बढ़िया!

स्टाइल

बटन काम कर रहे हैं, लेकिन वे अच्छे नहीं लग रहे हैं. सभी लोगों को सबसे नीचे huddle किया गया है. आइए, उन्हें सीन पर ओवरले करने के लिए स्टाइल दें.

इन बटनों पर स्टाइल लागू करने के लिए, हम static styles प्रॉपर्टी पर वापस जाते हैं. इन स्टाइल के दायरे में आते हैं. इसका मतलब है कि ये सिर्फ़ इस वेब कॉम्पोनेंट के एलिमेंट पर लागू होंगे. यह वेब कॉम्पोनेंट को लिखने का एक बेहतरीन तरीका है: सिलेक्टर को इस्तेमाल करना आसान हो सकता है. इसके अलावा, सीएसएस को पढ़ना और लिखना ज़्यादा आसान हो जाएगा. अलविदा, BEM!

स्टाइल अपडेट करें, ताकि वे इस तरह दिखें:

export class BrickViewer extends LitElement {
  static styles = css`
    :host {
      display: block;
      position: relative;
    }
    #controls {
      position: absolute;
      bottom: 0;
      width: 100%;
      display: flex;
    }
  `;
}

ब्रिक व्यूअर एलिमेंट जिसमें रीस्टार्ट, पीछे, और आगे जाने के बटन होते हैं.

कैमरा रीसेट करने का बटन

हमारे <brick-viewer> के असली उपयोगकर्ता, माउस कंट्रोल का इस्तेमाल करके सीन को घुमा सकते हैं. हम इसके लिए बटन जोड़ रहे हैं. चलिए, कैमरे को उसकी डिफ़ॉल्ट स्थिति पर रीसेट करने के लिए एक बटन जोड़ते हैं. क्लिक इवेंट बाइंडिंग वाले दूसरे <mwc-icon-button> का काम पूरा हो जाएगा.

export class BrickViewer extends LitElement {
  private _resetCamera() {
    this._controls.reset();
  }

  render() {
    return html`
      <div id="controls">
        <!-- ... -->
        <!-- Add this button: -->
        <mwc-icon-button @click=${this._resetCamera} icon="center_focus_strong"></mwc-icon-button>
      </div>
    `;
  }
}

ज़्यादा तेज़ नेविगेशन

ईंटों के कुछ सेट में कई सीढ़ियां होती हैं. ऐसा हो सकता है कि उपयोगकर्ता सीधे किसी चरण पर जाना चाहे. चरण संख्याओं के साथ स्लाइडर जोड़ने से, तेज़ी से नेविगेट करने में मदद मिल सकती है. हम इसके लिए <mwc-slider> एलिमेंट का इस्तेमाल करेंगे.

एमडब्ल्यूसी-स्लाइडर

स्लाइडर एलिमेंट को ज़रूरी डेटा के कुछ हिस्सों की ज़रूरत होती है. जैसे, स्लाइडर की कम से कम और ज़्यादा से ज़्यादा वैल्यू. स्लाइडर की कम से कम वैल्यू हमेशा "1" हो सकती है. अगर मॉडल लोड हो गया है, तो स्लाइडर की ज़्यादा से ज़्यादा वैल्यू this._numConstructionSteps होनी चाहिए. हम <mwc-slider> को इसके एट्रिब्यूट की मदद से ये वैल्यू बता सकते हैं. अगर _numConstructionSteps प्रॉपर्टी के बारे में नहीं बताया गया है, तो हम max एट्रिब्यूट को सेट करने से बचने के लिए, ifDefined lit-html directive का इस्तेमाल भी कर सकते हैं.

"पीछे जाएं" के बीच में <mwc-slider> जोड़ें और "आगे बढ़ें" बटन:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ... backwards button -->
        <!-- Add this slider: -->
        <mwc-slider
            step="1"
            pin
            markers
            min="1"
            max=${ifDefined(this._numConstructionSteps)}
        ></mwc-slider>
        <!-- ... forwards button -->
      </div>
    `;
  }
}

डेटा "ऊपर"

जब कोई उपयोगकर्ता स्लाइडर को मूव करता है, तो कंस्ट्रक्शन का मौजूदा चरण बदल जाना चाहिए. साथ ही, मॉडल को उसके हिसाब से ही अपडेट किया जाना चाहिए. जब भी स्लाइडर को खींचा जाएगा, स्लाइडर एलिमेंट से एक इनपुट इवेंट बनेगा. इस इवेंट को देखने और कंस्ट्रक्शन का चरण बदलने के लिए, स्लाइडर पर ही इवेंट बाइंडिंग जोड़ें.

इवेंट बाइंडिंग जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ...  -->
        <!-- Add the @input event binding: -->
        <mwc-slider
            ...
            @input=${(e: CustomEvent) => this.step = e.detail.value}
        ></mwc-slider>
        <!-- ... -->
      </div>
    `;
  }
}

वाह! स्लाइडर का इस्तेमाल करके, हम यह तय कर सकते हैं कि कौनसा चरण दिखाया जाए.

डेटा "कम"

एक और चीज़ है. जब "वापस जाएं" और "आगे बढ़ें" बटन का इस्तेमाल चरण बदलने के लिए किया जाता है, तो स्लाइडर हैंडल को अपडेट करना होगा. <mwc-slider> की वैल्यू एट्रिब्यूट को this.step से बाइंड करें.

value बाइंडिंग जोड़ें:

export class BrickViewer extends LitElement {
  render() {
    return html`
      <div id="controls">
        <!-- ...  -->
        <!-- Add the value property binding: -->
        <mwc-slider
            ...
            value=${ifDefined(this.step)}
        ></mwc-slider>
        <!-- ... -->
      </div>
    `;
  }
}

स्लाइडर का काम करीब-करीब पूरा हो गया है. इसे अन्य कंट्रोल के साथ अच्छे से चलाने के लिए कोई फ़्लेक्सिबल स्टाइल जोड़ें:

export class BrickViewer extends LitElement {
  static styles = css`
    /* ... */
    mwc-slider {
      flex-grow: 1;
    }
  `;
}

साथ ही, हमें स्लाइडर एलिमेंट पर ही layout को कॉल करना होगा. हम ऐसा firstUpdated लाइफ़साइकल वाले तरीके में करेंगे, जिसे डीओएम के पहली बार सेट होने के बाद कॉल किया जाता है. query डेकोरेटर से, हमें टेंप्लेट में स्लाइडर एलिमेंट का रेफ़रंस पाने में मदद मिल सकती है.

export class BrickViewer extends LitElement {
  @query('mwc-slider')
  slider!: Slider|null;

  async firstUpdated() {
    if (this.slider) {
      await this.slider.updateComplete
      this.slider.layout();
    }
  }
}

यहां स्लाइडर में जोड़ी जाने वाली सभी चीज़ों की जानकारी दी गई है (स्लाइडर पर अतिरिक्त pin और markers एट्रिब्यूट जोड़कर इसे बढ़िया तरीके से दिखाया गया है):

export class BrickViewer extends LitElement {
 @query('mwc-slider')
 slider!: Slider|null;

 static styles = css`
   /* ... */
   mwc-slider {
     flex-grow: 1;
   }
 `;

 async firstUpdated() {
   if (this.slider) {
     await this.slider.updateComplete
     this.slider.layout();
   }
 }

 render() {
   return html`
     ${this._renderer.domElement}
     <div id="controls">
       <mwc-icon-button @click=${this._restart} icon="replay"></mwc-icon-button>
       <mwc-icon-button @click=${this._stepBack} icon="navigate_before"></mwc-icon-button>
       <mwc-slider
         step="1"
         pin
         markers
         min="1"
         max=${ifDefined(this._numConstructionSteps)}
         ?disabled=${this._numConstructionSteps === undefined}
         value=${ifDefined(this.step)}
         @input=${(e: CustomEvent) => this.constructionStep = e.detail.value}
       ></mwc-slider>
       <mwc-icon-button @click=${this._stepForward} icon="navigate_next"></mwc-icon-button>
       <mwc-icon-button @click=${this._resetCamera} icon="center_focus_strong"></mwc-icon-button>
     </div>
   `;
 }
}

यह रहा फ़ाइनल प्रॉडक्ट!

ब्रिक-व्यूअर एलिमेंट की मदद से, कार के ब्रिक मॉडल को नेविगेट करना

7. नतीजा

हमने अपना खुद का एचटीएमएल एलिमेंट बनाने के लिए, lit-element इस्तेमाल करने के तरीके के बारे में बहुत कुछ सीखा. हमने ये काम करने के बारे में सीखा:

  • कस्टम एलिमेंट तय करना
  • एट्रिब्यूट एपीआई का एलान करना
  • पसंद के मुताबिक बनाए गए एलिमेंट के लिए व्यू रेंडर करना
  • इनकैप्सुलेट स्टाइल
  • डेटा भेजने के लिए इवेंट और प्रॉपर्टी का इस्तेमाल करना

अगर आपको लाइट-एलिमेंट के बारे में ज़्यादा जानना है, तो इसकी आधिकारिक साइट पर जाएं.

stackblitz.com/edit/brick-viewer-complete पर ब्रिक-व्यूअर एलिमेंट का पूरा डेटा देखा जा सकता है.

ब्रिक व्यूअर को एनपीएम पर भी भेजा जाता है और सोर्स यहां देखा जा सकता है: GitHub रेपो.