每月进步一点点--202306

1,018 阅读6分钟

31. 如何让一个页面所有的逻辑重新执行一遍?

  1. 给组件加一个动态的key
  2. 其次,跳转页面时加一个时间戳
    <Layout class="basic-layout-main">
      <router-view v-slot="{ Component }">
        <component :is="Component" :key="$route.fullPath" />
      </router-view>
      <BaseWaterMark container=".basic-layout-main" />
    </Layout>
  <script> 
  const onNext = (id: string) => {
    router.push(`/xxx/${id}/edit?timestamp=${Date.now()}`);
  };
  </script>

30. vite+vue3 出现 [Vue warn]: Failed to resolve component XXX 如何解决?

vite+vue3编译时出现不能识别的组件警告时,可以用如下配置解决:

// vue语法支持
import vue from '@vitejs/plugin-vue';

export default ({ command, mode }: ConfigEnv) => {
    plugins: [
      vue({
        template: {
          // 消除控制台wx-open-launch-weapp引起的警告
          compilerOptions: {
            isCustomElement: (tag) => {
              return tag === 'wx-open-launch-weapp';
            },
          },
        },
      }),
    ],
})

29. [Vue warn]: Component inside renders non-element root node that cannot be animated. 是什么意思,如何解决?

这句话的意思是: <Transition>里面的组件没有根元素,无法添加动画效果。只要给component加一个根元素,就可以了。

<template>
  <router-view v-slot="{ Component, route }">
    <div>
      <transition>
        <keep-alive :include="keepAliveList">
          <div :key="route.name">
            <component :is="Component" />
          </div>
        </keep-alive>
      </transition>
    </div>
  </router-view>
</template>

28. v-for循环,key重复的话,会不会造成渲染的内容不断增加?

如下的代码,每次切换tab时,dataClientReport的内容会变化,需要重新渲染dataClientReport列表数据, 因为这里的key取的是item.value,而这个值会重复,最终看到的现象是,在tab切换时,第一轮切换没问题,第二轮切换时,发现重复的记录越来越多,将:key="item.value"修改成唯一键:key="item.name"之后,发现这个问题就解决了。

     <template v-for="(item, index) in dataClientReport" :key="item.value">
          <div class="item" v-if="briefingActive !== 3 || index <= 1">
            <div class="name">{{ item.name }}</div>
            <div class="value">
              {{
                briefingActive === 3 && !isManagerKeep && index === 1
                  ? '--'
                  : item.value
              }}
            </div>
            <div class="supplement" v-if="item.supplement">
              {{ item.supplement }}
            </div>
          </div>
        </template>

27. 为什么有些小问题,别人不提,我们发现不了?

比如说图表纵轴表现以人为单位,却出现小数,不合理我们却习以为常,没有先于业务发现。还是欠缺产品思维。

image.png

如果使用的是ECharts的话,修正方法是:

yAxis: {
  minInterval : 1,
}

26. 为什么设置了style属性,却不生效?

如下vue中的代码,设置的style并不生效,很神奇。后面将style和class的书写顺序调整一下之后,就正常了。在vue的模板中style的渲染规则有点不同于html,html的style必须定义在class属性之后,才能生效。

       <template v-if="state.leftInfo.value">
          <div class="left">
            <div
              style="line-height: 0.84rem; font-size: 0.64rem"
              class="infoValue text-ellipsis"  
            >
              {{ state.leftInfo?.value }}
            </div>
            <div class="infoKey">{{ state.leftInfo?.name }}</div>
          </div>
        </template>

25. VSCode自带的git工具,把项目添加到VSCode中以后,用可视化窗口向远程仓库推送代码报错。怎么办?

image.png

image.png

解决方案是,基于项目路径打开终端,在终端命令行手动执行一次git push指令,你会发现可视化界面向远程仓库推送代码功能就正常了。

24. 问题如下,利率有一部分字符展示成乱码,是什么原因?

刚开始以为是字体文件加载报错造成的,后面发现是因为左侧的div宽度不足造成的。发生在IOS 15.4.1上,记录一下,下次就遇到就不慌了。

image.png

23. 为什么vue页面引入的组件,突然之间按Ctrl键+鼠标左键点击时无法正常跳转定义处?

最后发现Vue Language Features (Volar) 最近的版本出现问题,升级到1.8.0版本,或者回退到1.7.11版本,组件跳转定义功能正常。刚开始还以为是VSCode版本升级引起的,差点把VSCode版本回退。所以以后升级版本时,记住对哪些扩展进行了升级,要是原本使用正常的功能不能用了,肯定是那些扩展最新的版本出了问题,进行版本回退就可以了。

112afa66a2cfbe08739428f6b9d0ef2.png

22. 如何看懂控制台的警告?

如下的控制台警告信息, 如何找到出错的地方。出错信息都是从内向外输出错误。最上面的错误信息,是引起警告的源头。从源头上可以看到一些组件的属性信息,根据这些属性去查找出错的组件,如果点开出错信息左边的小三角,就会进入误区,不太好查找实际出错的地方。

image.png

21. 加载页面,vue-router导航报错,可能的原因是?

image.png

可能的原因是:

  1. 页面因为多种原因出现脚本错误
  2. 网络不好,造成的资源和数据请求错误

20. 使用useInfiniteScroll工具监听容器是否滚动到底,为什么在切换tab的时候,有时加载到底事件会执行两次?

这是因为如果调用了scrollRef.value?.scrollTo(0, 0);之后,也会触发滚动到底事件,造成误加载,要把这种情况过滤掉。修复之后的代码逻辑如下图所示:

 import { useInfiniteScroll } from '@vueuse/core';
 const scrollRef = ref<HTMLElement>();
 
 useInfiniteScroll(
    scrollRef,
    () => {
      console.log('上拉加载', scrollRef.value?.scrollTop);
      // 上拉加载更多
      scrollRef.value!.scrollTop > 0 && emit('loadMoreFun', true);
    },
    { distance: 5 }
  );

19. 日常开发中有哪些场景,需要提高代码的执行效率?

我能想到的场景有:

  1. 高频触发的事件 如mouse,scroll, 需要节流或者使用RAF
  2. 移动dom元素位置,要开启GPU加速
  3. 查找树形结构的某个元素,要将深度遍历改成广度遍历。
  4. dom操作,要批量执行。

18. flex布局,为什么一侧的容器被挤扁?

<style>
.flex{
    display:flex;
    width:300px;
}
.avatar{
    width:100px;
    height:100px;
    background-color:green;
    border-radius:100%;
}
.info-desc{
    width:220px;
}
</style>
<div class="flex">
    <div class="avatar"></div>
    <div class="info">
        <div class="info-desc">123456</div>
    </div>
</div>

效果如下图所示: 可以看出,头像被挤扁。对flex属性不太熟悉的新手,遇到这种诡异现象,一时肯定不知如何排查bug,解决方法就是让info下面的元素,宽度不要溢出。本例中宽度不能超过200px.

image.png

17. 今天发现, 微信分享出去的卡片,png格式的图片,在Android手机上展示不正常?

换成jpg格式的图片就正常了。

16. 下面的代码有什么问题?

下面的代码看着简单, 如果不细想,可能导致页面跳转出错。如果props.productDetail.productLink中没有查询参数,下面的代码在运行时就会造成页面一片空白。

    const jumpUrl = props.productDetail.productLink + `&a=foo`;

正确的写法是:

 const joiner = props.productDetail.productLink.includes('?') ? '&' : '?';
 const jumpUrl = props.productDetail.productLink + `${joiner}a=foo`;

15. 基于nx+workspace微前端架构,跨feature使用hooks, hooks变量是undefined,如何解决?

首先,要将hooks定义在shared特性库,这样才能被访问到。其次,hooks要定义成函数,才能在页面加载的时候正确执行。

import { computed } from 'vue';
export function useProduct() {
    const amount=computed(()=>props.data * 2);
    return {amount};
}

14. git stash pop之后,代码出现冲突,如何撤销操作?

切错了分支, 执行git stash pop后,引起代码冲突。想撤销git stash pop弹出储存的内容,如何撤销,既能将代码状态恢复到冲突之前,还能保留git stash 保存的内容。 答案是执行git reset --hard,这个指令说出来你肯定知道,可是在特定场景下的其它功效,你可能未必清楚。

13. async/await 出错之后,会不会执行到await之后的程序片段?

如下, 如果const res= await Api.getData(params)执行出错,是不会走到console.log(res)这里的,然而我发现,许多人以为可以执行到,在后面写了一些错误判断处理逻辑,其实是在做无用功。

async foo(){
    const res= await Api.getData(params);
    console.log(res);
}

12. 上拉加载更多功能, 除了用IScroll,还有哪些选择?

今天发现在vue中,一个比较好用的判断是否滚动到容器底部的方法useInfiniteScroll,用法如下:

<script setup lang="ts">
import { ref } from 'vue'
import { useInfiniteScroll } from '@vueuse/core'

const el = ref<HTMLElement>(null)
const data = ref([1, 2, 3, 4, 5, 6])

useInfiniteScroll(
  el,
  () => {
    // load more
    data.value.push(...moreData)
  },
  { distance: 10 }
)
</script>

<template>
  <div ref="el">
    <div v-for="item in data">
      {{ item }}
    </div>
  </div>
</template>

11. 组件中错误的v-if/v-else-if逻辑,造成下拉滚动列表, 每次数据加载的时候,无法复用上次渲染的数据,会滚动到容器顶部, 怎么处理?

这是错误的流程,错误之处在于,每次loading值发生变化时,ArticleListItem组件会被重新渲染。

    <Loading class="loading" v-if="isLoading" />
    <template v-else-if="list?.length > 0">
      <ArticleListItem
        v-for="(item, index) in list"
        :key="index"
        :data="item"
        :queryType="queryType"
        @click="openArticleDetailPage"
      />
      <BaseEndLine class="bottom-tips" v-if="showEnd">已经到底啦</BaseEndLine>
    </template>

改成这样就对了

  <Loading v-if="isLoading" class="loading" />
  <div class="article-list" ref="scrollRef">
    <template v-if="list?.length > 0">
      <ArticleListItem
        v-for="(item, index) in list"
        :key="index"
        :data="item"
        :queryType="queryType"
        @click="openArticleDetailPage"
      />
      <BaseEndLine class="bottom-tips" v-if="showEnd">已经到底啦</BaseEndLine>
    </template>
  </div>

10. axios 如何对post请求,json数据进行提交前的转换?

方式一: 使用transformRequest函数

const instance = axios.create({
    baseURL: 'api-url.com',
    transformRequest: [
        (data, headers) => {
            // 入参data是对象
            const transData = trans(data);
            // 出参要返回字符串才行
            return JSON.stringify(transData);
        },
    ],  
});

方式二: 直接修改config.data

instance.interceptors.request.use(
  function (config) {
      config.data=trans(config.data);
  }
)

9. Chrome浏览器的微信调试功能,为什么有时候突然没有反应?

如下图所示, Chrome的H5页面调试功能,有时突然不展示任何H5页面内容。

这是因为手机上的微信,会时不时的自动进行更新。每次更新之后,之前设置的调试功能会被覆盖。所以需要重新设置。在微信中点击下面的链接http://debugxweb.qq.com/?inspector=true,就可重新开启微信H5页面的调试功能。

8. 如何提取字符串中的数字?

提取连续在一起的单个数字:

const mixsStr = '1000起投';
// 将非数字字符全部替换成空字符
const num = mixStr.replace(/[^0-9]/ig, '');
num 结果 "1000"

上面的方法,并不通用,更通用的提取字符串中数字的方法是:

// 匹配以
const reg = /[1-9][0-9]*/g;
// 如果要匹配数字0,这里要改成
// const reg = /\d*/g;
const mixStr= '1000元起投,递增金额100元';
const num = mixStr.match(reg);
// num  结果 ["1000", "100"]

7. ant-design-vue, 如何禁用表格复选框的某些记录?

在官网查了一下如何禁用多选表格某些选项的示例,发现示例并不满足要求,不是按照记录中的某个属性设置禁用,看了好几篇文章,发现下面的方法是可行的。

const rowSelection = {
  selectedRowKeys,
  onSelect: (record, selected, selectedRows) => {
    // ...
  },
  onSelectAll: (selected, selectedRows, changeRows) => {
    // ...
  },
  getCheckboxProps: (record) => {
    if (record.isDelete == 1) {
      return { disabled: true };
    } else {
      return null;
    }
  },
};

6. 如何让一张图片铺满整个屏幕,且不变形?

body{
    min-height:100vh;
    background-url:url('xxx');
}

横向铺不满或铺满之后图片会变形的解决方法:

background-size: 100% auto;

横向图片铺不满或铺满之后图片会变形的解决方法:

纵向图片铺不满的解决方法:

     background-color: '和背景图片的主色调一致'; 

image.png

5. 在Chrome浏览器的Console工作台,如何安装使用npm工具包?

首先需要给Chrome浏览器安装一个Console Importer的扩展。 image.png

安装完之后,重启浏览器,我们安装一下dayjs,试试效果。

image.png

注意安装的npm包仅是在当前tab页,当次生效。

image.png

4. 网页的性能如何可视化 ?

第一步 安装stats.js工具包

pnpm  add stats.js

第二步 启动浏览器的时候,添加--enable-precise-memory-info参数

image.png

第三步:将fps/ms/mb仪盘添加到页面中。


    var stats = new Stats();
    // ms是需要多长时间可能渲染一帧
    stats.showPanel( 1 ); // 0: fps, 1: ms, 2: mb, 3+: custom
    document.body.appendChild( stats.dom );

    function animate() {
    	stats.begin();
    	// monitored code goes here
    	stats.end();
    	requestAnimationFrame( animate );
    }
    requestAnimationFrame( animate );

然后就能看到如下效果:

image.png

3. F12调试控制台被禁用怎么办?

有时候,想看看别人做的页面酷炫效果。使用了什么样式,可是有时发现,浏览器调试控制台打不开。以下3种打开方式, 统统失效。

  • ctrl+shifit+I
  • F12
  • 鼠标右键。

这个时候咋办呢,正确的打开浏览器控制台的方式是从浏览器设置栏打开开发者工具。 点击浏览器右上角的...==>更多工具==>开发者工具, 就可打开调试控制台。

2. 如何避免tag太长引起的内容溢出?

业务要求,每行最多展示两个tag, tag不能换行展示。如下图所示,出现两个tag时,第二个tag发生溢出,虽然可以加宽tag标签外层容器的宽度,缓解这种问题,可是如果tag中的文字过长的话,还是无法彻底解决这个问题。所以除了要加宽tag外层容器的宽度外,还要限定tag文字的长度,过长的话显示省略号。

1684893811221.png

  /*  省略号的实现  */
  .tag {
    max-width: 100px; 
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

1. useRequest 如何约束响应数据的ts类型?

查看了一下import { useRequest } from 'vue-request';的类型定义,如下所示:

declare function useRequest<R, P extends unknown[] = any>(service: IService<R, P>): RequestResult<R, P>;

从中可以看出,useRequest有两个泛型,一个用来约束响应数据,一个用来约束请求数据。所以约束响应数据的类型定义的写法就很easy了。

  interface ResponseData {
    ret: number;
    msg: string;
    retdata: {
      id: number;
      name: string;
    };
  }
   const {
    data: dataOverviewData,
    run: fetchDataOverview,
    loading: loadingDataOverview,
    error: dataOverviewError,
  } = useRequest<ResponseData>(managerSummaryApi.getDataOverview, {
    manual: true,
    formatResult: (res) => {
      return res.retdata || {};
    },
  });