在使用Vue js时,Webcomponents每次都会重新初始化



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

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

    --以上三个解决方案与我试图创建的并不完全匹配。

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

JSFiddle直连

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>

<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

因此,每次点击复选框时也会添加/删除<search-bar>

如果您想要<search-bar>的状态,则必须将其保存在<search-bar>组件之外的某个位置:

  • JavaScript变量
  • 本地存储
  • .getRootnode((.host
  • CSS属性我会选择这个属性,因为它们会逐渐进入shadowDOM

或者将复选框代码更改为不使用v-if,而是使用任何CSS:隐藏<div>

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

和/或。。。

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

您可以使用<style>元素轻松切换样式:

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

onload事件确保在页面加载时不应用<style>

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

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

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

比起Frameworks,我更喜欢原生。<style v-if='visible'/>将起作用。。通过粗暴地删除/添加样式表。

最新更新