import { Component, h, State } from '@stencil/core';
// import '@webcomponents/custom-elements';
import '@clr/core/icon/register';
import { ClarityIcons, plusIcon } from '@clr/core/icon';
ClarityIcons.addIcons(plusIcon);
@Component({
tag: 'tabs-component',
styleUrl: 'tabs-component.css',
shadow: false,
})
export class TabsComponent {
@State() tabs: Array<object> = [
(
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Cloud</button>
</li>
)
];
addTab(onHead = true) {
// debugger
const tab = (
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Dashboard</button>
</li>
);
if (onHead) {
this.tabs.unshift(tab);
} else {
this.tabs.push(tab);
}
console.log(this.tabs);
}
render() {
return (
<div>
<ul id="demoTabs" class="nav" role="tablist">
<li role="presentation" class="nav-item" onClick={() => this.addTab()}>
<cds-icon shape="plus" class="cursor"></cds-icon>
</li>
{this.tabs}
</ul>
<section id="panel1" role="tabpanel" aria-labelledby="tab1">
tab1
</section>
<section id="panel2" role="tabpanel" aria-labelledby="tab2" aria-hidden="true">
tab2
</section>
<section id="panel3" role="tabpanel" aria-labelledby="tab3" aria-hidden="true">
tab3
</section>
</div>
);
}
}
3 回答
Stencil 执行严格的相等检查 ( ===
) 以确定 Prop/State 变量是否已更改,这就是它未检测到push
更改的原因unshift
。您必须确保用新的阵列替换阵列。在您的示例中执行此操作的最快方法是在操作后手动将数组替换为副本:
if (onHead) {
this.tabs.unshift(tab);
} else {
this.tabs.push(tab);
}
this.tabs = [...this.tabs];
有关更新数组,请参阅Stencil 文档。
这是一个参照平等的问题。对象总是通过引用而不是值传递,因此两个对象永远不会相等(引用方式,即使它们包含相同的值)。
数组是一种特殊的对象,因此也是通过引用传递的。修改数组的值不会改变它的引用。
一些例子来说明这一点:
const foo = ['a', 'b'];
console.log(foo === ['a', 'b', 'c']); // false
foo.push('c');
console.log(foo === ['a', 'b', 'c']); // still false
console.log(['a', 'b', 'c'] === ['a', 'b', 'c']); // actually always false
console.log(foo === foo); // always true because it is the same reference
Stencil@State()
使用相同的严格相等运算符比较修饰的类成员===
(同样适用@Prop()
)。如果值相同,则不会重新渲染组件。
对于您的tabs
状态,值this.tabs
是对您分配给它的数组的引用。修改数组(例如this.tabs.push(...)
)只会更改引用的数组的值,this.tabs
但不会更改存储在 中的实际引用this.tabs
。
因此,您需要重新分配this.tabs
以让 Stencil 知道该成员已更改。最简单的方法是
this.tabs = [...this.tabs];
它将数组的值传播到一个新的数组中(返回一个新的引用)。或者,类似的东西this.tabs = this.tabs.slice()
也可以解决问题(任何返回新数组的东西都可以)。
在您的情况下,最简单的方法是将您的addTab
方法更改为
addTab(onHead = true) {
const tab = (
<li role="presentation" class="nav-item">
<button id="tab3" class="btn btn-link nav-link" aria-controls="panel3"
aria-selected="false" type="button">Dashboard</button>
</li>
);
this.tabs = onHead ? [tab, ...this.tabs] : [...this.tabs, tab];
}
(即在新项目之前或之后传播原始值)。
看起来 temp 变量起作用了,奇怪。
const tempTabs = [...this.tabs];
if (onHead) {
tempTabs.unshift(tab);
} else {
tempTabs.push(tab);
}
this.tabs = tempTabs;