【问题标题】:Webcomponents is re-initializing every time while working with Vue js每次使用 Vue js 时,Webcomponents 都会重新初始化
【发布时间】:2020-08-08 07:16:23
【问题描述】:

我为多个项目所需的通用输入框创建了一个 web 组件。 设计功能保持不变,只有我必须在每个项目上使用切换主题。所以我决定继续使用 webcomponents。其中一个项目基于 Vue Js。在 Vue js 中,DOM 内容在每次更新时重新呈现启用反应性。 vue 模板的重新渲染正在重新初始化我的自定义 web 组件,这将导致我使用 setter 分配给组件的所有配置丢失。 我知道以下解决方案。但我想使用 setter 方法。

  • 将数据作为属性传递
  • 基于事件的配置传递。
  • 使用 Vue 指令。
  • 使用 v-show 代替 v-if

    -- 以上三个解决方案与我要创建的解决方案并不真正匹配。

我在 jsfiddle 中创建了一个示例项目来显示我的问题。 每次我取消选中并选中复选框时,我的组件的新实例正在创建。这导致失去我选择的主题。 (请检查他的活动框数) 对于这个特定示例,我希望显示蓝色主题。但是一直变红

JSFiddle direct Link

class InputBox extends HTMLElement {
    constructor() {
        super();
        window.activeBoxes ? window.activeBoxes++ : window.activeBoxes = 1;
        var shadow = this.attachShadow({
            mode: 'open'
        });
        var template = `
        	<style>
          	.blue#iElem {
            	background: #00f !important;
            	color: #fff !important;
            }
						.green#iElem {
            	background: #0f0 !important;
            	color: #f00 !important;
            }
            #iElem {
                background: #f00;
                padding: 13px;
                border-radius: 10px;
                color: yellow;
                border: 0;
                outline: 0;
                box-shadow: 0px 0px 14px -3px #000;
              
            }
          </style>
        	<input id="iElem" autocomplete="off" autocorrect="off" spellcheck="false" type="text" />
        `;
        shadow.innerHTML = template;
        this._theme = 'red';
        
        this.changeTheme = function(){
        	this.shadowRoot.querySelector('#iElem').className = '';
    			this.shadowRoot.querySelector('#iElem').classList.add(this._theme);
        }
        
    }
    connectedCallback() {
    	this.changeTheme();
    }
    set theme(val){
    	this._theme = val;
      this.changeTheme();
		}
}
window.customElements.define('search-bar', InputBox);
<!DOCTYPE html>
<html>
  <head>
    <title>Wrapper Component</title>
    <script src="https://unpkg.com/vue"></script>
    <style>
      html,
      body {
        font: 13px/18px sans-serif;
      }
      select {
        min-width: 300px;
      }
      search-bar {
        top: 100px;
        position: absolute;
        left: 300px;
      }
      input {
        min-width: 20px;
        padding: 25px;
        top: 100px;
        position: absolute;
      }
    </style>
  </head>
  <body>
    <div id="el"></div>

    <!-- using string template here to work around HTML <option> placement restriction -->
    <script type="text/x-template" id="demo-template">
      <div>
      	
      	<div class='parent' contentEditable='true' v-if='visible'>
          <search-bar ref='iBox'></search-bar>
        </div>
        <input type='checkbox' v-model='visible'>
      </div>
    </script>

    <script type="text/x-template" id="select2-template">
      <select>
        <slot></slot>
      </select>
    </script>

    <script>
      var vm = new Vue({
        el: "#el",
        template: "#demo-template",
        data: {
          visible: true,
        },
        mounted(){
        		let self = this
            setTimeout(()=>{
              self.$refs.iBox.theme = 'blue';
            } , 0)
        }        
      });
    </script>
  </body>
</html>

【问题讨论】:

    标签: javascript vue.js vue-component web-component custom-element


    【解决方案1】:
    <div class='parent' contentEditable='true' v-if='visible'>
         <search-bar ref='iBox'></search-bar>
    </div>
    <input type='checkbox' v-model='visible'>
    

    Vue 的 v-if 将从 DOM 中添加/删除整个 DIV

    所以&lt;search-bar&gt; 也会在每次单击复选框时添加/删除

    如果您想要&lt;search-bar&gt; 的状态,您必须将其保存在&lt;search-bar&gt; 组件外部 的某个位置:

    或者将您的复选框代码更改为不使用v-if,而是隐藏带有任何CSS的&lt;div&gt;:

    • 显示:无
    • 可见性:隐藏
    • 不透明度:0
    • 移至屏幕外位置
    • 身高:0
    • ...

    和/或...

    使用样式表管理多个屏幕元素

    您可以使用&lt;style&gt; 元素轻松切换样式:

    <style id="SearchBox" onload="this.disabled=true">
     ... lots of CSS
     ... even more CSS
     ... and more CSS
    </style>
    

    onload 事件确保&lt;style&gt;不应用于页面加载。

    • 激活所有 CSS 样式:
      (this.shadowRoot || document).getElementById("SearchBox").disabled = false

    • 删除所有 CSS 样式:
      (this.shadowRoot || document).getElementById("SearchBox").disabled = true

    您确实需要 CSS Properties 才能与 shadowDOM 元素组合使用。

    我更喜欢原生而不是框架。 &lt;style v-if='visible'/&gt; 将起作用.. 通过粗暴地删除/添加样式表。

    【讨论】:

    • 感谢@Danny 提供的详细信息。我决定按属性继续。
    猜你喜欢
    • 1970-01-01
    • 2018-06-19
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 2014-05-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多