前端大佬的成长录

疑惑类

1. 在 promise 里面不需要async 但是什么时候需要async await 呢??

Promise 本身就是一个异步对象,async await 也是为了解决异步问题,

  • 函数不需要 async/await,因为它只是把 Promise 返回出去,调用方可以自己用 .then() 或 await。
  • 只有在你需要在函数内部处理异步结果时,才需要用 async/await。

"在函数内部处理异步结果" 理解:比如你用 axios、fetch、hyRequest 这些方法去请求后端接口,拿到的数据不是立刻返回的,而是异步返回的,通常是一个 Promise。

易错点

2. 关于scroll滚动时,是依据 window 滚动还是 ele 元素


1. 经验类:

1.1 关于flex布局可以产生的等价的效果

目前样式:

要求样式:

解决方式1. 采用displat: flex; + width: 50%; + 换行

解决方式2. 采用 flex: 1; + justify-content: flex-end;

完整的:

详细解释: 逐个分析这些属性:

1. display: flex

  • 将元素设置为弹性布局(Flexbox)容器

  • 这使得其子元素可以灵活地排列和对齐

  • 在这个评论组件中,它用于 .right 类,用来排列评分项

2. flex-wrap: wrap

  • 允许 flex 项目在需要时换行

  • 当一行放不下所有内容时,会自动换到下一行

  • 在这个场景中,如果评分项太多,会自动换行显示,不会溢出容器

3. flex: 1

  • 这是 flex-grow: 1 的简写

  • 表示该元素会占据父容器中所有可用的剩余空间

  • 在这个评论组件中,.right 区域会占据左侧评分区域之外的所有空间

4. justify-content: flex-end

  • 控制 flex 项目在主轴(水平方向)上的对齐方式
  • flex-end 表示将内容靠右对齐
  • 在这个评论组件中,评分项会靠右显示

1.2 关于数据存储的两种形式

方式一:存储在 store 里面 (引入+store.js)

第一步要注意:获取接口方法,例如是在 services 文件夹里面进行配置接口方法

接着,就要 借助pinia 里面的 defineStore(" ", {state: ... ,actions: ...})+ store 文件夹下面的.js文件( js 文件里面要写发送网络请求的函数

方式二: 存储在页面里面 defineProps({}) (组件+传参)

借助组件里面的传参的形式进行书写


1.3 关于 HYRequest 里面代码的理解

1.3.1 axios.create 的作用主要是创建单独的实例:为这个实例设置专属的 baseURL、timeout、拦截器等,不影响全局的 axios 配置。


1.4

2. 技巧类

2.1 关于导出

  1. 当使用 export default 时(就像当前的代码):

    javascript 复制代码
    // useScroll.js
    
    export default function useScroll() { ... }
    
    // detail.vue
    
    import useScroll from "@/hooks/useScroll";  // 不需要 {}
  2. 当使用普通 export 时:

javascript 复制代码
   // useScroll.js

   export function useScroll() { ... }

   // detail.vue

   import { useScroll } from "@/hooks/useScroll";  // 需要 {}
   

这是因为:

  • export default 表示这个模块的默认导出,一个模块只能有一个默认导出
  • 普通 export 可以导出多个内容,所以需要用 {} 来指定要导入的具体内容

2.2

3. 知识点

3.1 关于页面滚动中的clientHeight、scrollTop和scrollHeight的区别和关系

clientHeight指的是元素内部的可视区域高度,包括padding但不包括边框、滚动条和margin

scrollTop则是元素顶部被隐藏的滚动距离,也就是已经滚动的部分。

scrollHeight是整个内容的高度,包括被隐藏的部分,所以它代表实际内容的总高度。

通常,当判断是否滚动到底部时,会用到scrollTop + clientHeight >= scrollHeight . 这时候需要确保这三个值都是针对同一个元素的,比如document.documentElement或某个具体的容器元素。

1. 核心概念

clientHeight(可视区域高度)

  • 含义 :元素内部可见部分的高度(不含滚动条,但包含 padding)。

  • 计算方式

    js 复制代码
    clientHeight = 可视区域高度 + 上下padding
  • 特点 :如果元素没有滚动条,clientHeight 约等于内容高度(当内容不溢出时)。

scrollTop(已滚动距离)

  • 含义 :元素内容顶部可视区域顶部的滚动距离(被隐藏的高度)。

  • 单位:像素(px),可读写属性。

  • 特点

    • scrollTop = 0 表示未滚动(内容顶部与可视区域顶部对齐)。
    • scrollTop 最大值是 scrollHeight - clientHeight

scrollHeight(内容总高度)

  • 含义 :元素全部内容的高度(包括被隐藏的部分和 padding,不含滚动条)。

  • 计算方式

    js 复制代码
    scrollHeight = 实际内容高度 + 上下padding
  • 特点 :即使没有滚动条,scrollHeight 也始终存在(可能等于 clientHeight)。


2. 三者的关系

公式

js 复制代码
// 判断是否滚动到底部
if (element.scrollTop + element.clientHeight >= element.scrollHeight) {
  // 触发加载更多等操作
}
  • 解释

    • scrollTop + clientHeight:已滚动的高度 + 可视区域高度。
    • 当这个值大于等于 scrollHeight 时,说明已经滚动到底部。

3. 图解示例

lua 复制代码
|-------------------------------|
|         可视区域 (clientHeight) |
|                               |
|   ↑ scrollTop                 |
|   -------------------------   |
|   | 已隐藏的内容            |  |
|   -------------------------   |
|   | 可见的内容              |  |
|   |                         |  |
|   |                         |  |
|   |                         |  |
|   -------------------------   |
|                               |
|                               |
|-------------------------------|
  • 总内容高度 (scrollHeight) = 已隐藏内容高度 + 可见内容高度。
  • 已滚动距离 (scrollTop) = 已隐藏内容的高度。
  • 可视区域 (clientHeight) = 可见内容的高度。

4. 实际应用场景

① 判断页面滚动到底部

js 复制代码
window.addEventListener("scroll", () => {
  const { scrollTop, clientHeight, scrollHeight } = document.documentElement;
  if (scrollTop + clientHeight >= scrollHeight - 10) { // 留10px容错
    console.log("滚动到底部了!");
  }
});

② 滚动到指定位置

js 复制代码
// 滚动到元素中间
const element = document.getElementById("target");
element.scrollTop = element.scrollHeight / 2 - element.clientHeight / 2;

5. 注意事项

  1. 浏览器兼容性

    • 在标准模式下,使用 document.documentElement 获取属性。
    • 在怪异模式(Quirks Mode)下,使用 document.body
  2. 小数像素问题

    • 某些浏览器可能返回小数,建议用 Math.ceil() 处理:

      js 复制代码
      Math.ceil(element.scrollTop + element.clientHeight) >= element.scrollHeight
  3. 滚动条的影响

    • 如果容器有横向滚动条,clientHeight 会减去滚动条高度(通常约15-20px)。

总结

  • clientHeight:你能看到的内容高度。
  • scrollTop:你已经滚动了多少。
  • scrollHeight:全部内容的总高度。
  • 滚动到底部的条件scrollTop + clientHeight >= scrollHeight

3.2 defineEmits 的作用

defineEmits 是 Vue3 中用于定义组件可以触发的自定义事件的 API。

  1. 基本用法
js 复制代码
// 定义组件可以触发的事件

const emit = defineEmits(['tabItemClick'])

// 在需要的时候触发事件

emit('tabItemClick', index)
  1. 在你的代码中的应用
js 复制代码
<script setup>

import { ref } from 'vue'

defineProps({

    titles: {

        type: Array,

        default: () => []

    }

})

// 定义组件可以触发的事件

const emit = defineEmits(['tabItemClick'])

const currentIndexMy = ref(0);

const itemClickMy = (index) => {

    currentIndexMy.value = index;

    // 触发自定义事件,把 index 传给父组件

    emit('tabItemClick', index)

}

</script>
  1. 在父组件中如何使用
js 复制代码
<template>

    <tab-control 

        :titles="titles" 

        @tabItemClick="handleTabClick"

    />

</template>

<script setup>

const handleTabClick = (index) => {

    console.log('父组件收到点击事件,索引是:', index)

    // 在这里处理点击事件

}

</script>
  1. 为什么要用 defineEmits?
  • 组件通信:子组件可以通过 emit 向父组件传递信息
  • 解耦:子组件不需要知道父组件如何处理事件
  • 可维护性:明确声明组件可以触发哪些事件
  1. 完整示例
js 复制代码
<!-- 子组件 tab-control.vue -->

<template>

    <div class="tabControl">

        <template v-for="(item, index) in titles" :key="index">

            <div class="decoration" 

                 :class="{ active: currentIndexMy === index }" 

                 @click="itemClickMy(index)">

                <span>{{ item }}</span>

            </div>

        </template>

    </div>

</template>

<script setup>

import { ref } from 'vue'

defineProps({

    titles: {

        type: Array,

        default: () => []

    }

})

const emit = defineEmits(['tabItemClick'])

const currentIndexMy = ref(0);

const itemClickMy = (index) => {

    currentIndexMy.value = index;

    emit('tabItemClick', index)  // 触发事件,把 index 传给父组件

}

</script>

<!-- 父组件 -->

<template>

    <tab-control 

        :titles="['选项1', '选项2', '选项3']" 

        @tabItemClick="handleTabClick"

    />

</template>

<script setup>

const handleTabClick = (index) => {

    console.log('父组件收到点击事件,索引是:', index)

    // 处理点击事件

}

</script>
  1. 总结
  • defineEmits 用于定义组件可以触发的事件
  • 通过 emit('事件名', 参数) 触发事件
  • 父组件通过 @事件名="处理函数" 监听事件
  • 这是 Vue3 中组件通信的重要方式之一

3.3 关于 ref 和 conmputed 的区别和联系

  1. ref:
  • ref是Vue 3中引入的一个响应式API,用于创建一个响应式的引用。它可以用来包装基本类型(如字符串、数字等)或对象。

  • 在模板中,ref会自动解包,所以在模板中不需要使用.value来访问值;但在JavaScript中,我们需要通过.value来访问或修改它的值。

  • ref通常用于定义响应式数据,这些数据可能会被直接修改,并且可能不依赖于其他数据。

  1. computed:
  • computed用于定义计算属性。计算属性是基于它们的依赖进行缓存的响应式数据。

  • 计算属性是一个函数,返回一个值。这个值会根据其依赖的其他响应式数据的变化而变化,并且只有当依赖发生变化时,计算属性才会重新计算。

  • 计算属性适合用于需要根据其他数据派生出来的复杂逻辑,避免在模板中写过多逻辑。

区别:

  • 使用目的不同:ref用于创建响应式数据,而computed用于创建依赖于其他响应式数据的计算属性。

  • 缓存:computed具有缓存,只要依赖不变,多次访问计算属性不会重新计算;而ref每次访问都会得到当前值,但没有缓存机制(除非你自己用computed包装)。

  • 可写性:ref创建的数据是可读可写的(可以直接修改.value);而computed默认是只读的,但也可以定义成可写的(通过提供get和set函数)。

核心区别

特性 ref computed
用途 创建响应式数据(基本类型/对象) 创建基于依赖动态计算的值(派生数据)
返回值 返回一个响应式对象(通过 .value 访问) 返回一个只读 的响应式引用(自动解包,无需 .value
是否可写 ✅ 可直接修改 .value ❌ 默认只读(需定义 set() 才能可写)
缓存机制 ❌ 无缓存 ✅ 自动缓存(依赖不变时复用结果)
适用场景 存储可变状态(如计数器、输入值) 依赖其他数据的复杂计算(如过滤列表、格式化数据)

如何选择?

  1. 需要存储原始数据? → 选 ref

    (例:const inputText = ref("")

  2. 需要基于其他数据动态计算? → 选 computed

    (例:const sortedList = computed(() => [...list].sort())

  3. 需要可写计算属性? → 用 computedset()

    javascript 复制代码
    const writableComp = computed({
      get: () => count.value * 2,
      set: (val) => { count.value = val / 2 } // 修改依赖
    });

一句话总结

ref 是"数据容器",computed 是"自动计算的衍生值"

两者互补而非替代:computed 内部常依赖 ref 工作!


3.4 在vue 中,获取元素的方法

Vue 中获取元素有几种主要方式

  1. 使用 ref 获取元素(推荐方式):

    javascript 复制代码
    <template>
    
      <div ref="myRef">内容</div>
    
    </template>
    
    <script setup>
    
    import { ref, onMounted } from 'vue'
    
    const myRef = ref(null)
    
    onMounted(() => {
    
      console.log(myRef.value) // 获取到元素
    
    })
    
    </script>
  2. 使用 template ref(用于获取模板中的元素):

    javascript 复制代码
    <template>
    
      <div ref="myRef">内容</div>
    
    </template>
    
    <script setup>
    
    import { ref } from 'vue'
    
    const myRef = ref(null)
    
    </script>
  3. 使用 querySelector(不推荐,但在某些场景下可用):

    javascript 复制代码
    <script setup>
    
    import { onMounted } from 'vue'
    
    onMounted(() => {
    
      const element = document.querySelector('.my-class')
    
      console.log(element)
    
    })
    
    </script>
  4. 使用 getElementById(不推荐,但在某些场景下可用):

    javascript 复制代码
    <script setup>
    
    import { onMounted } from 'vue'
    
    onMounted(() => {
    
      const element = document.getElementById('my-id')
    
      console.log(element)
    
    })
    
    </script>
相关推荐
henujolly27 分钟前
网络资源缓存
前端
yuren_xia3 小时前
Spring Boot中保存前端上传的图片
前端·spring boot·后端
普通网友4 小时前
Web前端常用面试题,九年程序人生 工作总结,Web开发必看
前端·程序人生·职场和发展
站在风口的猪11086 小时前
《前端面试题:CSS对浏览器兼容性》
前端·css·html·css3·html5
青莳吖7 小时前
使用 SseEmitter 实现 Spring Boot 后端的流式传输和前端的数据接收
前端·spring boot·后端
CodeCraft Studio8 小时前
PDF处理控件Aspose.PDF教程:在 C# 中更改 PDF 页面大小
前端·pdf·c#
拉不动的猪8 小时前
TS常规面试题1
前端·javascript·面试
再学一点就睡9 小时前
实用为王!前端日常工具清单(调试 / 开发 / 协作工具全梳理)
前端·资讯·如何当个好爸爸
Jadon_z9 小时前
vue2 项目中 npm run dev 运行98% after emitting CopyPlugin 卡死
前端·npm
一心赚狗粮的宇叔9 小时前
web全栈开发学习-01html基础
前端·javascript·学习·html·web