说明:本文档的Vue基于vue/cli 4.5.13,vue typescript(集成vue-property-decorator)版本进行问题归类。

  • 直接在子组件template中使用的prop变量,在父组件更新的时候,子组件会同步更新。如果函数中使用了prop变量,需要通过$watch监听prop变量的变化并重新执行函数。
  • template中调用函数可能将导致vue的页面缓存(更新)策略失效。
  • 使用new创建Vue组件实例手动挂载时,在构造函数内传入data,将导致组件内对数据的改动无法触发响应式更新。因此,在手动挂载组件实例时,如果需要修改组件内部的显示值,需要通过获取到的实例直接去访问属性修改,而不是在构造函数内直接传入data,这样会覆盖原有的属性。手动挂载实例时,若没有传入$store和$router,将无法在实例内通过this访问$store和$router。
  • 如果子组件传入的props是从函数返回的值,那么,无论设置key与否,组件都会被刷新。这是由于响应式更新时,都会重新调用函数去获取返回值导致的。虽然这种刷新察觉不到,但是如果子组件内部通过$watch监听了传入的prop属性,那么就会观察到函数的每一次返回值都在发生改变。需要注意的是,子组件虽然会被刷新,但是如果子组件没有监听传入prop的变化并应用新的值,显示依然将会为第一次获取到的值。
  • 子组件可以通过this.$parent去访问父组件实例并获取父组件的实例属性和方法,但是需要注意的是:若需要将属性或方法直接初始化在变量定义时,变量名需要与父组件的属性和方法名保持一致。具体原因未知。
  • 使用vue.extend实例化组件的时候,若不传入$store和$router,组件内部将无法使用Vue Router和VueX。
  • 监听事件导致的同步等待事件陷阱。若监听事件内存在同步等待事件,存在某一全局变量在管理同步等待事件的结果时,监听事件连续被触发,同步等待事件仍可能在等待中,存在某一时刻,全部的同步等待事件完成,这将导致同步等待事件的相关状态错误。示例如下:

// before
  private inSpeakingDisplay() {
    let message: any = null
    this.$watch('status', async (status) => {
      (Message as any).closeAll();
      if (message) message.close();
      const inSpeaking = status.reduce((acc: any[], v: any) => {
        if (v.mediaType === 'audio' && String(v.uid) !== String(this.user.index)) {
          acc.push(v);
        }
        return acc;
      }, []).find((v: any) => (!v.pause));
      if (!inSpeaking) return;
      const httpClient = window.HttpClient;
      const { data } = await httpClient.get(`/user/${ inSpeaking.uid }`)
      message = this.$message({
        type: 'info',
        message: `${ data.organization_info.name } ${ data.name }正在讲话`,
        duration: 0
      });
    })
  }
// after
  private inSpeakingDisplay() {
    const messageQueue: any[] = []
    this.$watch('status', async (status) => {
      const inSpeaking = status.reduce((acc: any[], v: any) => {
        if (v.mediaType === 'audio' && String(v.uid) !== String(this.user.index)) {
          acc.push(v);
        }
        return acc;
      }, []).find((v: any) => (!v.pause));
      if (!inSpeaking) return;
      const httpClient = window.HttpClient;
      const { data } = await httpClient.get(`/user/${ inSpeaking.uid }`)
      messageQueue.forEach((message) => (message.close()));
      messageQueue.splice(0, messageQueue.length);
      const message = this.$message({
        type: 'info',
        message: `${ data.organization_info.name } ${ data.name }正在讲话`,
        duration: 0
      });
      messageQueue.push(message);
    })
  }

  • ref的bug问题,以下代码会导致loginMode为face的时候,ref的avatar被错误的链接到div class="face"上

<template v-if="loginMode === 'password'">
        <div class="user-header" ref="avatar">
          <!--        <img :src="require('@/assets/image/user_default_header.png')"/> -->
        </div>
        <div class="input-item">
          <input type="text" placeholder="手机" v-model="formData.account"/>
        </div>
        <div class="input-item">
          <input type="password" placeholder="密码" v-model="formData.password"/>
          <div style="width: 30px; height: 30px; position: absolute; right: 3px; top: 5px; cursor: pointer"
               @click="login">
            <svg-loader svg-file="login"></svg-loader>
          </div>
        </div>
      </template>
      <template v-if="loginMode === 'face'">
        <div class="face">
          <video ref="local_video" autoplay playsinline muted></video>
        </div>
      </template>