@dmitriyuvin
FullStack developer ( Laravel & Vue )

Как проверить значение из LocalStorage?

Есть FeedContainer.
<template>
    <div class="feed-container">
        <div class="navigation">
            <b-button
                class="btn-add-tweet"
                rounded
                size="is-medium"
                type="is-danger"
                icon-left="twitter"
                icon-pack="fab"
                @click="onAddTweetClick"
            >
                Tweet :)
            </b-button>
            <div class="buttons">
                <button
                    class="btn-left"
                    :class="{ 'btn-active': cardsViewSeen }"
                    @click="changeViewToCards"
                >
                    <img src="https://img.icons8.com/ios-filled/24/000000/health-data.png" />
                </button>
                <button
                    class="btn-right"
                    :class="{ 'btn-active': mediaObjViewSeen }"
                    @click="changeViewToMedia"
                >
                    <img src="https://img.icons8.com/ios-filled/24/000000/menu.png" />
                </button>
            </div>
        </div>
        <TweetPreviewList
            :tweets="tweets"
            @infinite="infiniteHandler"
            :cards-view-seen="cardsViewSeen"
            :media-obj-view-seen="mediaObjViewSeen"
        />
        <b-modal :active.sync="isNewTweetModalActive" has-modal-card>
            <NewTweetForm />
        </b-modal>
    </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex';
import TweetPreviewList from '@/components/common/TweetPreviewList.vue';
import { pusher } from '@/services/Pusher';
import { SET_TWEET } from '@/store/modules/tweet/mutationTypes';
import showStatusToast from '@/components/mixin/showStatusToast';
import NewTweetForm from './NewTweetForm.vue';

export default {
    name: 'FeedContainer',

    mixins: [showStatusToast],

    components: {
        TweetPreviewList,
        NewTweetForm,
    },

    data: () => ({
        isNewTweetModalActive: false,
        page: 1,
        mediaObjViewSeen: true,
        cardsViewSeen: false
    }),

    async created() {
        try {
            await this.fetchTweets({
                page: 1
            });
        } catch (error) {
            this.showErrorMessage(error.message);
        }

        const channel = pusher.subscribe('private-tweets');

        channel.bind('tweet.added', (data) => {
            this.$store.commit(`tweet/${SET_TWEET}`, data.tweet);
        });
    },

    beforeDestroy() {
        pusher.unsubscribe('private-tweets');
    },

    computed: {
        ...mapGetters('tweet', {
            tweets: 'tweetsSortedByCreatedDate'
        }),
    },

    methods: {
        ...mapActions('tweet', [
            'fetchTweets',
        ]),

        changeViewToMedia() {
            this.mediaObjViewSeen = true;
            this.cardsViewSeen = false;
        },
        changeViewToCards() {
            this.mediaObjViewSeen = false;
            this.cardsViewSeen = true;
        },

        onAddTweetClick() {
            this.showAddTweetModal();
        },

        showAddTweetModal() {
            this.isNewTweetModalActive = true;
        },

        async infiniteHandler($state) {
            try {
                const tweets = await this.fetchTweets({ page: this.page + 1 });

                if (tweets.length) {
                    this.page += 1;
                    $state.loaded();
                } else {
                    $state.complete();
                }
            } catch (error) {
                this.showErrorMessage(error.message);
                $state.complete();
            }
        },
    },
    mounted() {
        if (localStorage.getItem('mediaObjViewSeen') === true) {
            this.mediaObjViewSeen = true;
            this.cardsViewSeen = false;
        }
        if (localStorage.getItem('cardsViewSeen') === true) {
            this.mediaObjViewSeen = false;
            this.cardsViewSeen = true;
        }
    },

    watch: {
        mediaObjViewSeen(newMediaObjViewSeen) {
            localStorage.setItem('mediaObjViewSeen', newMediaObjViewSeen);
            this.mediaObjViewSeen = newMediaObjViewSeen;
        },
        cardsViewSeen(newCardsViewSeen) {
            localStorage.setItem('cardsViewSeen', newCardsViewSeen);
            this.cardsViewSeen = newCardsViewSeen;
        },
    }

};
</script>

<style lang="scss" scoped>
@import '~bulma/sass/utilities/initial-variables';

.buttons {
    float: right;
}
.btn-left, .btn-right {
    border: none;
    padding: 10px;
    outline: none;
}

.btn-left {
    border-radius: 5px 0 0 5px;
}

.btn-right{
    border-radius: 0 5px 5px 0;
}

.btn-active{
    background: #ff3860;
}

.navigation {
    padding: 10px 0;
    margin-bottom: 20px;
}

.modal-card {
    border-radius: 6px;
}

.btn-add-tweet {
    transition: 0.2s ease-out all;
    box-shadow: 1px 5px 5px 0 #00000020;

    &:hover {
        box-shadow: 1px 1px 0 0 #00000020;
    }

    @media screen and (max-width: $tablet) {
        font-size: 1rem;
    }
}

</style>

В mounted я проверяю, есть ли значение в LocalStorage и равно ли оно true.
Если есть то присваиваю mediaObjViewSeen = true, a cardsViewSeen = false.
mediaObjViewSeen - вид таблицей, cardsViewSeen - вид карточками.
При нажатии на кнопки, изменяем значения с помощью функций changeViewToMedia и changeViewToCards.
И с помощью watch, я отслеживаю изменения и записываю в LocalStorage.
В хранилище пишется правильно и после перезагрузки остаются нужные данные, но выводит не тот вид.
Как решить эту проблему?

TweetPreviewList.vue
<template>
    <div class="tweets-container">
        <transition-group name="slide-prev" tag="div">
            <template v-for="tweet in tweets">
                <TweetPreview
                    :key="tweet.id"
                    :tweet="tweet"
                    @click="onTweetClick"
                    :cards-view-seen="cardsViewSeen"
                    :media-obj-view-seen="mediaObjViewSeen"
                />
            </template>
        </transition-group>
        <infinite-loading @infinite="infiniteHandler">
            <div slot="no-more" />
            <div slot="no-results" />
            <div slot="spinner" />
        </infinite-loading>
    </div>
</template>

<script>
import InfiniteLoading from 'vue-infinite-loading';
import TweetPreview from './TweetPreview.vue';

export default {
    name: 'TweetPreviewList',

    props: {
        tweets: {
            type: Array,
            required: true
        },
        mediaObjViewSeen: {
            type: Boolean,
        },
        cardsViewSeen: {
            type: Boolean,
        }
    },
    components: {
        TweetPreview,
        InfiniteLoading,
    },

    methods: {
        onTweetClick(tweet) {
            this.$router.push({ name: 'tweet-page', params: { id: tweet.id } }).catch(() => {});
        },

        infiniteHandler($state) {
            this.$emit('infinite', $state);
        },
    },
};
</script>

<style lang="scss" scoped>
.tweets-container {
    padding-bottom: 20px;
}
</style>

TweetPreview.vue
<template>
    <div
        class="box tweet"
        :class="{ 'col-f': cardsViewSeen }"
        @click="$emit('click', tweet)"
    >
        <CardsView v-if="cardsViewSeen" :tweet="tweet" />
        <MediaObjView v-if="mediaObjViewSeen" :tweet="tweet" />
    </div>
</template>

<script>
import CardsView from '../view/feed/CardsView.vue';
import MediaObjView from '../view/feed/MediaObjView.vue';

export default {
    name: 'TweetPreview',

    components: {
        CardsView,
        MediaObjView
    },

    props: {
        tweet: {
            type: Object,
            required: true,
        },
        mediaObjViewSeen: {
            type: Boolean,
        },
        cardsViewSeen: {
            type: Boolean,
        }
    },
};
</script>
<style lang="scss" scoped>
    @import '../../styles/common';

    .col-f {
        width: 32%;
        display: inline-block;
        margin-left: 1%;
        vertical-align: top;
    }
    .card-image {
        min-height: 160px;
    }
    .card-image figure {
        min-height: 160px;
    }
    .tweet {
        cursor: pointer;
        padding: 15px;
        border-radius: 5px;
        box-shadow: 5px 5px 5px 0 #00000020;
        transition: 0.2s ease-out all;


        &:hover {
            box-shadow: 1px 1px 0 0 #00000020;
        }

        &-image {
            margin: 12px 0 0 0;

            img {
                width: auto;
            }
        }

        .nickname {
            margin-left: 5px;
        }

        .created {
            margin-left: 5px;
        }
    }
    @media (min-width: 500px) and (max-width: 768px) {
        .col-f {
            width: 49%;
            display: inline-block;
            margin-left: 1%;
        }
    }
    @media (max-width: 499px) {
        .col-f {
            width: 100%;
        }
    }
</style>
  • Вопрос задан
  • 288 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега Vue.js
if (localStorage.getItem('mediaObjViewSeen') === true) {

Было бы круто, если вы хотя бы поверхностно знакомились с инструментом, прежде чем его использовать:

Ключи и значения всегда строки

Строка не может быть равна булеву значению, сами (надеюсь) понимаете.

Но вообще, по-хорошему, проверять ничего не надо - вместо двух булевых свойств должно быть одно строковое, обозначающее, в каком виде представлять данные:

data: () => ({
  view: localStorage.getItem('view') || 'CardsView',
  // ...
}),
watch: {
  view: val => localStorage.setItem('view', val),
},

Описания доступных вариантов представления складываете в массив, на основе этого массива создаёте кнопки для переключения представлений:

data: () => ({
  views: [
    {
      name: 'CardsView',
      btnClass: 'btn-left',
      img: '...',
    },
    {
      name: 'MediaObjView',
      btnClass: 'btn-right',
      img: '...',
    },
  ],
  // ...
}),

<button
  v-for="n in views"
  :class="[ n.btnClass, view === n.name ? 'btn-active' : '' ]"
  @click="view = n.name"
>
  <img :src="n.img">
</button>

Передаёте view в TweetPreview, используете его значение как имя компонента:

<component
  :is="view"
  :tweet="tweet"
/>
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы