Javascript Vue.js 无法使用 querySelector 找到元素
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44258869/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Vue.js can't find element using querySelector
提问by Nick Maddren
I am trying to create a chat style form. So a user inputs their data and then uses the button within my template with the class of continue-btn.
我正在尝试创建一个聊天风格的表单。因此,用户输入他们的数据,然后使用我的模板中的按钮与continue-btn.
As you can see when the continue-btnis pressed it uses the nextStepmethod which adds 1 to the counterdata property.
正如您所看到的,当continue-btn按下 时,它使用nextStep将 1 添加到counter数据属性的方法。
Within my template I then use v-if="counter >= 1"to display the next section of the chat dialog and input field.
在我的模板中,我然后使用v-if="counter >= 1"来显示聊天对话框和输入字段的下一部分。
I am then trying to use scrollTop to automatically scroll the page to the new section with the id of #conversation__tram-1. I originally tried running this block of code just after the counterhad been given a value of 1:
然后我尝试使用 scrollTop 自动将页面滚动到 id 为 的新部分#conversation__tram-1。我最初尝试counter在给定值 1后运行此代码块:
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
This didn't work though because I'm guessing the #conversation__tram-1element hadn't been added to the DOM yet.
但这不起作用,因为我猜该#conversation__tram-1元素尚未添加到 DOM 中。
So for the sake of testing I tried wrapping it in a timeout function:
所以为了测试,我尝试将它包装在一个超时函数中:
setTimeout(function(){
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
However I am left with this error when trying this:
但是,在尝试此操作时,我遇到了此错误:
Uncaught TypeError: Cannot read property 'querySelector' of undefined
Here is my whole single vue file:
这是我的整个单一 vue 文件:
<template>
<div id="conversation-app">
<!-- <div v-for="item in items">
{{ item.text }}
</div> -->
<div class="conversation__track">
<div id="conversation__tram-0">
<div class="conversation__item agent">
<img src="/assets/cdn.annuityadvicecentre.dev/images/theme-f/michael-chat-agent.jpg" class="conversation__item-prof-img" alt="Michael Chat Agent" />
<div class="conversation__item-content">
<p>
Hello my name is {{ agent }}, we'll compare the whole annuity market to bring you back the best annuity rates from the top providers for you. Let's get started, what's your name?
</p>
</div>
</div>
<div class="conversation__item customer" id="title-fullname">
<div class="conversation__item-content">
<p>
Hi {{ agent }}, my name is...
</p>
<div class="row">
<div class="col-4">
<select id="title" class="field-title" name="payload[title]"><option value="mr">Mr</option><option value="mrs">Mrs</option><option value="miss">Miss</option><option value="ms">Ms</option></select>
</div>
<div class="col-8">
<input v-model="customerName" id="full_name" class="field-full_name" name="payload[full_name]" type="text">
</div>
</div>
</div>
</div>
</div>
<transition name="fade">
<div id="conversation__tram-1" v-if="counter >= 1">
<div class="conversation__item agent">
<img src="/assets/cdn.annuityadvicecentre.dev/images/theme-f/michael-chat-agent.jpg" class="conversation__item-prof-img" alt="Michael Chat Agent" />
<div class="conversation__item-content">
<p>
Thanks {{ firstName }}, nice to meet you. To process your instant quote please can I have your Pension Value?
</p>
</div>
</div>
<div class="conversation__item customer">
<div class="conversation__item-content">
<p>
Sure, my pension value is...
</p>
<input id="pension_value" class="field-pension_value" placeholder="£" pattern="\d*" name="payload[pension_value]" type="number">
<div class="error-wrap error_pension_value is-hidden" data-format="<div class="error-text">:message</div>"></div>
</div>
</div>
</div>
</transition>
<div id="conversation__buttons">
<button type="button" class="continue-btn"
v-on:click="nextStep"
>Continue <i class="fa fa-chevron-right" aria-hidden="true"></i></button>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'conversation-app',
data () {
return {
agent: 'Brick',
counter: 0,
customerName: '',
}
},
methods: {
nextStep: function() {
this.counter += 1;
setTimeout(function(){
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
},
},
computed: {
firstName() {
return this.customerName.split(' ')[0];
}
}
}
</script>
Any idea why this isn't working? Thanks.
知道为什么这不起作用吗?谢谢。
回答by varbrad
This is a good time to use arrow functions, as they preserve the context of this.
这是使用箭头函数的好时机,因为它们保留了this.
nextStep: function() {
this.counter += 1;
setTimeout(() => {
const container = this.$el.querySelector("#conversation__tram-" + this.counter);
container.scrollTop = container.scrollHeight;
}, 3000);
Altenatively, instead of the timeout you can use Vue.nextTickwhich is a more technically-correct way of doing this.
或者,您可以使用Vue.nextTick在技术上更正确的方法来代替超时。
nextStep: function () {
this.counter += 1
this.$nextTick(() => { ... })

