【问题标题】:Vue.js toggling expanding v-for component from parentVue.js 从父级切换扩展 v-for 组件
【发布时间】:2019-08-14 23:03:10
【问题描述】:

我有一个正在页面上使用的“相册”组件。我正在尝试创建一些东西,在给定时间只能切换一张专辑。因此,如果一个相册在单击另一个相册时已经打开,它将关闭。

组件在“父”应用中递归挂载。

<album v-for="(album, index) in albums"
  :key="index"
  @expand="setAlbumContainerHeight"
  @action="removeFromCollection"
  :albumDetails="album"
  page="collection">
</album>

组件本身。

<template>
    <div v-on:click="toggleExpand" ref="album" class="album">
        <img class="album-artwork" alt="album-artwork" :src="albumDetails.cover_url">
        <div ref="expandContent" class="expanded-content">
            <div class="left-block">
                <div class="title">{{ albumDetails.title }}</div>
                <div class="artist">{{ albumDetails.artist }}</div>

                <!-- Search page specific -->
                <div v-if="page === 'search'" class="info">{{ albumDetails.year }}<br> <span v-for="genre in albumDetails.genre"> {{ genre }}</span><br> {{ albumDetails.label }}</div>
                <!-- Collection page specific -->
                <div v-if="page === 'collection'" class="info">{{ albumDetails.year }}<br> <span v-for="genre in albumDetails.genres"> {{ genre.genre }}</span><br> {{ albumDetails.label }}</div>

                <!-- Search page specific -->
                <button v-if="page === 'search'" v-on:click.stop="addToCollection" class="add-collection">Add to collection</button>
                <!-- Collection page specific -->
                <button v-if="page === 'collection'" v-on:click.stop="removeFromCollection" class="add-collection">Remove from collection</button>
            </div>

            <div v-if="page === 'search'" class="right-block">
                <div class="a-side">
                    <p v-for="track in albumDetails.track_list_one" class="track">{{ track }}</p>
                </div>
                <div class="b-side">
                    <p v-for="track in albumDetails.track_list_two" class="track">{{ track }}</p>
                </div>
            </div>

            <div v-if="page === 'collection'" class="right-block">
                <div class="a-side">
                    <p v-for="track in trackListOne" class="track">{{ track.track }}</p>
                </div>
                <div class="b-side">
                    <p v-for="track in trackListTwo" class="track">{{ track.track }}</p>
                </div>
            </div>

            <img class="faded-album-artwork" alt="faded-album-artwork" :src="albumDetails.cover_url">
        </div>
    </div>
</template>
<script>
    module.exports = {
        name: 'Album',
        props: ['albumDetails', 'page'],

        data: function () {
            return {
                expanded: false,
                expandedContentHeight: 0,
                trackListOne: [],
                trackListTwo: []
            }
        },

        mounted() {
            if (this.albumDetails.tracks) {
                this.getTrackListOne(this.albumDetails.tracks);
                this.getTrackListTwo(this.albumDetails.tracks);
            }
        },

        methods: {
            toggleExpand() {
                if (!this.expanded) {
                    this.expanded = true;
                    this.$refs.expandContent.style.display = 'flex';
                    this.expandedContentHeight = this.$refs.expandContent.clientHeight;
                    let height = this.$refs.album.clientHeight + this.expandedContentHeight;
                    this.$emit('expand', height, event);
                } else {
                    this.expanded = false;
                    this.$refs.expandContent.style.display = 'none';
                    let height = 'initial';
                    this.$emit('expand', height, event);
                }
            },

            addToCollection() {
                this.$emit('action', this.albumDetails.cat_no);
            },

            removeFromCollection() {
                this.$emit('action', this.albumDetails.cat_no);
            },

            getTrackListOne(tracks) {
                let halfWayThough = Math.floor(tracks.length / 2);
                this.trackListOne = tracks.slice(0, halfWayThough);
            },

            getTrackListTwo(tracks) {
                let halfWayThough = Math.floor(tracks.length / 2);
                this.trackListTwo = tracks.slice(halfWayThough, tracks.length);
            },
        },
    }
</script>
<style scoped lang="scss">
    @import './styles/album';
</style>

组件本身使用简单的“扩展”数据属性存储其状态。目前这意味着该组件在用户打开和关闭每个相册时运行良好,但是当他们一次打开多个相册时会出现问题。由于绝对定位,我必须手动设置容器的高度。目的是一次只打开一个。我在想办法存储和跟踪当前打开的专辑时遇到了麻烦——我也不确定父母如何管理每张专辑的舞台/在哪里打开和关闭它们。即使我知道在父项中打开了哪个相册,我如何触发各个子组件方法?

我已经尽量说清楚了,如果还有什么我可以说得更清楚的,请告诉我。

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-component


    【解决方案1】:

    我不太清楚你所说的递归是什么意思,据我所知,你并没有递归地引用专辑组件本身。

    我会采用这种方法: expanded 是组件的属性。
    单击时,组件会发出this.$emit('expand', albumID)
    在您的父母中,您侦听 @expand 事件并将您的 expandedAlbumID 分配给事件有效负载。
    现在剩下的最后一块拼图是传递您的expanded 属性,例如:expanded="expandedAlbumID == album.id"

    完整的工作示例:https://codesandbox.io/s/o5p4p45m9

    【讨论】:

    • 抱歉,我可能在这里使用了错误的术语。您的解决方案看起来肯定会在您提供的工作示例中发挥作用。非常感谢您花时间创建一个示例,我现在来看看并实现类似的东西。
    • 再次感谢您,这真的很烦人,因为我不得不设置容器的高度,因为这使它变得更加复杂。将继续开发,看看我是否能提出解决方案。
    • 我刚刚注意到一件事,如果用户单击当前打开的(即关闭它),这不会跟踪。需要在扩展的方式中构建更多逻辑。
    • @JakeFauvel 在expandedEvent 方法中只检查新的id 是否等于旧的id,如果是则将其设置为null。 if (e !== this.expandedAlbumID) this.expandedAlbumID = e; else this.expandedAlbumID = null;
    • 是的,这就是我所走的路线。效果很好。现在正确拍摄扩展专辑。只需要对高度进行排序。不应该很棘手。只需要移除之前展开的相册高度即可。
    猜你喜欢
    • 2019-08-06
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多