响应式,在PC、手机端显示响应图片,js图片懒加载,占位符

303 阅读2分钟

1.picture

根据屏幕匹配的不同尺寸显示不同图片,如果没有匹配到或浏览器不支持 picture 属性则使用 img 元素

        <picture>
            <source media="(max-width:750px)" srcset="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa8a465887b744629fc8d509f04ddee0~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp" >
            <img src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/496767f91dd44ee1a427c4423007537b~tplv-k3u1fbpfcp-zoom-mark-crop-v2:240:240:0:0.awebp">
        </picture>

2. js图片懒加载

data-srcset data-src放入正常显示的图片; 在srcset src 放入一张loading图片,来代替网络还未加载正常图片前的页面空白。

    <picture>
        <source media="(max-width:750px)" srcset="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a05115a403f4a0c866993e4d7291f88~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp" data-srcset="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa8a465887b744629fc8d509f04ddee0~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp">
        <img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a05115a403f4a0c866993e4d7291f88~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp" data-src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/496767f91dd44ee1a427c4423007537b~tplv-k3u1fbpfcp-zoom-mark-crop-v2:240:240:0:0.awebp" alt="">
    </picture>
        
    let images = document.querySelectorAll('[data-src],[data-srcset]');
    let observer = new IntersectionObserver(entries => {
        entries.forEach(item => {
            if (item.isIntersecting) {
                if (item.target.dataset.src) {
                    item.target.src = item.target.dataset.src;
                }
                if (item.target.dataset.srcset) {
                    item.target.srcset = item.target.dataset.srcset;
                }
                observer.unobserve(item.target); // 停止监听已开始加载的图片
            }
        });
    }, {rootMargin: "0px 0px 200px 0px"});
    images.forEach(item => observer.observe(item));

3. 占位符以及响应式适配

在写响应式适配时,图片、文字(即图片可以当背景图,上面有文字)同时需要响应式。我这里用到的是——定位,外层裹一个div,里面放 图片、文字进行定位。

这里的图片假设本身的宽高是 1400 x 1000; loading的图片假设本身的宽高是 240 x 240;

<style>
.box-big{
    max-width: 1400px;
    width: 100%;
    position: relative;
}
.box-big img {
    max-width: 100%;
    display: block;
    margin: 0 auto;
}
.box-big .box-title {
     position: absolute;
    left: 10%;
    top: 8%;
    z-index: 33;
}
</style>
    <div class="box-big">
        <picture>
            <source media="(max-width:750px)" srcset="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a05115a403f4a0c866993e4d7291f88~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp" data-srcset="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/fa8a465887b744629fc8d509f04ddee0~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp">
            <img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a05115a403f4a0c866993e4d7291f88~tplv-k3u1fbpfcp-zoom-mark-crop-v2:460:460:0:0.awebp" data-src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/496767f91dd44ee1a427c4423007537b~tplv-k3u1fbpfcp-zoom-mark-crop-v2:240:240:0:0.awebp" alt="">
        </picture>
        <div class="box-title">
            <h3>title</h3>
            <P>words</P>
            <P>words</P>
            <P>words</P>
            <P>words</P>
        </div>
    </div>

这样会有一个问题,当网络迟迟加载不出原本的图片,而loading图片的高度只有240,远远撑不起原本高度的样式;当好几个loading累加在一起会出现一团乱麻。

解决:办法有很多,比如给一张同样的高度是1000 的loading 图即可。

我这里的是用js,当是loading图时,则把外层的div的高度设置为1000;相反当不是loading图时,则把外层div的高度设置为auto。

        let images = document.querySelectorAll('[data-src],[data-srcset]');
        let observer = new IntersectionObserver(entries => {
            entries.forEach(item => {
                if (item.isIntersecting) {
                    if (item.target.dataset.src) {
                        item.target.src = item.target.dataset.src;
                        const parentDom = item.target.parentNode.parentNode
                        if (parentDom.dataset.minHeight === '1') {
                            const img = new Image()
                            img.src = item.target.src
                            img.onload = () => {
                                parentDom.style.minHeight = 'auto'   // 把外层div的高度设置为auto
                                parentDom.dataset.minHeight = '0'    // 标记设置回 0 
                            }
                        }
                    }
                    if (item.target.dataset.srcset) {
                        item.target.srcset = item.target.dataset.srcset;
                        const parentDom = item.target.parentNode.parentNode
                        if (parentDom.dataset.minHeight === '1') {
                            const img = new Image()
                            img.src = item.target.src
                            img.onload = () => {
                                parentDom.style.minHeight = 'auto'
                                parentDom.dataset.minHeight = '0'
                            }
                        }
                    }
                    observer.unobserve(item.target); // 停止监听已开始加载的图片
                }
            });
        }, {rootMargin: "0px 0px 200px 0px"});
        images.forEach(item => observer.observe(item));

        let bigImg = document.querySelectorAll('.box-big')
        let samllImg = document.querySelectorAll('.box-samll')
        function lazyload(arr,val) {
            arr = [...arr]
            arr.forEach((item) => {
                let isGif = (item.querySelector('img') && item.querySelector('img').src.includes('2205/photo/0bcda4d0d7')) || false
                if (isGif) {
                    item.style.minHeight = val
                    item.dataset.minHeight = '1'
                } else {
                    item.style.minHeight = 'auto'
                    item.dataset.minHeight = '0'
                }
            })
        }
        lazyload(bigImg,'1000px')
        lazyload(samllImg,'700px')

最后延申一个点:当图片设置为背景图时,背景图进行懒加载

// html里面的img的占位符——  data-src
    <div class="b-Big">
        <div class="b-Img"><img src="loading.gif" data-src="./img/content-product-mark.jpg" alt=""></div>
        <div class="b-Words">
            <p>Words</p>
            <p>Words</p>
            <p>Words"</p>
        </div>
    </div>
<style>
// 在css样式中的背景图进行懒加载——  data-bgsrc
.box-bg {
    width:100%;
    height: 500px;
    background: url("./img/loading.gif");
    background-size: 240px;
    background-repeat: no-repeat!important;
    background-position: center!important;
}
</style>
    <div class="box-bg" data-bgsrc="./img/content-product-rearLight-bg.jpg">
        <div class="bikeEb-title">
            <h3>title</h3>
            <p>Words</p>
            <p>Words</p>
        </div>
    </div>
// js 代码
    let images = document.querySelectorAll('[data-src],[data-bgsrc]');
    let observer = new IntersectionObserver(entries => {
        entries.forEach(item => {
            if (item.isIntersecting) {
                if (item.target.dataset.src) {
                    item.target.src = item.target.dataset.src;
                }
                console.log(item.target.dataset.bgsrc)
                if (item.target.dataset.bgsrc) {
                    item.target.style.background = `url(${item.target.dataset.bgsrc})`;
                    item.target.style.backgroundSize = '100%'
                }
                observer.unobserve(item.target); // 停止监听已开始加载的图片
            }
        });
    }, {rootMargin: "0px 0px 200px 0px"});
    images.forEach(item => observer.observe(item));