我要完成的工作: 我在页面上显示了一些过滤器,以过滤页面上显示的产品。在移动设备中,我想将这些过滤器隐藏在一个按钮后面,一旦按下该按钮,这些过滤器就会从侧面的滑出菜单中显示出来。
虽然我可以在页面上重复两次相同的组件,但是这些组件不是完全相同的实例,也就是说,单击过滤器将触发该函数来过滤页面上的产品,但是它设置了自己的数据属性,我用来说“如果data attribute'selected'为true,则向该组件添加一个'selected'类。当我调整窗口大小时,该组件的另一个实例没有将'selected'数据属性标记为” “真”。
我希望如此,因为来自文档:
请注意,单击按钮时,每个按钮都会保留自己的单独计数。这是因为每次使用组件时,都会创建该组件的新实例。
...但是最好的方法是什么?
我只考虑在组件上设置类“ mobile”,而.mobile css会为组件设置不同的样式,但是我需要它打破嵌套的位置。
例如
<body>
<header>
<!-- desktop -->
<guitar-filters>
<header>
<!-- mobile -->
<guitar-filters>
</body
这是我的Vue组件“吉他过滤器”,其中显示了几个名为“仪器过滤器”的组件:
Vue.component('guitar-filters', {
data: function() {
return {
isMobile: false
}
},
mounted: function() {
var comp = this;
this.setIsMobile();
window.addEventListener('resize', function() {
comp.setIsMobile();
});
},
methods: {
setIsMobile: function() {
this.isMobile = (window.innerWidth <= 900) ? true : false;
}
},
template: `
<ul class="filters" :class="{mobile: isMobile}">
<li>
All
</il>
<li>
Series
<ul>
<instrument-filter filter-by="series" filter="All">All</instrument-filter>
<instrument-filter filter-by="series" filter="Frontier">Frontier</instrument-filter>
<instrument-filter filter-by="series" filter="Legacy">Legacy</instrument-filter>
<instrument-filter filter-by="series" filter="USA">USA</instrument-filter>
</ul>
</li>
<li>
Body Shape
<ul>
<instrument-filter filter-by="bodyType" filter="All">All</instrument-filter>
<instrument-filter filter-by="bodyType" filter="Concert">Concert</instrument-filter>
<instrument-filter filter-by="bodyType" filter="Concertina">Concertina</instrument-filter>
<instrument-filter filter-by="bodyType" filter="Concerto">Concerto</instrument-filter>
<instrument-filter filter-by="bodyType" filter="Orchestra">Orchestra</instrument-filter>
</ul>
</li>
</ul>
`
});
仪器过滤器组件
Vue.component('instrument-filter', {
data: function() {
return {
selected: false
}
},
props : [
'filterBy',
'filter'
],
methods: {
addFilter: function() {
this.$root.$emit('addFilter',{filterBy: this.filterBy,filter: this.filter});
},
clearFilter: function() {
this.$root.$emit('clearFilter',{filterBy: this.filterBy,filter: this.filter});
}
},
template: `
<li :class="{ 'selected' : selected }" @click="selected = !selected; selected ? addFilter() : clearFilter()"><slot></slot></li>
`
});
.css:
ul.filters > li > ul > li.selected::before {
content: "✔️";
...
}
目标是使两个实例中的过滤器都具有“ selected”类。如果我单击“音乐会”的身体形状,然后将窗口调整为移动断点的大小,则还将选择该过滤器组件的其他实例。
编辑:我可以破解这个。我可以使用javascript移动该组件的一个实例,但是我正在学习Vue,并希望以此实现Vue的方式和最佳实践。
答案 0 :(得分:3)
您可以通过多种方法来处理此问题。看来您已经沿着事件总线路径开始了。另一种选择是使用共享应用程序状态(请参见Vuex)。
我所做的与共享状态类似,但是仅使用应用程序(相同的内容将应用于公共父组件)数据。共享库被传递到组件的两个实例。如果选择了一个项目,则将切换相应的条目。由于对象是共享的,因此两个组件保持同步。
如果没有公共的父组件,则必须查看事件或状态。
看看是否有帮助。
Vue.component('guitar-filters', {
props: [ 'data' ],
data: function() {
return {
isMobile: false
}
},
mounted: function() {
var comp = this;
this.setIsMobile();
window.addEventListener('resize', function() {
comp.setIsMobile();
});
},
methods: {
setIsMobile: function() {
this.isMobile = (window.innerWidth <= 900) ? true : false;
}
},
template: `
<ul class="filters" :class="{mobile: isMobile}">
<li>
All
</il>
<li>
Series
<instrument-filters :list="data.seriesFilters"/>
</li>
<li>
Body Shape
<instrument-filters :list="data.bodyFilters"/>
</li>
</ul>
`
});
Vue.component('instrument-filters', {
props : [ 'list', ],
methods: {
toggle(toggleItem) {
let itemInList = this.list.find((item) => item.value === toggleItem.value);
itemInList.selected = !itemInList.selected;
},
},
template: `
<ul>
<li v-for="item in list" :class="{ 'selected' : item.selected }" @click="toggle(item)">{{ item.label }}</li>
</ul>
`
});
new Vue({
el: "#app",
data: {
filterData: {
seriesFilters: [
{ label: 'All', value: 'All', selected: false },
{ label: 'Frontier', value: 'Frontier', selected: false },
{ label: 'Legacy', value: 'Legacy', selected: false },
{ label: 'USA', value: 'USA', selected: false },
],
bodyFilters: [
{ label: 'All', value: 'All', selected: false },
{ label: 'Concert', value: 'Concert', selected: false },
{ label: 'Concertina', value: 'Concertina', selected: false },
{ label: 'Concerto', value: 'Concerto', selected: false },
{ label: 'Orchestra', value: 'Orchestra', selected: false },
],
}
},
});
ul {
margin-left:20px;
}
ul > li {
cursor: pointer;
}
ul.filters > li > ul > li.selected::before {
content: "✔️";
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<header>
<!-- desktop -->
<guitar-filters :data="filterData" />
</header>
<!-- mobile -->
<guitar-filters :data="filterData" />
</div>