@Leopandro
Разработчик CRM/ERP систем

VueJS и localstorage реактивный?

Можно ли как нибудь сделать реактивное обновление и отображение данных и отображение данных в зависимости от условий полученных после извлечения этих данных из локального хранилища динамически?
Я тут попытался это сделать - получился небольшой франкенштейн из 2 параметров.
<template>
    <div class="accordion">
        <div v-if="!item.parent_id" class="box">
            <button class="node-tree-button px-0" v-on:click="addNode()">
                <div class="">
                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    </svg>
                </div>
                <div class="node-tree-button-add-text p-1 px-3">
                        Добавить корневую папку
                </div>
            </button>
            <div class="how-to p-1">
                <router-link to="/how-to-node">
                 Как перемещать создавать и редактировать папки
                </router-link>
            </div>
        </div>
        <div ref="accordion-item" :id="'kt_accordion_'+item.id" v-if="item && item.name && item.parent_id" class="accordion-item">
            <h2 class="accordion-header" :id="'kt_accordion_'+item.id+'_header_'+item.id"  @mouseover="isHovering = true"
                @mouseout="isHovering = false" >
                <div class="node-item-wrapper notice d-flex bg-light-primary rounded border p-2" type="button"
                     v-on:click="folderClick(item.id)"
                        :data-bs-target="'#kt_accordion_'+item.id+'_body_'+item.id">
                    <svg class="add-to-folder" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    </svg>
                    <div class="min-w-10px">
                        <div style="width: 24px" v-if="item.children && item.children.length > 0" v-on:click="toggleChildren()">
                            <span class="svg-icon svg-icon-primary svg-icon-2x">
                                <svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
                                </svg>
                            </span>
                        </div>
                    </div>
                    <div ref="div"
                         class="node-tree-folder-name p-1"
                         :style="{display: showEditInput ? 'none' : 'block'}"
                         :id="'node_item_'+item.id+'_input'">
                        {{ item.name }}
                    </div>
                    <input type="text" ref="input" :style="{display: showEditInput ? 'block' : 'none'}"
                           @keydown.enter="saveNode">
                    <div class="pl-1">
                        <svg v-on:click="addNode()" :style="{visibility: isHovering ? 'visible' : 'hidden'}" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                         </svg>
                    </div>

                    <div class="pl-1">
                        <svg v-on:click="editNode()" :style="{visibility: isHovering ? 'visible' : 'hidden'}" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        </svg>
                    </div>

                    <div class="pl-1">
                        <svg v-on:click="deleteNode()" :style="{visibility: isHovering ? 'visible' : 'hidden'}" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                         </svg>
                    </div>
                </div>
            </h2>
        </div>
        <template v-for="(newItem, index) of item.children">
            <div :style="{display: showChildrenFlag ? 'block' : 'none'}"  :id="'kt_accordion_'+item.id+'_body_'+item.id"
                 class="accordion-collapse collapse show"
                 aria-labelledby="kt_accordion_1_header_1"
                 :data-bs-parent="'#kt_accordion_'+item.id">
                <div class="node-tree-child">
                    <node-tree ref="node-tree-item-child" :item="newItem" :index="index" :name="newItem.name" @change-value="changeValue">

                    </node-tree>
                </div>
            </div>
        </template>
    </div>
</template>
<script>
import ApiService from "@/core/services/ApiService";
import {useAuthStore} from "@/stores/auth";
export default {
    name: "NodeTree",
    props: [
        'item',
        'index',
    ],
    emits: ['update:name'],
    components: {
        'child': this
    },
    init() {
    },
    methods: {
        isVisible() {

        },
        async addNode() {
            const api = ApiService;
            const auth = useAuthStore();
            let openId = null;
            await api.post('/category-tree/add', {
                user_id: auth.user.id,
                id: this.item.id,
                name: 'Новая папка',
            }).then((response) => {
                if (!this.item.children) {
                    this.item.children = [];
                }
                this.item.children.push({
                    id: response.data.id,
                    name: response.data.name,
                    parent_id: response.data.parent_id
                });
                openId = response.data.id;
            });
            this.showChildren(openId);
        },
        async saveNode(event) {
            await this.$emit('change-value', {
                value: event.target.value,
                id: this.item.id
            });

            this.showEditInput = false;
        },
        async updateNode(object) {
            const api = ApiService;
            const auth = useAuthStore();
            await api.post('/category-tree/edit', {
                user_id: auth.user.id,
                id: object.id,
                name: object.name,
            }).then((response) => {
                if (!this.item.children) {
                    this.item.children = [];
                }
                const item = this.item.children.find(element => element.id === response.data.id);
                item.name = response.data.name;
            });
        },
        async editNode() {
            if (this.showEditInput === true) {
                await this.$emit('change-value', {
                    value: this.$refs.input.value,
                    id: this.item.id
                });
                this.showEditInput = !this.showEditInput;
                return;
            }
            this.$refs.input.value = this.item.name;
            this.showEditInput = !this.showEditInput;
            setTimeout(() => {
                this.$refs.input.focus();
            }, 1);

            this.emitter.emit("reload-tree");
        },
        async deleteNode() {
            if (confirm('Удалить папку')) {
                await this.$parent.deleteChildren(this.index);
            }
        },
        async changeValue(data) {
            await this.updateNode({
                name: data.value,
                id: data.id
            });
            let element = this.item.children.find(element => element.id === data.id);
            element.name = data.value;
        },
        async deleteChildren(id) {
            const api = ApiService;
            await api.post('/category-tree/delete', {
                id: this.item.children[id].id,
            }).then((response) => {
                let item = this.item.children.filter(function(item, index) {
                    return index !== id
                });
                this.item.children = item;
            });
        },
        showChildren(id = null) {
            this.showChildrenFlag = true;
            if (id) {
                const nodeItem = this.$refs["node-tree-item-child"].find((nodeItem) => {
                    return nodeItem.item.id === id;
                });
                nodeItem.editNode();
            }
        },
        hideChildren() {
            this.showChildrenFlag = false;
        },
        toggleChildren() {
            this.showChildrenFlag = !this.showChildrenFlag;
        },
        folderClick(id) {
            this.emitter.emit("pick-folder", id);
        }
    },
    data() {
        return {
            showEditInput: false,
            isHovering: false,
            showChildrenFlagProperty: true,
            task_categories: []
        }
    },
    computed: {
        showChildrenFlag: {
            get: function () {
                return this.showChildrenFlagProperty
            },
            set: function (value) {
                if (this.item) {
                    localStorage.setItem('node-item-' + this.item.id, value);
                    this.showChildrenFlagProperty = Boolean(value);
                }
            },
        }
    },
    mounted() {
        if (this.item.parent_id == null) {
            this.showChildrenFlagProperty = true;
        } else {
            if (localStorage.getItem('node-item-' + this.item.id) === 'false') {
                this.showChildrenFlagProperty = false;
                this.showChildrenFlag = false;
            } else {

                this.showChildrenFlagProperty = true;
                this.showChildrenFlag = true;
            }
        }

    },
};
</script>
<style>
</style>

Здесь самая главная загвоздка в том что тут используются 2 параметра - showChildrenFlagProperty и showChildrenFlag.
  • Вопрос задан
  • 352 просмотра
Пригласить эксперта
Ответы на вопрос 1
theartkod
@theartkod
front-end разработчик
Есть пакет с композициями — vueuse, в котором есть удобная утилита которая позволяет работать с локалстораджем как с реактивным объектом https://vueuse.org/core/useLocalStorage/

Ну или можно написать свою реализацию реактивного локалстораджа, точнее реакцию на изменения. https://developer.mozilla.org/en-US/docs/Web/API/W...
Ответ написан
Комментировать
Ваш ответ на вопрос

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

Похожие вопросы