简体   繁体   English

Vue.js从父级切换扩展v-for组件

[英]Vue.js toggling expanding v-for component from parent

I've got an 'Album' component that is being used on a page. 我在页面上使用了“相册”组件。 I am trying to create something whereby only one album can be toggled at a given time. 我正在尝试创建某种东西,以便在给定时间只能切换一张专辑。 So if an album is already open when clicking another it would close. 因此,如果在单击另一个专辑时已经打开了一个专辑,它将关闭。

扩展专辑的例子

Component being mounted recursively in the 'parent' app. 组件以递归方式安装在“父”应用程序中。

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

The component itself. 组件本身。

<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>

The component itself is storing its state with a simple 'expanded' data attribute. 组件本身使用简单的“扩展”数据属性存储其状态。 Currently this means that the component works nicely when a user is opening and closing each album, however, problems occur when they are opening several at a time. 当前,这意味着该组件在用户打开和关闭每张专辑时可以很好地工作,但是,当他们一次打开几张专辑时会出现问题。 Due to absolute positioning I am manually having to set the height of the container. 由于绝对定位,我不得不手动设置容器的高度。 The aim is to have only one open at a time. 目的是一次只能打开一个。 I am having trouble thinking of a way to store and track what album is currently open - I'm also unsure how the parent can manage the stage each album / open and closing them where. 我在思考如何存储和跟踪当前打开的专辑的方式时遇到了麻烦-我也不确定父母如何管理每个专辑的舞台/在哪里打开和关闭它们。 Even if I know which album is open in the parent how can I trigger individual child components methods? 即使我知道哪个相册在父目录中打开,如何触发单个子组件方法?

I've tried to be as clear as possible, please let me know if there's anything else I can make clearer. 我已尝试尽可能清楚,请让我知道是否还有其他我可以澄清的内容。

I'm not quite sure what you mean by recursive, as far as I can see you're not referencing the album component within itself recursively. 就我所知,您不是在递归地引用相册组件,因此我不太确定您的意思是递归。

I'd go with this approach: expanded is a property of your component. 我会采用这种方法: expanded是组件的属性。
On a click the component emits a this.$emit('expand', albumID) . 单击该组件将发出this.$emit('expand', albumID)
In your parent you listen for the @expand event and assign your expandedAlbumID to the event payload. 在你的父母你听的@expand事件和您的指定expandedAlbumID的事件负载。
The last remaining piece of the puzzle is now to pass your expanded property like :expanded="expandedAlbumID == album.id" 现在,剩下的最后一块难题就是传递您的expanded属性,例如:expanded="expandedAlbumID == album.id"

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM