解析 URL 参数为对象,字符串模板,图片懒加载之三道js题

247 阅读2分钟

前言

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

解析 URL 参数为对象

题目要求:

将一个字符串

'http://localhost:8080/?a=1&b=2&c=3&a=4&keyword=%E7%94%B5%E8%84%91'

变成一个对象。

上述字符串变成了:

{ a: [ '1', '4' ], b: '2', c: '3', d: true, keyword: '电脑' }

前提须知:

  1. 一个URL只有一个?(取到问号右边的参数)
  2. 使用字串上的api(split), 按照'&'切开变成数组['a=1', 'b=2',...]
  3. 将数组中的每一项进行处理: 将有'='的进行切开进行[key, value] 的赋值
  4. 浏览器会对URL中文部分进行加码。 在输入http://localhost:8080/?a=电脑时。

image.png

在NetWork中看为:

image.png

实现代码:

function parseURL(urlstr) {
    let rightStr = /.+\?(.+)$/.exec(urlstr)[1];// ^匹配要检索的文本的开头,$匹配文本的结束。
    let urlArr = rightStr.split('&');
    let paramUrl = {};
    urlArr.forEach((item) => {
        if(/=/.test(item)){
            let [key, value] = item.split('=');
            value = decodeURIComponent(value);  // 进行解码
            value = /^\d+$/.test('') ? parseFloat(value) : value; // 判断是否转为数字
            if(paramUrl.hasOwnProperty(key)) {
                paramUrl[key] = [].concat([paramUrl[key], value])
            } else {
                paramUrl[key] = value
            }
        } else {
            paramUrl[item] = true
        }    
    })
    console.log(paramUrl);
}

字符串模板

题目要求:

传入let obj = { name: 'xxx', age: 13 }let str = 'my name is ${name},I am ${age}...'变成'my name is xxx,I am 13...'

实现代码:

let str = 'my name is ${name},I am ${age}...';
let obj = {
    name: 'xxx',
    age: 13
}
function render(template, obj) {
    let reg = /\$\{\w+?\}/g;   
    // \w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]
    // ?  匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。
    if(reg.test(template)) {
        Object.keys(obj).forEach((item) => {
            template = template.replace(/\$\{\w+?\}/, obj[item])
            // 这里就没有全局(/g), 只能一个一个的替代。
        })
        return template
    } else {
        return template;
    }
}
console.log(render(str,obj));

图片懒加载

题目原理:

有时候一个网页会包含很多的图片,例如淘宝京东这些购物网站,商品图片多只之又多,页面图片多,加载的图片就多。服务器压力就会很大。不仅影响渲染速度还会浪费带宽。比如一个1M大小的图片,并发情况下,达到1000并发,即同时有1000个人访问,就会产生1个G的带宽。

为了解决以上问题,提高用户体验,就出现了懒加载方式来减轻服务器的压力,优先加载可视区域的内容,其他部分等进入了可视区域再加载,从而提高性能。

实际要求:

例如: 有十个这样的, 当进入可视区域图片就会进行加载(src="./zw.jpg"为占位符, 本地的一个空白图片, 加载很多), 也就是src变成data-src

<img src="./zw.jpg" alt="" datasrc="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fi1.sinaimg.cn%2FIT%2F2010%2F0419%2F201041993511.jpg&refer=http%3A%2F%2Fi1.sinaimg.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1620099936&t=5f2884cf2b5510b9313d76a1c14a8770">

实现代码:

<script>
        let imgList = [...document.querySelectorAll('img')];
        let length = imgList.length;
        function imgLazyload() {
            let count = 0; // 有多少张照片已经加载
            return function() {
                let  deleteIndexList = [];
                imgList.forEach((img, index) => {
                    let rect = img.getBoundingClientRect()

                    if(rect.top < window.innerHeight) {
 
                        img.src = img.dataset.src;
                        deleteIndexList.push(index);
                        count++;
                        if(count === length) {
                            document.removeEventListener('scroll', imgLazyload)
                            // 当count === length时, 图片已加载完成移除事件监听;

                        }
                    }
                })
                imgList = imgList.filter((img, index) => 
                !deleteIndexList.includes(index))
                // 加载完的图片,从 imgList 移除;
            }
        }
        document.addEventListener('scroll', imgLazyload());
    </script>

详情解释:

getBoundingClientRect获取元素位置

getBoundingClientRect.(left, top, right, bottom)用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。

getBoundingClientRect是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。

window.innerHeight浏览器窗口的视口(viewport)高度(以像素为单位);如果有水平滚动条,也包括滚动条高度。

借用一张图来看看:

image.png 图片出处

后记

本文参考:

juejin.cn/post/694602…