小白白仿网易云项目经验总结。

482 阅读3分钟

遗留问题

1.VUE如何实现自定义指令,例如:

问题1:怎么注册一个全局的防抖函数,减少防抖函数的重复引用编写。

//解决代码

2.VUE在生命周期函数绑定了一个防抖函数,但是防抖的函数是一个闭包,在离开该组件时,无法销毁该事件函数。

  • 已解决
//解决方式:
//网上解决问题地址:https://blog.csdn.net/zyxczyf123/article/details/108800810

3.使用Element UI 里的表格,然后在表格里嵌套div,给这个div加上ref,表格循环后获取不到所有的赋予了ref的div,只能获取到最后一个div

  • 暂未解决

  • 换成dom方式去获取所有div是可以获取到的

    //document.queryselectorall获取所有div
    

4.状态机里的数据每次刷新都会重新赋值吗?

  • 遗留问题:歌手详情页面的mv页面一刷新,获取的数据就是没有传limit(获取多少条数据)值的。

5.为什么防抖函数写在另一个函数里就不起作用了?

  • 问题代码:
import {  debounce } from "../../utils/common";

created() {
   
        window.addEventListener(
            "scroll",
            debounce(this.changeCurrentPage, 500),
            false
        );
    },
methods:{
    changeCurrentPage(){
		//业务代码
    }
}
//以上写法防抖函数是可以正常运行的,但有问题:
//1.无法清除该函数,到下个页面依然会有这个事件
//2.每次都要重新引入防抖,绑定,重复在编写,浪费时间。
import {  debounce } from "../../utils/common";
created() {
   
        window.addEventListener(
            "scroll",
            this.changeCurrentPage,
            false
        );
    },
methods:{
    changeCurrentPage(){
		//业务代码
        debounce(this.foo,1000)
    },
    foo(){
		//业务代码
    	}
}
//以上写法是无法正常 执行的,debounce里的foo,并不能实现防抖效果。

//*********************
//防抖函数
// debounce 函数接受一个函数和延迟执行的时间作为参数
export const debounce = (func, wait) => {
    let timer;
    return function () {
        let context = this; // 注意 this 指向
        let args = arguments; // arguments中存着e
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
            func.apply(this, args);
        }, wait);
    };
}

6.在搜索界面也含有歌手,歌曲,MV列表,在歌手详情页也有这几个模块,按理来说应该是可以封装相同组件进行引用,但先前没有规划,导致难改。

  • 组件模块化很乱,代码粘性很大,比如歌手详情页的歌曲列表组件无法在搜索列表的歌曲组件进行使用,因为状态机和获取的数据不一样。粘性太大。

    • 耦合性太高

    • 什么是耦合

      模块与模块之间有写操作是有关联的, 如果改动一个木块其他的木块都有可能受到影响,模块与模块之间的关系越是紧密,独立性就越不好!

已解决问题----经验

1.页面滚动到底后加载下一页的数据

  • 首先可以给window绑定一个滚轮事件,再加上防抖就更好了。

  • 设定一个初始值,用于判定只有在滚轮向下滚动时才会触发该事件,防止反复发送请求和触发事件函数。

    • this.$refs.poll.getBoundingClientRect().top:
      • 判断该poll元素顶部距离窗口顶部的位置
    • window.innerHeight
      • 用户窗口的高度
    //实现代码
    //用于记录用户的滚动方向,用户一滚动,就把滚动后得到的值赋给这个值
    //等于是一个单向锁,防止用户向上滚动的时候也会触发事件
    this.prevY = 0;
    //给窗口绑定事件
    sendAjax() {
     	if (window.scrollY > this.prevY) {
        lazyload(this.$refs.singerImg);
        //记录单向锁,防止向上滚动也触发事件
         this.prevY = window.scrollY;
         console.log("window", window.scrollY);
          if (
     //如果占位符距离顶部的距离小于窗口,就证明这个占位符出现在了用户视野里
    //就可以发送ajax了
    //或者执行其他相应的操作
        this.$refs.poll.getBoundingClientRect().top <
                        window.innerHeight
                    ) {
                        //请求下一页数据
                        this.changeCurrentPage();
                        this.getSingerList();
                        this.qq();
                    }
                }
    
  • 可以给最下方的占位元素里面添加加载动画,直到获取回来的数据为空,就去除掉加载动画,并去除掉该监听事件(我的项目里,还未做该事情)

2.手动做一个可以拖动的进度条

实现步骤

  • 首先定义一个对象用于记录用户第一次点击拖动的鼠标位置
  • 记录用户点击之前进度条的长度
  • 然后当用户触发了点击事件后,加一个鼠标移动事件,记录用户的鼠标移动了多少距离。通过最开始记录的用户鼠标点击位置减去移动后用户的鼠标位置去计算进度条增加多少或者减少多少。
  • 最后在用户松开鼠标时,消除掉绑定的鼠标移动的事件。
progressMouseDown(e) {
            console.log(e.pageX);
            this.touch.sliding = true;
            this.touch.startX = e.pageX; //记录第一次用户鼠标的位置
            this.touch.length = this.$refs.progress.clientWidth; //记录最开始进度条的长度
            console.log(this.$refs.progress.clientWidth);
            document.onmousemove = (e) => {
                console.log(e.pageX);
                let deltaX = e.pageX - this.touch.startX; //计算鼠标移动了多少像素
                let offsetWidth = this.touch.length + deltaX;
              if(offsetWidth<710){//这里的710是进度条的总长度,限定拖动范围
                     this._offset(offsetWidth);
}
            };
        },
        progressMouseUp(e) {
            document.onmousemove = null;
            document.onmouseup = null;
        },
        _offset(offsetWidth) {
            this.$refs.progress.style.width = `${offsetWidth}px`;
        },

3.VUE在生命周期函数绑定了一个防抖函数,但是防抖的函数是一个闭包,在离开该组件时,无法销毁该事件函数。

原因:

  • 因为每次调用debounce都是返回的一个新的函数,因为是闭包,所以每次返回的新函数的地址都是不同的,所以每次清除的时候得清除这个新的函数的引用地址。

解决:

  • 事先用一个变量保存调用debounce返回的函数,然后在绑定事件的时候,绑定这个变量(这个变量就是防抖函数处理过的,返回的新函数),然后在销毁时,也销毁这个变量(函数)。

    updated(){
        //保存防抖函数处理过的新函数
    	this.foo=this.debounce(this.sendAjax, 1000);
    	console.log('返回的函数',this.foo);
        //绑定新函数
    	window.addEventListener("scroll",this.foo,false);
    }
    beforeDestroy() {
        //销毁掉新函数
         window.removeEventListener("scroll", this.foo);
    }
    

遗留问题(项目中)

  • 有时在鼠标松开时,鼠标的移动事件还是没有去处掉
  • 没有加判断当鼠标移动的距离大于进度条本身时,不能再增加进度条的长度,导致进度条的长度超出了该有的范围。

4.在项目中,有多个地方引用了相同的字符串或者字符。

  • **问题:**在多个地方都有引用相同的字符串,比如在生成token的时候,生成密钥的时候,有三个地方都在用相同的字符串。(加密,验证,解密token),都有用到这个字符串。而且这个字符串是不会被代码修改的,只能人为修改。

  • **解决:**在utils文件夹里,新建一个文件夹为consts(常量集合),去设置一些固定的常量,暴露出去。常量一般都是全大写

const TOKEN_SECRET='helloword';

5.如何在本地存储里面存数组?如何往本地存储的数组里面添加数据?

  • 首先你得指定在本地存储里面存储的数据只能是字符串形式,所以你想存储数组或者对象的话就得把数组和对象转换成JSON字符串形式。

    • JSON.stringify:
      • 把对象或者数组转换成json字符串形式
    • JSON.parse:
      • 把json字符串转换成数组或者对象。

    存数组实现步骤

    1. 因为本地存储里面只能存字符串,所以就把数组或对象利用JSON.stringfy转换成字符串
    2. localStorage.setItem("_history", JSON.stringify(arr));

    往已存在的数组存数据

    1. 先取出数据localStorage在用JSON.parse转换成数组
    2. 直接push即可

    以下代码是搜索历史的业务代码

    1. 首先判断用户的浏览器里是否搜索过,搜索过就直接往历史记录数组里添加历史记录
    2. 没搜过则创建一个历史数组。
    3. 待解决问题是:没有去重,可以重复添加相同记录。
     sendSearch(val) {
                // let arr = [{ his: val }];
                console.log("发送请求拉搜索时~~~~~~~~");
                this.$router.push("/home/search/" + val);
                this.search(this.$route.params._keywords);
                this.searchInput = "";
                let lishi = localStorage.getItem("_history");
                if (lishi != null) {
                    lishi = JSON.parse(lishi);
                    lishi.push(val);
                    localStorage.setItem("_history", JSON.stringify(lishi));
                } else {
                    let arr = [val];
                    localStorage.setItem("_history", JSON.stringify(arr));
                }
                this.loadingHistory();
            },