vue3函数如何将axios请求的返回值以字符串的格式返回

问题:

最近尝试做一个后台管理的项目练手,在做菜单栏图标的时候,发现图标不能显示。

技术前提:

vue3,后端返回图片流,前端转为base64然后循环显示

全部代码:

<template>
  <div>
    <template v-for="item in menuList" :key="item.path">
      <!-- 分为两种方式渲染:有子菜单和没有子菜单-->
  <el-sub-menu
  :index="item.path"
  v-if="item.nodeType == 1"
  >
        <template #title>
          <el-icon v-show="item.iconId!=null"><img :src="sendIcon(item.iconInfo)" alt="" class="icon_class"/></el-icon>
          <span>{{ item.name }}</span>
        </template>
        <!-- 有子菜单的继续遍历(递归)-->
  <menuTree :menuList="item.children"></menuTree>
      </el-sub-menu>
      <!-- 没有子菜单-->
  <el-menu-item :index="item.path" v-if="item.nodeType==2">
        <el-icon v-show="item.iconId!=null">
          <img :src="sendIcon(item.iconInfo)" alt="" class="icon_class"/>
        </el-icon>
        <span>{{ item.name }}</span>
      </el-menu-item>
    </template>
  </div>
</template>

<script>
import {getIcon} from '@/api/home/file/index'
import {computed} from 'vue'

export default ({
  name: 'menuTree',
  props: {
    menuList: {
      type: Array
  }
  },
  setup(props) {
   async function sendIcon(fileInfo) {
      // 获取菜单图片路径
  if (fileInfo != null) {
        //获取图片输出流
  let res = await getIcon(fileInfo)
        const base64Image = btoa(
            new Uint8Array(res.data).reduce(
                (data, byte) => data + String.fromCharCode(byte),
                '',
            ),
        );
        return 'data:image/png;base64,' + base64Image
  }
    }
    return {
      sendIcon
  };
  }
})
</script>

关键代码

<el-icon v-show="item.iconId!=null"><img :src="sendIcon(item.iconInfo)" alt="" class="icon_class"/></el-icon>

async function sendIcon(fileInfo) {
   // 获取菜单图片路径
  if (fileInfo != null) {
     //获取图片输出流
  let res = await getIcon(fileInfo)
     const base64Image = btoa(
         new Uint8Array(res.data).reduce(
             (data, byte) => data + String.fromCharCode(byte),
             '',
         ),
     );
     return 'data:image/png;base64,' + base64Image
  }
 }

效果

Vue.js

原因:

图片无法显示,经过仔细琢磨和搜索之后,发现是sendIcon函数的返回值在模板中变成了promise对象,

Vue.js

尝试的办法:
chatgpt说可以通过计算属性computed实现返回字符串,但是我试过后并没有什么用

let sendIcon = computed(() => {
  return async function (fileInfo) {
    // 获取菜单图片路径
  if (fileInfo != null) {
      //获取图片输出流
  let res = await getIcon(fileInfo)
      const base64Image = btoa(
          new Uint8Array(res.data).reduce(
              (data, byte) => data + String.fromCharCode(byte),
              '',
          ),
      );
      return 'data:image/png;base64,' + base64Image
  }
  }
})

我知道可以通过一些其他方法,比如在获取菜单信息的时候,再发起获取图片流文件的时候,手动处理为一个数组,然后在模板中遍历这个独立的数组,有点麻烦,我并不想使用那种方法,我想通过现在这个方式,因为只需要将其转为字符串返回就解决了。

讨论数量: 7

你的 getIcon 函数的逻辑是什么,请求接口吗,

菜单图片不是应该跟着菜单列表项一起出来的吗,为什么会需要前端额外处理?

8个月前 评论
abao_02__ (楼主) 8个月前
zhaojjiang (作者) 8个月前
abao_02__ (楼主) 8个月前
abao_02__ (楼主) 8个月前
zhaojjiang (作者) 8个月前

computed 一般是纯计算处理,不应该有副作用。可以使用 watchEffect 来实现你要的效果。

setup() {
        // 模拟 http 请求
        const mockRequest = (val) => {
            return new Promise(resolve => {
                setTimeout(() => {
                    resolve(`响应 ${val}`)
                }, 3200);
            })
        }
        const getIcon = (fileInfo) => {
            return mockRequest(fileInfo)
        }
        // 假设这是默认的菜单
        const menuList = ref([
            {
                name: '你好', fileInfo: 1,
            },
            {
                name: '你好2', fileInfo: 2
            }
        ])
        const showMenuList = ref([])

        watchEffect(async () => {
            const imgs = menuList.value.map((item) => {
                return getIcon(item.fileInfo);
            });
           // 使用 Promise.all 可以并发同时获取多个图片。
            const imgResponse = await Promise.all(imgs);
            showMenuList.value = imgResponse.map((res, index) => {
                // 每一个res 就是 getIcon 请求的结果,可以在这里转换图片
                return {
                    ...menuList.value[index],
                    iconUrl: `转为了图片${res}`
                }
            })
        })
        return {
            menuList,
            showMenuList
        }
    }
8个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!