Как убедиться, что DOM-элементы, которыми я хочу манипулировать, загружены, прежде чем пытаться что-либо делать с ними в Vue.js? - PullRequest
0 голосов
/ 15 апреля 2019

Я боролся с этой проблемой со вчерашнего дня, и я в своем уме.В настоящее время у меня есть метод в файле vue, который делает это:

methods: {
    showSlides(n) {
        let slides = document.getElementsByClassName("mySlides");

        slides[0].style.display = "block";
    }
},
mounted(){
    this.showSlides();
}

Он находит все элементы с классом "mySlides", сохраняет их в переменной, а затем пытается изменить стиль первого элемента.,Эта функция вызывается, когда компонент монтируется ().

Теперь проблема в том, что я получаю сообщение об ошибке "TypeError: Cannot read property 'style' of undefined".Оказывается, что во время выполнения этой функции эти элементы DOM не определены.Я понял это, добавив событие @click='showSlide()' к кнопке.Когда я нажимаю кнопку, функция запускается успешно, однако, когда она монтируется (), она не работает.

Код также успешно работает в простом HTML-файле, где скрипт находится внизу страницы.,Это то, что заставляет меня верить, что происходит что-то подозрительное.

Полный код:

<template>
    <div class="wrapper">
        <div class="sight-container">
            <p class='sight-name'>{{ sight.name }}</p>
            <p>{{ sight.formatted_address }}</p>
            <p>{{ sight.formatted_phone_number }}</p>
            <p>{{ sight.international_phone_number }}</p>
            <p>{{ sight.website }}</p>


            <div class="photos-container">
                <div v-for='(image, index) in sightImages' class="mySlides">
                    <div class="numbertext">{{ index + 1 }} / {{ sightImages.length }}</div>
                    <img class='sight-photos'  :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + '&key='">
                </div>

                <a class="prev" @click='plusSlides(-1)'>❮</a>
                <a class="next" @click='plusSlides(1)'>❯</a>

                <div class="caption-container">
                    <p id="caption"></p>
                </div>

                <div class="row">
                    <div v-for='(image, index) in sightImages' class="column">
                      <img class="demo cursor" :src="'https://maps.googleapis.com/maps/api/place/photo?maxwidth=1920&photoreference=' + image.photo_reference + '&key='" style="width:100%" @click="currentSlide(1)">
                    </div>
                </div>
            </div>


        </div>
    </div>
</template>

<script>
    import axios from 'axios'

    export default {
        data(){
            return {
                placeId: this.$route.params.placeid,
                sight: "",
                sightImages: [],
                slideIndex: 1
            }
        },
        methods: {
            showSlides(n) {
                let i;
                let slides = document.getElementsByClassName("mySlides");
                let dots = document.getElementsByClassName("demo");
                let captionText = document.getElementById("caption");

                if (n > slides.length) {
                    this.slideIndex = 1
                }
                if (n < 1) {
                    this.slideIndex = slides.length
                }
                for (i = 0; i < slides.length; i++) {
                    slides[i].style.display = "none";
                }
                for (i = 0; i < dots.length; i++) {
                    dots[i].className = dots[i].className.replace(" active", "");
                }

                slides[this.slideIndex-1].style.display = "block";
                dots[this.slideIndex-1].className += " active";
                captionText.innerHTML = dots[this.slideIndex-1].alt;
            },
            plusSlides(n) {
                this.showSlides(this.slideIndex += n);
            },
            currentSlide(n) {
                this.showSlides(this.slideIndex = n);
            }
        },
        mounted(){
            axios.get('/getSight/' + this.placeId)
            .then(response => {
                this.sight = response.data.result.result
                this.sightImages = response.data.result.result.photos
            }).catch((error) => console.log(error));

            this.showSlides(this.slideIndex);
        }
    }
</script>

1 Ответ

1 голос
/ 15 апреля 2019

Это потому, что вы используете его неправильно.

Обычно mounted называются после рендеринга DOM компонента, на данный момент this.$el компонента готов к использованию.

Однако в mounted вы вызываете асинхронную операцию, которая обновляет data (и более позднюю DOM) после завершения, но вы пытаетесь использовать ее результат до это случилось.

Это должно быть так:

mounted() {
  axios.get('/getSight/' + this.placeId)
       .then(response => {
         this.sight = response.data.result.result;
         this.sightImages = response.data.result.result.photos;
         this.$nextTick(() => {
           this.showSlides(this.slideIndex);
         });
       }).catch((error) => console.log(error));
}

Небольшая подсказка: вместо использования el.className += ... и el.className.replace(...) вы можете использовать el.classList.add(...) и el.classList.remove(...).

Документы: Element.classList

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...