当前位置: 首页 > news >正文

vue3搭建实战项目笔记三

vue3搭建实战项目笔记三

      • 3.1.行高偏移问题
      • 3.2.谷歌浏览器上不能定位
        • 3.2.2 移动端css隐藏滚动条
      • 3.3.获取列表的数据
        • 3.3.1 服务器返回十万条数据
        • 3.3.2 分页展示数据
        • 3.3.2 防止展示数据为空报错
      • 3.4.上拉加载数据
        • 3.4.1 加载更多数据
        • 3.4.2 监听页面滚动到底部
        • 3.4.3 监听滚动的时机
        • 3.4.4 监听滚动抽取成hooks
        • 3.4.5 useScrollHook在页面中使用
        • 3.4.6 监听滚动距离scrollTop
        • 3.4.7 优化scrollHook
      • 3.5.显示头部搜索
      • 3.6 解决手动切换路由不更新tarBar的问题
      • 3.7 开始时间和结束的共享

3.1.行高偏移问题

  • 3.1.1.引入了normalize.css,引起的行高偏差问题
    - 1.产生的原因:
    • 由于引入了normalize.css, 所以html的line-height: 1.15;
    • line-height是会继承的,line-height没有设置单位,相当于是fontSize的倍数
    • 例如:
          line-height: 2; => 12*2 = 24px
          font-size: 12px;
      
    • line-height去掉文字的高度后再进行平方,1.15*12 = 13.8
    • 去掉文字高度后,只剩下1.8 无法平方,可能有些浏览器会下面来个1,上面来一个0(0.8做一个向下取证Math.floor(0.8))
- 2.防止行高偏差的解决方案:
    在assets文件夹下的css目录下的reset.css进行html行高的重置
    ```css
      html {
        /* 目前大多数浏览器的line-height:1.2是比较常见的 */
        line-height: 1.2; 
      }
    ```
- 3.补充:中文的文字会向上偏移一点点,英文反而是有一点点向下沉的

3.2.谷歌浏览器上不能定位

  • 1.在Edge浏览器测试定位
    Edge浏览器在渲染界面的时候,渲染的引擎对应的chrome里面的Blink是一样的
    在实现一些API的时候不一样的
  • 2.拿到对应的经纬度发送给服务器(或第三方服务器百度,高德)并返回城市信息
    • longitude:113.2643
    • latitude: 23.129
  • 3.分析谷歌浏览器不能定位的原因:
    • 3.1.如果电脑可以连上国外的服务器,就可以获取到对应的定位信息
    • 3.2.edge浏览器和chrome浏览器对于geolocation.getCurrentPosition()的实现不一样
      • edge:
      • 获取当前位置信息,是直接获取下电脑有没有获取到当前用户的位置,如果有获取的到直接返回当前用户位置
      • chrome:
      • 拿到当前电脑的IP地址,把IP地址发送给谷歌服务器,要求必须先连接上谷歌的服务器,
        在国内是连接不上谷歌服务器的,连接不上就没法根据IP地址分析出当前位置,无法返回对应的地址信息
      • 手机上是可以正常获取的
    • 3.3.解决:
      在edge、手机上是可以正常获取到定位信息
  • 4.参考文档:https://www.w3.org/TR/geolocation/#introduction
    • geolocationAPI是一个高度抽象的接口,就是不告诉内部怎么实现的
    • 内部是不管不规定是如何通过IP地址、GPS、RFID、WiFi、蓝牙等设备信息来分析出当前用户的位置信息,只是和设备的速度有关联
    • 在谷歌PC端,谷歌是通过IP地址来分析出当前用户的位置信息,不保证返回的一定是当前设备的真实位置
  • 5.补充:sdk - software development kit
  • 完整代码:
        navigator.geolocation.getCurrentPosition((renderToString) => {
          // latitude// 纬度
          // longitude// 经度
          console.log('获取位置成功:', renderToString);
        }, (res) => {
          console.log('获取位置失败:', res);
        },{
          enableHighAccuracy: true,
          timeout: 5000,
          maximumAge: 0,
        })
    
3.2.2 移动端css隐藏滚动条
  ::webkit-scrollbar {
    display: none;
  }

3.3.获取列表的数据

3.3.1 服务器返回十万条数据
    1. 在当前应用程序里开一个对应的线程(多线程的东西-webworker)
    1. 虚拟列表,比较少见
    1. 一般在整个项目架构的时候不推荐返回十万条数据,除非非常需要,最好不要放在前端处理十万条数据,前端出处理十万条数据,会让浏览器变得非常卡,对用户体验不好,让服务器去处理去占用对应的资源,让前端来做展示(用户浏览器占用过多资源的话,会造成卡顿,体验不好,最好不要这么做)
  • 两种做法如下:
    1. 引入第三方库 axios,直接在组件页面直接使用axios发送网络请求,但是这样来做不好,不利于代码维护
    2. 最好对axios做一层封装,不管是复用性、可用性、可维护性,甚至框架的替换都是更方便的
3.3.2 分页展示数据
  • 1.分页请求传参
    页码和每页条数 page, size (服务器有做分页的情况下)
    每页条数和偏移 size offset=0,30,60 (服务器没有做分页的情况下)
3.3.2 防止展示数据为空报错
- 1.使用可选链?.
  ```javascript
      const { userInfo } = getUserInfo()
      console.log(userInfo?.image?.url)
  ```
- 2.使用v-if
 ```html
    <div v-if="userInfo.image">{{userInfo.image.url}}</div>
  ```

3.4.上拉加载数据

3.4.1 加载更多数据
- 1.在homeStore中定义一个页码来记录当前第几页,默认为第一页
- 2.每次点击加载更多,发送请求,请求成功后, 把数据添加到数组中,然后重新渲染页面, 然后页码+1。
- 3.代码如下:
  ```javascript
      // 1.service.js
      export function getHomeCategories () {
        return hyRequest.get({ url: "/home/categories" })
      }

      // 2.homeStore.js
      import { defineStore } from "pinia";
      import { getHomeHouseList} from "@/service";

      const useHomeStore = defineStore("home", {
        state: () => ({
          currentPage: 1,
          houselist: []
        }),
        actions: {
          async fetchHouseListData () {
            const res = await getHomeHouseList(this.currentPage)
            this.houselist.push(...res.data)
            this.currentPage++
          }
        }
      })

      export default useHomeStore
  ```
3.4.2 监听页面滚动到底部
- 1. 页面为什么会滚动
  - 1.1.window窗口滚动(整个页面所有内容超过100%并且有滚动条)
  - 1.2.元素滚动(元素设置overflow-y: auto)
- 2.监听滚动
    ```javascript
      // window窗口的滚动
      window.addEventListener('scroll', () => {})
      // 元素的滚动
      divEl.addEventListener('scroll', () => {})
    ```
- 3.监听滚动到底部
  - 3.1.想要知道滚动了多少区域 
    - 3.1.1. 它其实是我们对应文档的一个滚动,整个窗口之所以可以滚动,是因为它的文档变得非常的长,当往上面滚动的时候,有一个往上滚动的高度
    - 3.1.2. 往上滚动的高度叫做scrollTop
  - 3.2.怎么知道滚动到了底部
    - 3.2.1. 可以拿到整个文档可以滚动的区域scrollHeight(也相当于整个文档的高度)
    - 3.2.2. 拿到客户端的高度,如果客户端的高度 + scrollTop >= scrollHeight 说明滚动到底部
  - 3.3.代码如下: 
  ```javascript
    // 监听窗口的滚动
    window.addEventListener('scroll', () => {
      const clientHeight = document.documentElement.clientHeight
      const scrollTop = document.documentElement.scrollTop
      const scrollHeight = document.documentElement.scrollHeight
      if (clientHeight + scrollTop >= scrollHeight) {
        // 如果说到达底部了,就加载更多数据
        homeStore.fetchHouseListData()
      }
    })
  ```
3.4.3 监听滚动的时机
- 1. 当加载页面时,监听滚动
    ```javascript
      onMounted(() => {
        window.addEventListener('scroll', scrollListenerHandler)
      })
     ```
- 2. 当离开页面时,移除监听滚动(原因:页面之间都监听了window的滚动,会影响下一个页面的监听滚动,所以需要再卸载页面移除滚动事件)
    ```javascript
        onUnmounted(() => {
          window.removeEventListener('scroll', scrollListenerHandler)
        }) 
    ```
3.4.4 监听滚动抽取成hooks
- 在hooks中封装一个useScroll(原因:别的页面也需要进行类似的监听)
  - 1.1.判断滚动到底部的两种做法:
      1. 传入一个回调函数,一旦滚动到底部执行回调函数 
        ```javascript
          import { ref, onActivated, onDeactivated, onMounted, onUnmounted } from 'vue'
          export default function useScroll(reachBottomCB) {
            const scrollListenerHandler = () => {
              const clientHeight = document.documentElement.clientHeight
              const scrollTop = document.documentElement.scrollTop
              const scrollHeight = document.documentElement.scrollHeight
              if (clientHeight + scrollTop >= scrollHeight) {
                if(reachBottomCB) {
                  reachBottomCB()
                }
              }
            }

            onMounted(() => {
              window.addEventListener('scroll', scrollListenerHandler)
            })

            onUnmounted(() => {
              window.removeEventListener('scroll', scrollListenerHandler)
            }) 

            onActivated(() => {
              window.addEventListener('scroll', scrollListenerHandler)
            })

            onDeactivated(() => {
              window.removeEventListener('scroll', scrollListenerHandler)
            })
          
          }
        ```
      2. 返回一个变量,代表是否滚动到底部
        原因:回调比较多的时候,不好管理,更好管理的是变量
        ```javascript
          import { ref, onActivated, onDeactivated, onMounted, onUnmounted } from 'vue'
          export default function useScroll() {
            const isReachBottom = ref(false)
            const scrollListenerHandler = () => {
              const clientHeight = document.documentElement.clientHeight
              const scrollTop = document.documentElement.scrollTop
              const scrollHeight = document.documentElement.scrollHeight
              if (clientHeight + scrollTop >= scrollHeight) {
                isReachBottom.value = false
              }
            }

            onMounted(() => {
              window.addEventListener('scroll', scrollListenerHandler)
            })

            onUnmounted(() => {
              window.removeEventListener('scroll', scrollListenerHandler)
            }) 

            onActivated(() => {
              window.addEventListener('scroll', scrollListenerHandler)
            })

            onDeactivated(() => {
              window.removeEventListener('scroll', scrollListenerHandler)
            })


            return {
              isReachBottom
            }
          }
        ```
3.4.5 useScrollHook在页面中使用
  - 3.4.2.4.1. 回调函数形式
    ```javascript
      import useScroll from '@/hooks/useScroll';
      // 监听是否滚动底部
      useScroll(() => {
         homeStore.fetchHouseListData()
      })

    ```
  - 3.4.2.4.2. 返回一个变量
    ```javascript
      import useScroll from '@/hooks/useScroll';
      // 拿到isReachBottom,然后监听isReachBottom为真的时候滚动到底部
      const { isReachBottom } = useScroll()

      // 监听是否滚动底部
      watch(isReachBottom, (newValue) => {
        if(newValue) {
          homeStore.fetchHouseListData().then(() => {
            isReachBottom.value = false
          })
        }
      })
    ```
3.4.6 监听滚动距离scrollTop
  - 1.局部监听滚动距离放到全局上,返回把滚动距离返回出去
  - 2. 代码如下:
    ```javascript
      import { ref, onActivated, onDeactivated, onMounted, onUnmounted } from 'vue'
      export default function useScroll() {
        const isReachBottom = ref(false)
        const clientHeight = ref(0) // 可见的高度
        const scrollTop = ref(0) // 滚动的距离
        const scrollHeight = ref(0) // 整个文档的可滚动的高度
        
        // 监听窗口的滚动
        const scrollListenerHandler = (reachBottomCB) => {
          clientHeight.value = document.documentElement.clientHeight
          scrollTop.value = document.documentElement.scrollTop
          scrollHeight.value = document.documentElement.scrollHeight
          if (clientHeight.value + scrollTop.value >= scrollHeight.value) {
            isReachBottom.value = true
          }
        }

        onMounted(() => {
          window.addEventListener('scroll', scrollListenerHandler)
        })

        onUnmounted(() => {
          window.removeEventListener('scroll', scrollListenerHandler)
        }) 

        onActivated(() => {
          window.addEventListener('scroll', scrollListenerHandler)
        })

        onDeactivated(() => {
          window.removeEventListener('scroll', scrollListenerHandler)
        })


        return {
          isReachBottom,
          clientHeight,
          scrollTop,
          scrollHeight,
        }
      }
    ```
3.4.7 优化scrollHook
- 使用使用underscore库节流优化scrollHook
  - 1.监听滚动时,发现函数执行的次数很频繁,使用节流处理,减少函数执行次数。
  - 2.使用underscore.js中的throttle函数,对scrollHook进行优化。
  - 3.安装underscore: npm install underscore
  - 4.使用:import { throttle } from 'underscore'
    ```javascript
        import { ref, onActivated, onDeactivated, onMounted, onUnmounted } from 'vue'
        import { throttle } from 'underscore'

        // 执行频率太高使用:防抖/节流
        // 防抖:本来准备去执行一个东西,但是发现又触发了,然后把这个事件不断的延后,直到最后一次才执行
        // 节流:在单位时间内执行一个函数是非常频繁的,规定一个时间执行一次函数,每间隔一个时间执行一次函数
        export default function useScroll() {
          const isReachBottom = ref(false)
          const clientHeight = ref(0) // 可见的高度
          const scrollTop = ref(0) // 滚动的距离
          const scrollHeight = ref(0) // 整个文档的可滚动的高度
          
 
          const scrollListenerHandler = throttle(() => {
            clientHeight.value = document.documentElement.clientHeight
            scrollTop.value = document.documentElement.scrollTop
            scrollHeight.value = document.documentElement.scrollHeight
            if (clientHeight.value + scrollTop.value >= scrollHeight.value) {
              isReachBottom.value = true
            }
          }, 100)

          onMounted(() => {
            window.addEventListener('scroll', scrollListenerHandler)
          })

          onUnmounted(() => {
            window.removeEventListener('scroll', scrollListenerHandler)
          }) 

          onActivated(() => {
            window.addEventListener('scroll', scrollListenerHandler)
          })

          onDeactivated(() => {
            window.removeEventListener('scroll', scrollListenerHandler)
          })


          return {
            isReachBottom,
            clientHeight,
            scrollTop,
            scrollHeight,
          }
        }
    ```

3.5.显示头部搜索

-3.4.3.7.滚动到100显示头部搜索框
```javascript
import { watch, ref, computed } from ‘vue’;
import useScroll from ‘@/hooks/useScroll’;
const { isReachBottom, scrollTop } = useScroll()

    // const isShowSearchBar = ref(false)
    // 1.监听scrollTop的距离
    // watch(scrollTop, (newScrollTop) => {
    //  isShowSearchBar.value = newScrollTop > 100
    // })

    // 当一个可响应式数据依赖(影响)另外一个可响应式数据的时候,使用计算函数
    const isShowSearchBar = computed(() => {
      return scrollTop.value >= 100
    })
  ```

3.6 解决手动切换路由不更新tarBar的问题

  ```javascript
    // 1.开启路由模式
    <template>
      <van-tabbar v-model="currentIndex" active-color="#ff9854" route></van-tabbar>
    </template>
    // 2.监听路由变化,找到对应的索引,并修改currentIndex
      import { ref, watch } from 'vue';
      const route = useRoute()
      watch(route, (newRoute) => {
        const index = tabbarData.findIndex(item => item.path === newRoute.path)
        if(index === -1) return
        currentIndex.value = index
      })
  ```

3.7 开始时间和结束的共享

```javascript
   // 抽取到一个公共的mainStore中
  // src/store/main.js
  import { defineStore } from "pinia";

  const startDate = new Date()
  const endDate = new Date()
  endDate.setDate(startDate.getDate()+1) // 或者  nowDate.getTime() + 24*60*60*1000

  const useMainStore = defineStore('main', {
    state: () => ({
      token: '',
      startDate: startDate,
      endDate: endDate
    })
  })

  export default useMainStore


  // src/views/cpns/home-search-box.vue
  // 日期范围处理(页面中使用)
  import { computed, ref } from 'vue'
  import { storeToRefs } from 'pinia'
  import { formatMonthDay, getDiffDays } from '@/utils/format_date';
  import useMainStore from '@/stores/modules/main';
  const calendarShow = ref(false)
  const mainStore = useMainStore()
  const { startDate, endDate} = storeToRefs(mainStore)
  // formatMonthDay格式日期,默认格式为MM月DD日
  const startDateStr = computed(() => formatMonthDay(startDate.value))
  const endDateStr = computed(() => formatMonthDay(endDate.value))
  const stayCount = ref(getDiffDays(startDate.value, endDate.value))
  const onConfirm = (value) => {
    // 1.设置日期
    const selectStartDate = value[0]
    const selectEndDate = value[1]
    mainStore.startDate = selectStartDate
    mainStore.endDate = selectEndDate
    stayCount.value = getDiffDays(selectStartDate, selectEndDate)
    // 2.隐藏日历
    calendarShow.value = false
  }


  // src/components/search-bar.vue
  // 页面中使用
  import useMainStore from '@/stores/modules/main';
  import { formatMonthDay } from '@/utils/format_date';
  import { computed } from 'vue';
  import { storeToRefs } from 'pinia';

  const mainStore = useMainStore()
  const { startDate, endDate } = storeToRefs(mainStore)
  const startDateStr = computed(() => formatMonthDay(startDate.value, 'MM.DD'))  
  const endDateStr = computed(() => formatMonthDay(endDate.value, 'MM.DD'))

  ```

相关文章:

  • 如何设置PDF文件的到期日期
  • this关键字
  • 特征增强金字塔FPN
  • 为什么 ThreadLocalMap 的 key 是弱引用 value是强引用
  • 过滤器filter,监听器Listener
  • Java日志进化论:从System.out.println到日志框架的全面升级
  • 青少年编程与数学 02-013 初中数学知识点 02课题、概要
  • 习题2.1
  • 【免费】2007-2019年各省地方财政医疗卫生支出数据
  • J2EE框架技术 第三章 SSM项目的CURD
  • Netty源码—10.Netty工具之时间轮一
  • BAR帧处理
  • 怎样提升大语言模型(LLM)回答准确率
  • MySQL内存使用率高问题排查与解决方案:
  • Windows10上部署DeepSeek+RAG知识库操作详解(Dify方式)之1
  • GAMES101-现代计算机图形学入门(Assignment7)
  • sql优化子查询展开执行计划测试
  • 【Deepseek】企业AI DeepSeek战略课
  • 生产者消费者模型
  • 金融级密码管理器——密码泄露监控与自动熔断
  • 佳木斯建设局网站/做推广哪个平台好
  • 什么是手机网站建设/谷歌三件套一键安装
  • 徐州企业网站建设/推广手段
  • 传奇私服发布网网站建设/简单制作html静态网页
  • 建设银行科技中心网站首页/百度网站名称及网址
  • 网站制作如何做/品牌推广软文