Vue компонентам не присвоен уникальный идентификатор - PullRequest
0 голосов
/ 13 июля 2020

У меня есть одностраничное приложение для отображения информации датчиков со всего дома. У меня есть компонент, который отображает датчик, использующий библиотеку highcharts. В зависимости от отображаемой информации существует разное количество датчиков для разных помещений. У меня есть параметры для отображения датчиков (max, min, форматирование и т.д. c), хранящихся в массиве состояний vuex. Все комнаты - это разные маршруты в моем приложении с их собственной ссылкой на панели навигации.

Если я нажимаю на первую комнату (скажем, офис), отображаются три датчика - все в порядке. Однако, если я сейчас нажму на гараж (в котором есть только один датчик), то параметры для первого датчика не изменятся по сравнению с предыдущим дисплеем в офисе. Это как если бы компонент хранится в памяти и его настройки не обновляются.

Вот мой код, чтобы помочь моему объяснению, сначала компонент датчика:

<template>
    <div :ref="'gauge-'+_uid" class="border gauge-container"></div>
</template>

<script>
module.exports = {
    props: {
        'gValue': {type: Number, default: 20},
        'gMin': {type: Number, default: 0},
        'gMax': {type: Number, default: 100},
        'gUnits': {type: String, default: ""},
    },
    data: function () {
        return {
            // Data for chart
            chart: null,
            gaugeOptions: {
                chart: {
                    type: 'solidgauge'
                },
                title: null,
                pane: {
                    size: 200,
                    center: ['50%', '75%'],
                    startAngle: -90,
                    endAngle: 90,
                    background: {
                        backgroundColor:
                            Highcharts.defaultOptions.legend.backgroundColor || '#EEE',
                        innerRadius: '60%',
                        outerRadius: '100%',
                        shape: 'arc'
                    }
                },
                tooltip: {
                    enabled: false
                },
                // the value axis
                yAxis: {
                    stops: [
                        [0.1, '#55BF3B'], // green
                        [0.5, '#DDDF0D'], // yellow
                        [0.9, '#DF5353'] // red
                    ],
                    lineWidth: 0,
                    tickWidth: 0,
                    minorTickInterval: null,
                    tickAmount: 0,
                    title: {
                        y: -70
                    },
                    labels: {
                        y: 16
                    },
                    min: this.gMin,
                    max: this.gMax,
                    title: null,
                },
                plotOptions: {
                    solidgauge: {
                        dataLabels: {
                            y: 5,
                            borderWidth: 0,
                            useHTML: true
                        }
                    }
                },
                credits: {
                    enabled: false
                },
                series: [{
                    data: [this.gValue],
                    dataLabels: {
                    format:
                        '<div style="text-align:center">' +
                        '<span style="font-size:14px">{y} ' + this.gUnits + '</span>' +
                        '</div>'
                    },
                }],
            }
        }
    },
    mounted: function () {
        console.log(this._uid) // Look at the id that is generated -- this is not being updated!
        Highcharts.setOptions(
            {
                chart: {
                    style: {
                        fontFamily: 'roboto'
                    }
                }
            }
        )
        this.chart = Highcharts.chart(
            this.$refs['gauge-' + this._uid], 
            this.gaugeOptions
        )
    },
    watch: {
        gValue: function (val) {
            this.chart.series[0].points[0].update(val)
        },
    }
}
</script>

<style scoped>
.gauge-container {
    max-width: 250px;
    height: 180px;
}
</style>
* 1007 console.log там, чтобы проверить идентификатор - я думаю, здесь возникает проблема. Он обновляется только тогда, когда я go со страницы с одним уровнемером до трех (добавляет еще два идентификатора). Есть ли способ уничтожить компонент датчика, когда я покидаю эту часть маршрута?

и теперь родительский компонент, который вызывает компонент датчика:

<template>
    <div v-if="hasRooms" id="room">
        <b-container>
            <h2>{{ roomName }}</h2>
            <b-row align-h="center">
                <b-col sm="3" class="text-center p-0 ml-1 mr-1"  v-for="device in deviceList" v-bind:key="deviceList.name">
                    <p>{{ device.name }} - {{ device.function }}</p>
                    <highchart v-if="device.format == 'default'" :g-value="device.value">
                        <template v-slot:title>
                            {{ device.function | capitalize }}
                        </template>
                    </highchart>
                    <highchart v-else
                        v-bind:g-value="device.value"
                        v-bind:g-min="device.format.min"
                        v-bind:g-max="device.format.max"
                        v-bind:g-units="device.format.units"
                    >
                        <template v-slot:title>
                            {{ device.function | capitalize }}
                        </template>
                    </highchart>
                </b-col>
            </b-row>
        </b-container>
    </div>
</template>

<script>
module.exports = {
    name: 'room',

    /** Load external component files
     *  Make sure there is no leading / in the name
     *  To load from the common folder use like: 'common/component-name.vue' */
    components: {
        'highchart': httpVueLoader('components/HighCharts.vue'),
    }, // --- End of components --- //
    
    data() {
        return {

        };
    },
    computed: {
        hasRooms() {
            return this.$store.getters['rooms/nRooms'] > 0;
        },
        roomName() {
            return this.$store.getters['rooms/getRoomById'](this.$route.params.roomId);
        },
        deviceList() {
            return this.$store.getters['rooms/getDevicesinRoom'](this.$route.params.roomId);
        },
    },
    filters: {
        capitalize: function (value) {
            if (!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
        },
        tonumber: function (value){
            if (!value) return ''
            return parseFloat(value)
        }
    },
}
</script>

Комнаты генерируются роутер и рендеринг из:

<template>
    <div id="rooms">
        <b-alert variant="info" :show="!hasRooms">
            <p>
                There are no rooms available yet. Pass a message that defines a room id and device id 
                to the uibuilder node first. See <router-link :to="{name: 'usage_info'}">the setup information</router-link> 
                for instructions on how start using the interface.
            </p>
        </b-alert>
        <router-view></router-view>
    </div>
</template>

<script>
module.exports = {
    name: 'RoomsOverview',
    data() {
        return {

        };
    },
    computed: {
        hasRooms() {
            return this.$store.getters['rooms/nRooms'] > 0;
        },
        roomList() {
            return this.$store.getters['rooms/getAllRooms'];
        },
    },
}
</script>

1 Ответ

0 голосов
/ 13 июля 2020

Хорошо, после небольшого поиска я использовал последний метод на этой странице (https://michaelnthiessen.com/force-re-render/). При изменении маршрута он вызывает метод forceRerender () в моем родительском компоненте. Вот обновленные компоненты:

Помещение. vue:

<template>
    <div v-if="hasRooms" id="room">
        <b-container>
            <h2>{{ roomName }}</h2>
            <b-row align-h="center">
                <b-col sm="3" class="text-center p-0 m-1"  v-for="device in deviceList" v-bind:key="deviceList.name">
                    <highchart v-if="device.format == 'default'" :g-value="device.value" :key="componentKey">
                        <template v-slot:title>
                            {{ device.function | capitalize }}
                        </template>
                    </highchart>
                    <highchart v-else
                        :g-value="device.value"
                        :g-min="device.format.min"
                        :g-max="device.format.max"
                        :g-units="device.format.units"
                        :key="componentKey"
                    >
                        <template v-slot:title>
                            {{ device.function | capitalize }}
                        </template>
                    </highchart>
                </b-col>
            </b-row>
        </b-container>
    </div>
</template>

<script>
module.exports = {
    name: 'room',

    /** Load external component files
     *  Make sure there is no leading / in the name
     *  To load from the common folder use like: 'common/component-name.vue' */
    components: {
        'highchart': httpVueLoader('components/HighCharts.vue'),
    }, // --- End of components --- //
    
    data() {
        return {
            componentKey: 0,
        };
    },
    methods: {
        forceRerender() {
            this.componentKey += 1
        },
    },
    computed: {
        hasRooms() {
            return this.$store.getters['rooms/nRooms'] > 0;
        },
        roomName() {
            return this.$store.getters['rooms/getRoomById'](this.$route.params.roomId);
        },
        deviceList() {
            return this.$store.getters['rooms/getDevicesinRoom'](this.$route.params.roomId);
        },
    },
    watch: {
        '$route.params.roomId' () {
            this.forceRerender()
        }
    },
    filters: {
        capitalize: function (value) {
            if (!value) return ''
            value = value.toString()
            return value.charAt(0).toUpperCase() + value.slice(1)
        },
        tonumber: function (value){
            if (!value) return ''
            return parseFloat(value)
        }
    },
}
</script>

и датчик. vue

<template>
    <b-card no-body class="bg-secondary text-light">
        <b-card-body class="bg-secondary m-0 pt-0 pb-0">
            <h5 class="pt-2"><slot name="title">Title</slot></h5>
            <div ref="gauge" class="gauge-container"></div>
        </b-card-body>
    </b-card>
</template>

<script>
module.exports = {
    props: {
        'gValue': {type: Number, default: 20},
        'gMin': {type: Number, default: 0},
        'gMax': {type: Number, default: 100},
        'gUnits': {type: String, default: ""},
    },
    data: function () {
        return {
            // Data for chart
            chart: null,
            gaugeOptions: {
                chart: {
                    type: 'solidgauge'
                },
                title: null,
                pane: {
                    size: 200,
                    center: ['50%', '75%'],
                    startAngle: -90,
                    endAngle: 90,
                    background: {
                        innerRadius: '60%',
                        outerRadius: '100%',
                        shape: 'arc'
                    }
                },
                tooltip: {
                    enabled: false
                },
                // the value axis
                yAxis: {
                    stops: [
                        [0.1, '#55BF3B'], // green
                        [0.5, '#DDDF0D'], // yellow
                        [0.9, '#DF5353'] // red
                    ],
                    lineWidth: 0,
                    tickWidth: 0,
                    minorTickInterval: null,
                    tickAmount: 0,
                    title: {
                        y: -70
                    },
                    labels: {
                        y: 16
                    },
                    min: this.gMin,
                    max: this.gMax,
                    title: null,
                },
                plotOptions: {
                    solidgauge: {
                        dataLabels: {
                            y: 5,
                            borderWidth: 0,
                            useHTML: true
                        }
                    }
                },
                credits: {
                    enabled: false
                },
                series: [{
                    data: [this.gValue],
                    dataLabels: {
                    format:
                        '<div style="text-align:center">' +
                        '<span style="color:#FFF; font-size:16px">{y} ' + this.gUnits + '</span>' +
                        '</div>'
                    },
                }],
            }
        }
    },
    mounted: function () {
        Highcharts.setOptions(
            {
                chart: {
                    style: {
                        fontFamily: 'roboto',
                    },
                    backgroundColor:'#6C757D',
                }
            }
        )
        this.chart = Highcharts.chart(
            this.$refs['gauge'], 
            this.gaugeOptions
        )
    },
    watch: {
        gValue: function (val) {
            this.chart.series[0].points[0].update(val)
        },
    }
}
</script>

<style scoped>
.gauge-container {
    max-width: 250px;
    height: 180px;
}
</style>
...