【问题标题】:VueJS Showing and Hiding MessagesVueJS 显示和隐藏消息
【发布时间】:2018-07-06 23:22:09
【问题描述】:

我创建了一个基本的 CLI 结构环境。我有一个显示消息/警报的组件,即:登录失败等......

由于这个组件将在整个应用程序中重复使用,我想将它导入到根 App.vue 文件并在那里进行处理。它正在工作……有点。

它可以很好地显示消息/警报,但我希望它在设定的几秒钟后隐藏/消失/蒸发。或者单击一个按钮,它会隐藏/消失/蒸发 - 我在下面的警报组件示例中显示了这一点。在某个预定义的时间后我根本无法隐藏,并且单击和隐藏有效,但取消隐藏也会产生问题。我在 App.vue 文件中使用 setTimeout 方法在 5 秒后自动隐藏,并且什么都不会发生我认为该方法在 Alert 模块被导入之前触发......我想。

到目前为止,这是我的代码......看起来很简单的任务,但在过去的几个小时里它一直在破坏我的大脑:

应用组件:

<template>
   <div id="app">
         <alert v-if="alert" v-bind:message="alert"></alert>
         <router-view></router-view>
   </div>
</template>

<script>
   import Alert from './components/frontend/alert'
   export default {
      name: 'App',
      data() {
         return {
            alert: ''
         }
      },
      updated: function() {
         if(this.$route.query.alert){
            this.alert = this.$route.query.alert;
            // This was for me to test the click even - PREFER AUTO HIDE AFTER A FEW SECONDS
           // This returns an error on form submit - see error below
            document.querySelector('.alert').style.display = 'block';
         }
      },
      components: {
         'alert': Alert
      }
   }
</script>

这是警报组件:

<template>
   <div class="alert">
      <p class="text-brand m-20">
         <button class="btn btn-small btn-brand" v-on:click="hideAlert()">Close</button>
         {{message}}
      </p>
   </div>
</template>

<script>
   export default {
      name: 'alert',
      props: ['message'],
      data () {
         return {

         }
      },
      methods: {
         hideAlert() {
            // This was for me to test the click even - PREFER AUTO HIDE AFTER A FEW SECONDS
            document.querySelector('.alert').style.display = 'none';
         }
      }
   }
</script>

使用点击隐藏时出错 - 来自 App.vue 文件:

[Vue warn]: Error in updated hook: "TypeError: Cannot read property 'style' of null"

found in

---> <App> at src/App.vue
       <Root>

我怎样才能让 Alert 组件在 App 根组件之后隐藏,比如说 5 秒?这将是我的首选方法,否则我该怎么做才能让点击和隐藏工作?

非常感谢!

【问题讨论】:

    标签: javascript vue.js settimeout


    【解决方案1】:
    document.querySelector('.alert').style.display = 'none';
    

    不要这样做。你不应该在方法中操作 DOM,只能在指令和生命周期钩子等规定的地方操作。在它们之外,Vue 期望控制 DOM。

    您可以使用您的视图模型控制inline styles。你也可以conditional rendering with v-if。 Vue 方法是让您操作模型并让 Vue 使 DOM 反映它。

    我已将您的代码改编为下面的可运行 sn-p。 由于您将 hideAlert 方法放在组件中,因此我将关联的v-if 放在那里。测试是message(道具)是否有值,所以关闭是让父母清除消息的问题。这是使用the .sync modifier 处理的标准通信功能。

    关闭按钮调用hideAlert方法,我还放了一个观察者,这样每当设置新消息时,它会等待5秒并调用hideAlert

    Alert 组件是独立的;它的prop如何获取它的值并不重要,例如父组件是否从路由器组件中获取它并不重要,重要的是它是否有值。

    const Alert = {
      template: '#alert-template',
      props: ['message'],
      methods: {
        hideAlert() {
          // Tell the parent to clear the message
          this.$emit('update:message', '');
        }
      },
      watch: {
        message(newValue) {
          // Close after 5 seconds
          if (newValue) {
            setTimeout(this.hideAlert, 5000);
          }
        }
      }
    };
    
    new Vue({
      el: '#app',
      data() {
        return {
          alert: ''
        }
      },
      components: {
        'alert': Alert
      },
      mounted() {
        // If alert has a value, it will display. If not, not.
        setTimeout(() => {
          this.alert = 'Now you have a message';
        }, 500);
      }
    });
    <script src="//unpkg.com/vue@latest/dist/vue.js"></script>
    <div id="app">
      <alert v-bind:message.sync="alert"></alert>
    </div>
    
    <template id="alert-template">
       <div v-if="message" class="alert">
          <p class="text-brand m-20">
             <button class="btn btn-small btn-brand" v-on:click="hideAlert()">Close</button>
             {{message}}
          </p>
       </div>
    </template>

    【讨论】:

    • 罗伊,我应该在上面提到点击事件(提交)发生在另一个组件内,即:登录组件。该组件通过&lt;router-view&gt;&lt;/router-view&gt; 在 App 组件中呈现。这就是我在更新函数中使用 if $route.query 的原因。并且将您的代码集成到我的代码中不起作用...setTimeout 永远不会触发。
    【解决方案2】:

    首先,了解 Vue 和 v-if 指令很重要。 v-if 计算它的表达式,如果计算结果为 true,则 Vue 将在 DOM 中呈现该元素,但如果不是,则该元素不会包含在 DOM 中。

    这会导致您看到的错误消息,因为当没有警报显示时,DOM 中没有匹配 document.querySelector('.alert') 的元素。

    此外,如果您将所有隐藏/显示代码都放在一个组件中会更好。例如,如果您希望它在父组件中,您的hideAlert() 方法应该是:

    methods: {
        hideAlert() {
            this.alert = null
        }
    }
    

    您的警报按钮组件将是:

    <button class="btn btn-small btn-brand" v-on:click="$emit('hide')">Close</button>
    

    而您在父级中拥有&lt;alert&gt; 标记的位置将变为:

    <alert v-if="alert" v-bind:message="alert" @hide="hideAlert"></alert>
    

    【讨论】:

    • David,使用上面的代码,“显示警报”会在哪里发生?这样做对我来说永远不会隐藏,因为我在更新函数内的 if 语句中有 this.displayAlert = true
    • 如果您有v-if="alert",那么您不需要单独的displayAlert 变量。要显示警报,您只需设置this.alert = 'some message'
    【解决方案3】:

    很抱歉打扰了这个帖子,但我认为这是实现这一目标的最佳方式:

    示例:假设我们有以下来自服务器响应的数据

    data() {
      return {
        serverMessages: [],
      }
    },
    methods: {
      onSubmit() {
        this.$axios.$get('/myroute')
      .then(res => {
        this.serverMessages.push(res)
        this.$emit('flush-message')
      })
      .catch(err => {
        this.serverMessages.push(err.data)
        this.$emit('flush-message')
      });
    },
    mounted() {
        let timer
        this.$on('flush-message', message => {
          clearTimeout(timer)
    
          timer = setTimeout(() => {
            this.serverMessages = []
          }, 3000)
        })
    }
    

    这样您可以清除超时,例如,如果您有多条消息,它就不会出现故障。您还可以将类似的代码集成到单独的控制器中。

    【讨论】:

      【解决方案4】:

      您应该使用创建的生命周期将其隐藏在警报组件中,如下所示:

      `

        created: {
      
               setTimeout(() => this.message = [], 1000)
        }
      

      【讨论】:

        猜你喜欢
        • 2016-02-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-09
        • 2020-01-10
        • 1970-01-01
        相关资源
        最近更新 更多