Vue生命周期与Firebase:为何出现“TypeError: Cannot read property 'url' of null”?
这个报错的根源很明确:组件第一次渲染的时候,你的photo变量还是初始的null,模板里直接访问photo.url就会触发类型错误。Vue的渲染流程是在mounted钩子之前执行的,哪怕你在mounted里写了异步获取数据的逻辑,初始渲染的那一刻photo还没被赋值,所以必然会报错。
下面给你几个实用的解决办法,选适合你项目的就行:
方法1:初始化photo为空对象
把data里的photo从null改成空对象,这样初始渲染时访问photo.url只会得到undefined,不会触发报错,同时v-if="photo.url"也能正常判断(undefined属于假值,不会渲染img):
data() { return { photo: {}, // 替换原来的null anno: {} } }
方法2:使用可选链操作符(ES2020+)
如果不想修改初始值,可以在模板里用ES6的可选链?.来安全访问属性,当photo为null或undefined时,会直接返回undefined,不会继续访问后面的属性:
<img :src="photo?.url" :id="photo?.filename" :alt="photo?.title" v-if="photo?.url" />
这个方法很简洁,不过要确保你的项目支持ES2020语法(现在绝大多数Vue项目都没问题)。
方法3:给img加外层条件判断
把img标签包裹在一个判断photo存在的容器里,确保只有当photo有值的时候才尝试渲染img:
<template> <div v-if="photo"> <img :src="photo.url" :id="photo.filename" :alt="photo.title" v-if="photo.url" /> </div> </template>
这样初始渲染时因为photo是null,整个外层div都不会渲染,自然不会触发属性访问错误。
额外优化:监听photo变化初始化Annotorious
另外提个小建议,你在mounted里用await获取数据后初始化Annotorious,虽然逻辑没问题,但如果异步请求延迟比较高,可能还是会有风险。可以改用watch监听photo的变化,确保只有当photo.filename存在时才初始化:
watch: { photo(newPhoto) { if (newPhoto?.filename) { this.anno = new Annotorious({ image: newPhoto.filename }) } } }
这样不管数据什么时候加载完成,只要photo被赋值,就能自动初始化Annotorious,比在mounted里等待更可靠。
内容的提问来源于stack exchange,提问作者redshift

