英文:
Displaying an image saved in a variable in Vue 3
问题
以下是翻译的内容:
我有一个基于Vue 3和Django REST的应用程序。该应用程序显示数据库中的歌曲,并且应该显示歌曲的专辑封面图片。我将封面图片存储在服务器的文件系统中,并可以通过Django访问它们,当API请求到来时,通过FileResponse将它们传递给前端。我在前端接收到这些图片并将它们保存到变量中。然而,当我想要在<img>标签中显示这些图片时,它看起来像这样:
[![当前的显示效果](https://i.stack.imgur.com/1BsEE.png)](https://i.stack.imgur.com/1BsEE.png)
我希望灰色框显示专辑封面艺术品而不是这样。奇怪的是,我的浏览器从API接收到这些图片并正确显示它们:
[![浏览器接收到的内容](https://i.stack.imgur.com/yHRhm.png)](https://i.stack.imgur.com/yHRhm.png)
(我知道歌曲的封面艺术品不正确,但这不是重点)。
API(Django REST):
```python
@api_view(['GET'])
def img_api(request):
# ...(此处是API代码,未进行翻译)
Vue 3组件 SongBox.vue
使用了Tailwind CSS:
<script setup>
</script>
<script>
import axios from "axios";
export default {
name: "SongBox",
props: ['song'],
methods: {
async getImage() {
this.image = await axios.get(this.$hostname + 'img?id=' + this.song.pk)
}
},
created() {
this.getImage()
},
data() {
return {
image: []
}
}
}
</script>
<template>
<div v-if="song" class="flex w-1/3 flex-wrap px-3 -mb-12">
<div class="w-full px-2">
<div class="relative overflow-hidden bg-cover bg-no-repeat" style="background-position: 50%">
<img class="block w-full h-full rounded-lg object-cover object-center" :src="this.image"/>
<div class="absolute rounded-lg bottom-0 right-0 left-0 top-0 h-full w-full bg-black bg-fixed opacity-50 overflow-hidden"></div>
</div>
<div class="relative inset-y-[-20%] bottom-5 hidden py-5 text-center text-white md:block">
<p class="text-xl">{{ song.fields.song_name }}</p>
<p class="text-base">{{ song.fields.song_artist }}</p>
</div>
</div>
</div>
</template>
看起来前端在API响应返回之前就渲染了SongBox组件,但是Vue也没有更新渲染的SongBox。我需要做什么改变,以便Vue正确渲染SongBox?
此外,我不确定是否在这里正确处理图片,因为我没有找到其他人以这种方式处理图片。歌曲的路径肯定是正确的,因为浏览器接收到了正确的图片。
我已经尝试将图片通过props从父组件传递到SongBox,但也没有成功。我期望接收到的图片在SongBox中渲染,而不是显示灰色背景。
<details>
<summary>英文:</summary>
I have an application based on Vue 3 and Django REST. The application displays songs in a database, and is also supposed to display the cover images of the songs' respective albums. I have the cover images in the file system of the server and can access them via Django, and hand them out via a FileResponse when an API request comes in. I receive them in the Frontend and save the image to a variable. However, when I want to then display the image in an <img> tag, it just looks like this:
[![What it currently looks like](https://i.stack.imgur.com/1BsEE.png)](https://i.stack.imgur.com/1BsEE.png)
I want the gray boxes to display the album cover art instead. What's weird is that my browser receives the images from the API and displays them correctly:
[![What the Browser gets](https://i.stack.imgur.com/yHRhm.png)](https://i.stack.imgur.com/yHRhm.png)
(I know that the cover art is incorrect for the songs, that's not the point here).
The API (Django REST):
@api_view(['GET'])
def img_api(request):
if request.method == "GET":
if request.GET['id'] == 'undefined':
return HttpResponse(
HttpResponse(serializers.serialize('json', Song.objects.none()), content_type='application/json'))
if 'id' in request.GET:
query = request.GET['id']
song = Song.objects.filter(song_id=query).first()
try:
img = open(os.path.join(SONG_PATH, song.song_image_file), 'rb')
if song.song_image_file.endswith(".png"):
return FileResponse(img, content_type='image/png')
return FileResponse(img, content_type='image/jpeg') # file is closed automatically
except FileNotFoundError:
return HttpResponse(HttpResponse(serializers.serialize('json', Song.objects.none()), content_type='application/json'))
except PermissionError:
return HttpResponse(HttpResponse(serializers.serialize('json', Song.objects.none()), content_type='application/json'))
return HttpResponse(HttpResponse(serializers.serialize('json', Song.objects.none()), content_type='application/json'))
return HttpResponse(HttpResponse(serializers.serialize('json', Song.objects.none()), content_type='application/json'))
The Vue 3 component `SongBox.vue` with Tailwindcss:
<script setup>
</script>
<script>
import axios from "axios";
export default {
name: "SongBox",
props: ['song'],
methods: {
async getImage() {
this.image = await axios.get(this.$hostname + 'img?id=' + this.song.pk)
}
},
created() {
this.getImage()
},
data() {
return {
image: []
}
}
}
</script>
<template>
<div v-if="song" class="flex w-1/3 flex-wrap px-3 -mb-12">
<div class="w-full px-2">
<div class="relative overflow-hidden bg-cover bg-no-repeat" style="background-position: 50%">
<img class="block w-full h-full rounded-lg object-cover object-center" :src="this.image"/>
<div class="absolute rounded-lg bottom-0 right-0 left-0 top-0 h-full w-full bg-black bg-fixed opacity-50 overflow-hidden"></div>
</div>
<div class="relative inset-y-[-20%] bottom-5 hidden py-5 text-center text-white md:block">
<p class="text-xl">{{ song.fields.song_name }}</p>
<p class="text-base">{{ song.fields.song_artist }}</p>
</div>
</div>
</div>
</template>
It seems a bit like the frontend renders the SongBox component before the request for the image is answered, but then Vue also doesn't update the rendered SongBox. What do I need to change s.t. Vue renders the SongBoxes correctly?
Also, I'm not sure if I'm handling the images correctly here, since I have found no one else doing it this way. The paths to the songs are definately correct, as seen by that the browser receives the correct image.
I have tried already to pass the images via props from parent components down to the SongBox, but that also didn't work. I'm expecting the received images to render in the SongBox instead of the gray background.
</details>
# 答案1
**得分**: 0
你的网络选项卡有点误导性。实际上,GET 请求获取的是原始图像数据。网络选项卡只是基于数据生成预览。直接将这些数据分配给 img 元素的 `src` 属性将不起作用。`src` 只接受 URL。你需要将你的响应进行转换。
```js
async getImage() {
const response = await axios.get(
this.$hostname + "img?id=" + this.song.pk,
{ responseType: "blob" }
);
this.image = URL.createObjectURL(response.data);
},
英文:
Your network tab is a bit misleading. What the GET actually retrieves is the raw image data. The network tab is just generating a preview based on the data. Assigning this data directly to the src
attribute of an img element will not work. src
only accepts URLs. You need to convert your response
async getImage() {
const response = await axios.get(
this.$hostname + "img?id=" + this.song.pk,
{ responseType: "blob" }
);
this.image = URL.createObjectURL(response.data);
},
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论