解决Vue异步请求中this为undefined以及mounted中获取不到data的数据的问题

解决Vue异步请求中this为undefined以及mounted中获取不到data的数据的问题

起因

使用Nuxt做项目要实现视频点播功能,视频存在阿里云,整合了一个阿里云播放器,在created中使用封装的异步请求获取视频的vid和播放凭证,但是发现后端接口提示获取视频id失败。

image-20220723122110528

<template>
  <div>
    <!-- 阿里云视频播放器样式 -->
    <link
      rel="stylesheet"
      href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css"
    />
    <!-- 阿里云视频播放器脚本 -->
    <script
      charset="utf-8"
      type="text/javascript"
      src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"
    />

    <!-- 定义播放器dom -->
    <div id="J_prismPlayer" class="prism-player" />
  </div>
</template>
<script>
import vodApi from "@/api/vod";

export default {
  layout: "video", //应用video布局
  data() {
    return {
      vid: "",
      playAuth: "",
    };
  },
  created() {
    this.init()
  },
  methods: {
    init() {
      vodApi.getPlayAuth(this.$route.params.id).then((response) => {
        this.vid = this.$route.query.courseId;
        this.playAuth = response.data.data.playAuth;
      });
    },
    createPlayer() {
      new Aliplayer(
        {
          id: "J_prismPlayer",
          vid: this.vid, // 视频id
          playauth: this.playAuth, // 播放凭证
          encryptType: "1", // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
          width: "100%",
          height: "500px",
          // 以下可选设置
          cover: "", // 封面
          qualitySort: "asc", // 清晰度排序

          mediaType: "video", // 返回音频还是视频
          autoplay: false, // 自动播放
          isLive: false, // 直播
          rePlay: false, // 循环播放
          preload: true,
          controlBarVisibility: "hover", // 控制条的显示方式:鼠标悬停
          useH5Prism: true, // 播放器类型:html5
        },
        function (player) {
          console.log("播放器创建成功");
        }
      );
    },
  },
  mounted(){
    //页面渲染之后  created
    this.createPlayer()
  },
};
</script>

排查

​ 对后端接口进行了DEBUG,发现获取到的id为undefined

image-20220723122358977

​ 我就纳闷了这是什么鬼情况。对前端进行DEBUG,发现赋值后的视频id和播放凭证仍是空。

image-20220723123253207

image-20220723123344600

​ 看到这,我怀疑是this的锅,将视频id的赋值放到异步请求外,发现输出了undefined,离谱…

image-20220723125120025

image-20220723125746050

​ 这说明路由没有这个值,对这个方法进行一下DEBUG。

image-20220723125211928

​ 可以发现,路由中果然没有这个值…

image-20220723125955601

​ 我记得还有一种方式传递,是在路径后加?参数名=xxx,并用this.$route.query.xxx得到它的值,说干就干!

image-20220723130308238

image-20220723130708999

​ 进行DEBUG,成功获取到了视频id!

image-20220723130753381

​ 那么接下来的问题就只剩下,异步请求中如何给播放凭证赋值了…尝试在外头用变量保存this试试…

​ 成功保存!

image-20220723131152950

​ 但是我发现DEBUG的时候,并不执行then里面的语句!…

​ 经过百度,发现mounted中读取数据的时候,以及console.log输出的时候,有可能created的异步请求还没有返回数据,自然是无法读取和输出的。 也 就 是 c r e a t e d 里 的 数 据 还 没 获 取 到 , m o u n t e d 就 开 始 了 渲 染 视 图 的 工 作 , 且 m o u n t e d 只 会 调 用 一 次 \color{red}{也就是created里的数据还没获取到,mounted就开始了渲染视图的工作,且mounted只会调用一次} createdmounted,mounted。接下来,DEBUG一波,返现直接跳过了then,去执行mounted了,后面才执行的then

<template>
  <div>
    <!-- 阿里云视频播放器样式 -->
    <link
      rel="stylesheet"
      href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css"
    />
    <!-- 阿里云视频播放器脚本 -->
    <script
      charset="utf-8"
      type="text/javascript"
      src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"
    />

    <!-- 定义播放器dom -->
    <div id="J_prismPlayer" class="prism-player" />
  </div>
</template>
<script>
import vodApi from "@/api/vod";

export default {
  layout: "video", //应用video布局
  data() {
    return {
      vid: "",
      playAuth: "1",
    };
  },
  created() {
    console.log("执行了created");
    this.init();
    console.log(this.vid);
    console.log(this.playAuth);
    console.log("执行了created");
  },
  methods: {
    init() {
      this.vid = this.$route.query.vid;
      var that = this;
      vodApi
        .getPlayAuth(this.$route.query.vid)
        .then((response) => {
          console.log("执行了then");
          console.log(response.data);
        })
        .catch((response) => {
          console.log("执行了catch:" + response);
        });
    },
    createPlayer() {
      console.log("执行了mounted");
      new Aliplayer(
        {
          id: "J_prismPlayer",
          vid: this.vid, // 视频id
          playauth: this.playAuth, // 播放凭证
          encryptType: "1", // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
          width: "100%",
          height: "500px",
          // 以下可选设置
          cover: "", // 封面
          qualitySort: "asc", // 清晰度排序

          mediaType: "video", // 返回音频还是视频
          autoplay: false, // 自动播放
          isLive: false, // 直播
          rePlay: false, // 循环播放
          preload: true,
          controlBarVisibility: "hover", // 控制条的显示方式:鼠标悬停
          useH5Prism: true, // 播放器类型:html5
        },
        function (player) {
          console.log("播放器创建成功");
        }
      );
    },
  },
  mounted(){
    this.createPlayer()
  },
};
</script>

image-20220723140501285

那 就 为 m o u n t e d 设 置 一 个 定 时 器 , c r e a t e d 获 取 数 据 的 速 度 是 很 快 的 , 让 m o u n t e d 停 那 么 一 丢 丢 时 间 \color{red}{那就为mounted设置一个定时器,created获取数据的速度是很快的,让mounted停那么一丢丢时间} mountedcreatedmounted

mounted: function () {
    setTimeout(() => {
     //填入要执行的方法
    }, 1000);
  }
mounted: function () {
    //定时器,进行延迟,等待异步请求数据
    setTimeout(() => {
      //填入要执行的方法
      this.createPlayer();
    }, 1000);
  }

完美!

image-20220723140926921

image-20220723141058134

<template>
  <div>
    <!-- 阿里云视频播放器样式 -->
    <link
      rel="stylesheet"
      href="https://g.alicdn.com/de/prismplayer/2.8.1/skins/default/aliplayer-min.css"
    />
    <!-- 阿里云视频播放器脚本 -->
    <script
      charset="utf-8"
      type="text/javascript"
      src="https://g.alicdn.com/de/prismplayer/2.8.1/aliplayer-min.js"
    />

    <!-- 定义播放器dom -->
    <div id="J_prismPlayer" class="prism-player" />
  </div>
</template>
<script>
import vodApi from "@/api/vod";

export default {
  layout: "video", //应用video布局
  data() {
    return {
      vid: "",
      playAuth: "",
    };
  },
  created() {
    console.log("执行了created");
    this.init();
    console.log(this.vid);
    console.log(this.playAuth);
    console.log("执行了created");
  },
  methods: {
    init() {
      this.vid = this.$route.query.vid;
      var that = this;
      vodApi
        .getPlayAuth(this.$route.query.vid)
        .then((response) => {
          console.log("执行了then");
          that.playAuth = response.data.data.playAuth
        })
        .catch((response) => {
          console.log("执行了catch:" + response);
        });
    },
    createPlayer() {
      console.log("执行了mounted");
      new Aliplayer(
        {
          id: "J_prismPlayer",
          vid: this.vid, // 视频id
          playauth: this.playAuth, // 播放凭证
          encryptType: "1", // 如果播放加密视频,则需设置encryptType=1,非加密视频无需设置此项
          width: "100%",
          height: "500px",
          // 以下可选设置
          cover: "", // 封面
          qualitySort: "asc", // 清晰度排序

          mediaType: "video", // 返回音频还是视频
          autoplay: false, // 自动播放
          isLive: false, // 直播
          rePlay: false, // 循环播放
          preload: true,
          controlBarVisibility: "hover", // 控制条的显示方式:鼠标悬停
          useH5Prism: true, // 播放器类型:html5
        },
        function (player) {
          console.log("播放器创建成功");
        }
      );
    },
  },
  mounted:function(){
    setTimeout(() => {
        this.createPlayer()
    }, 1000);
  },
};
</script>

总结

  1. 获取路由参数的两种方式
    1. this.$route.params.id 用于获取如下形式的参数 路径/id
    2. this.$route.query.xxx 用于获取如下形式的参数 路径?xxx=…
  2. 注意在异步请求中的this不是VueComponent
  3. 注意data中的值由created中的异步请求获取并赋值的,mounted中要进行引用的话,可能异步请求中还未返回结果就被引用了。

推荐

具体详细的使用可以去官方查看

Nuxt.js 扩展了 Vue.js,增加了一个叫 asyncData 的方法,使得我们可以在设置组件的数据之前能异步获取或处理数据。

asyncData 方法

asyncData方法会在组件(限于页面组件)每次加载之前被调用。它可以在服务端或路由更新之前被调用。在这个方法被调用的时候,第一个参数被设定为当前页面的上下文对象,你可以利用 asyncData方法来获取数据, N u x t . j s 会 将 a s y n c D a t a 返 回 的 数 据 融 合 组 件 d a t a 方 法 返 回 的 数 据 一 并 返 回 给 当 前 组 件 \color{red}{Nuxt.js 会将asyncData返回的数据融合组件data方法返回的数据一并返回给当前组件} Nuxt.jsasyncDatadata

注意:由于asyncData方法是在组件 初始化 前被调用的,所以在方法内是没有办法通过 this 来引用组件的实例对象。

​ Nuxt.js 提供了几种不同的方法来使用 asyncData 方法,返回一个 Promise, nuxt.js 会等待该Promise被解析之后才会设置组件的数据,从而渲染组件.

Axios异步请求返回的就是一个Promise,所以用这一种方式就好。

    export default {
      asyncData({ params }) {
        return axios.get(`https://my-api/posts/${params.id}`).then(res => {
          return { title: res.data.title }
        })
      }
    }

asyncData({ params, error }) {
       return vod.getPlayAuth(params.vid)
        .then(response => {
            return { 
                playAuth: response.data.data.playAuth,
                vid: params.vid
            }
        })
}
  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 Vue.js ,created 钩子函数在实例创建之后立即调用。这意味着在 created 钩子函数进行的数据请求可能还没有完成。mounted 钩子函数在挂载完成之后调用,此时已经渲染完成,因此如果在 mounted 访问数据请求的结果,可能会得到 "undefined" 的值。 为了解决这个问题,你可以在数据请求完成之后再调用 mounted 钩子函数,或者将数据请求的代码放在 mounted 钩子函数进行。 例如,你可以使用 Promise.then 方法来等待数据请求完成: ``` created() { this.fetchData().then(() => { // 数据请求完成 }); }, mounted() { // 数据请求已经完成,可以访问数据了 }, methods: { fetchData() { return axios.get('/api/data').then((response) => { this.data = response.data; }); } } ``` 或者你也可以将数据请求的代码放在 mounted 钩子函数: ``` mounted() { this.fetchData(); }, methods: { fetchData() { axios.get('/api/data').then((response) => { this.data = response.data; }); } } ``` ### 回答2: 在Vue,createdmounted是两个生命周期钩子函数。created在组件实例被创建之后立即调用,此时组件的DOM还未被挂载,而mounted在组件的DOM被挂载后调用。如果在created钩子请求数据,并在mounted使用这些数据,有可能会出现数据undefined的情况。 这是因为在created钩子请求数据时,请求的过程是异步的,数据还未返回就已经进入到了mounted钩子。因此,在mounted钩子访问数据时,数据还未被赋值,所以会显示为undefine。 要解决这个问题,可以在created钩子使用Promise或async/await来确保数据已经返回后再进入到mounted钩子。 示例代码如下: created() { this.getData().then(data => { this.myData = data; }); }, methods: { async getData() { // 在这里进行数据请求,返回一个Promise对象 return axios.get('api/data') .then(response => response.data) .catch(error => { console.error(error); return null; }); } }, mounted() { // 此时会正确显示数据 console.log(this.myData); } 通过使用Promise或async/await,可以确保在mounted钩子访问数据时,数据已经被正确赋值,避免了数据undefined的情况。 ### 回答3: 在Vue,createdmounted是组件的两个生命周期钩子函数。 在created钩子函数,组件实例已经创建完成,但是DOM元素还没有渲染出来。所以,在created钩子函数请求的数据,是可以成功获取到的,但是在mounted钩子函数显示的时候可能会出现undefined。 造成这种情况的原因可能是请求数据需要一定的时间来获取,并且在mounted钩子函数可能会更早执行,导致数据还没有获取到。 要解决这个问题,可以使用Vue的异步操作或者Promise对象。例如,可以使用axios库来发送异步请求数据,并且使用Promise对象来保证在获取数据之后再进行显示。 下面是一个示例代码: ```javascript // 在created钩子函数发送异步请求 created() { axios.get('example.com/api/data') .then(response => { // 获取数据后赋值给组件的data属性 this.data = response.data; }) .catch(error => { console.log(error); }); }, // 在mounted钩子函数显示数据 mounted() { // 使用Vue的$nextTick方法来保证数据已经渲染完毕 this.$nextTick(() => { console.log(this.data); // 这里的this.data应该是有值的 }); } ``` 通过使用异步操作和Promise对象,可以确保在mounted钩子函数获取到的数据不会是undefined

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值