微信小程序之如何使用自定义组件封装原生 image 组件

零、问题的由来

一般在前端展示图片时都会碰到这两个常见的需求:

  1. 图片未加载完成时先展示占位图,等到图片加载完毕后再展示实际的图片。
  2. 假如图片链接有问题(比如 404),依然展示占位图。甚至你还可以增加点击图片再次加载的功能。(例如知乎)

然鹅,小程序原生组件 image 并没有提供这些常用功能…

 

(此图片来源于网络,如有侵权,请联系删除! )

 

注:这里加了 2s 的延迟

一、常规操作

在小程序没还没推出自定义组件功能时,只能通过改变 Page 中的 data 来展示兜底的占位图,所以当时的处理方式十分蛋疼…

1.1.相同默认图

由于需要知道这个图片的数据路径,所以不得不在每个 image 上加上类似 data-img-path 的东西。

<view
    wx:for="{{ obj.arr }}"
    wx:key="imgSrc"
    wx:for-item="item"
    wx:for-index="itemIdx"
>
    <image
        src="{{%20item.imgSrc%20}}"
        binderror="onImageError"
        data-img-path="obj.arr[{{ itemIdx }}].imgSrc"
    />
</view>
复制代码
const DEFAULT_IMG = '/assets/your_default_img'

Page({
    data: {
        obj: {
            arr: [
                { imgSrc: 'your_img1' },
                { imgSrc: 'your_img2' },
            ],
        },
    },
    onImageError ({
        target: { dataset: { imgPath } },
    }) {
        this.setData({
            [imgPath]: DEFAULT_IMG,
        })
    },
})
复制代码

1.2.不同默认图

如果默认图片不同呢?例如球员、球队和 feed 的默认图片一般都是不同的。

那么一般只好再增加一个属性例如 data-img-type 来标识默认图的类型。

<!-- 球队图 -->
<image
    ...
    data-img-type="team"
/>
<!-- 球员图 -->
<image
    ...
    data-img-type="player"
/>
复制代码
const DEFAULT_IMG_MAP = {
    feed: '/assets/default_feed',
    team: '/assets/default_team',
    player: '/assets/default_player',
}

Page({
    data: {
        obj: {
            arr: [
                { imgSrc: 'your_img1' },
                { imgSrc: 'your_img2' },
            ],
        },
    },
    onImageError ({
        target: { dataset: { imgPath, imgType } },
    }) {
        this.setData({
            [imgPath]: DEFAULT_IMG_MAP[imgType],
        })
    },
})
复制代码

1.3.图片在模板中

页面层级浅倒还好,如果跨模板了,那么模板就可能要用一个类似于 pathPrefix 的属性来传递模板数据的路径前缀。

<!--
    球员排行模板
    pathPrefix: String
    playerList: Array
    ...
-->
<template name="srPlayerRank">
    <view
        wx:for="{{ playerList }}"
        wx:key="imgSrc"
        wx:for-item="item"
        wx:for-index="itemIdx"
    >
        <image
            src="{{%20item.imgSrc%20}}"
            binderror="onImageError"
            data-img-type="player"
            data-img-path="{{ pathPrefix }}.playerList[{{ itemIdx }}].imgSrc"
        />
    </view>
</template>
复制代码

最后在失败回调里调用 setData({ [path]: DEFAULT_IMG }) 重新设置图片地址。

就问你蛋不蛋疼?这一坨 data-img-path=”{{ pathPrefix }}.playerList[{{ itemIdx }}].imgSrc” 代码真让人无发可脱…

 

(此图片来源于网络,如有侵权,请联系删除! )

 

二、自定义组件

有了自定义组件后,用领袖【窃·格瓦拉】的话来说的话就是:“感觉好 door 了~”

(此图片来源于网络,如有侵权,请联系删除! )

2.1.原生自定义组件

原生写法一般要写4个文件:.json/.wxml/.js/.wxss

  • TuaImage.json
{
    "component": true
}
复制代码
  • TuaImage.wxml
<!-- 加载中的图片 -->
<image
    hidden="{{ !isLoading }}"
    src="{{%20errSrc%20}}"
    style="width: {{ width }}; height: {{ height }}; {{ styleStr }}"
    mode="{{ imgMode }}"
/>


<!-- 实际加载的图片 -->
<image
    hidden="{{ isLoading }}"
    src="{{%20imgSrc%20||%20src%20}}"
    mode="{{ imgMode }}"
    style="width: {{ width }}; height: {{ height }}; {{ styleStr }}"
    bindload="_onImageLoad"
    binderror="_onImageError"
    lazy-load="{{ true }}"
/>
复制代码
  • TuaImage.js
const DEFAULT_IMG = '/assets/your_default_img'

Component({
    properties: {
        // 图片地址
        src: String,
        // 图片加载中,以及加载失败后的默认地址
        errSrc: {
            type: String,
            // 默认是球队图标
            value: DEFAULT_IMG,
        },
        width: {
            type: String,
            value: '48rpx',
        },
        height: {
            type: String,
            value: '48rpx',
        },
        // 样式字符串
        styleStr: {
            type: String,
            value: '',
        },
        // 图片裁剪、缩放的模式(详见文档)
        imgMode: {
            type: String,
            value: 'scaleToFill',
        },
    },
    data: {
        imgSrc: '',
        isLoading: true,
    },
    methods: {
        // 加载图片出错
        _onImageError (e) {
            this.setData({
                imgSrc: this.data.errSrc,
            })
            this.triggerEvent('onImageError', e)
        },
        // 加载图片完毕
        _onImageLoad (e) {
            this.setData({ isLoading: false })
            this.triggerEvent('onImageLoad', e)
        },
    },
})
复制代码

布吉岛大家使用原生写法时有木有一些感觉不方便的地方:

  • 4个文件:.json/.wxml/.js/.wxss,这样老需要切来切去的降低效率
  • properties 是什么鬼?大家(React/Vue)一般不都用 props 么?
  • style=”width: {{ width }}; height: {{ height }}; {{ styleStr }}” 样式字符串怎么辣么长…

2.2.TuaImage.vue

所以以下是一个使用单文件组件封装原生 image 组件的例子。

  • 使用单文件组件将配置、模板、脚本、样式写在一个文件中,方便维护。
  • 使用计算属性 computed 将样式字符串写在 js 中。
  • 使用 this.imgSrc = this.errSrc 而不是 this.setData 来改变 data。
<config>
{
    "component": true
}
</config>

<template lang="wxml">
    <!-- 加载中的图片 -->
    <image
        hidden="{{ !isLoading }}"
        src="{{%20errSrc%20}}"
        style="{{ imgStyleStr }}"
        mode="{{ imgMode }}"
    />

    <!-- 实际加载的图片 -->
    <image
        hidden="{{ isLoading }}"
        src="{{%20imgSrc%20||%20src%20}}"
        mode="{{ imgMode }}"
        style="{{ imgStyleStr }}"
        bindload="_onImageLoad"
        binderror="_onImageError"
        lazy-load="{{ true }}"
    />
</template>

<script>
/**
 * 图片组件,能够传递备用图片以防图片失效
 * https://developers.weixin.qq.com/miniprogram/dev/component/image.html
 */

// 也可以设置为网络图片如: https://foo/bar.png
const DEFAULT_IMG = '/assets/your_default_img'

export default {
    props: {
        // 图片地址
        src: String,
        // 图片加载中,以及加载失败后的默认地址
        errSrc: {
            type: String,
            // 默认是球队图标
            default: DEFAULT_IMG,
        },
        width: {
            type: String,
            default: '48rpx',
        },
        height: {
            type: String,
            default: '48rpx',
        },
        // 样式字符串
        styleStr: {
            type: String,
            default: '',
        },
        // 图片裁剪、缩放的模式(详见文档)
        imgMode: {
            type: String,
            default: 'scaleToFill',
        },
    },
    data () {
        return {
            imgSrc: '',
            isLoading: true,
        }
    },
    computed: {
        // 样式字符串
        imgStyleStr () {
            return `width: ${this.width}; height: ${this.height}; ${this.styleStr}`
        },
    },
    methods: {
        // 加载图片出错
        _onImageError (e) {
            this.imgSrc = this.errSrc
            this.$emit('onImageError', e)
        },
        // 加载图片完毕
        _onImageLoad (e) {
            this.isLoading = false
            this.$emit('onImageLoad', e)
        },
    },
}
</script>

<style lang="scss">

</style>

免责声明:本站所有文章和图片均来自用户分享和网络收集,文章和图片版权归原作者及原出处所有,仅供学习与参考,请勿用于商业用途,如果损害了您的权利,请联系网站客服处理。

【小程序源码网资源版权风险说明】:
本站为避免不必要的纷争,分享的所有资源中一切可能有版权风险的资源将全部转载自第三方网站或平台,站长只为大家提供相关资源的介绍和跳转引导。 因可能有疏忽大意,所以如有遗漏资源侵犯了您的合法权利,请联系站长删除。
【小程序源码网资源下载使用说明】:
本站所分享的一切QQ小程序源码,thinkphp整站源码,微信小程序源码,图文教程等资源仅供用户学习参考使用,任何人不得作其他用途,违者自行承担所有责任。
【小程序源码网毫无人看的介绍】:
本站又称Z站,原名贼娘网,开站于2018年,换过三任站长,目前站长是第四任站长,本站是一个主要分享免费开源小程序源码/网站源码/免费素材/教程资源的网站,主要小程序资源有用于学习的小程序源码,也有正版原创可商用的小程序源码,是一个公益博客型网站。
【小程序源码网原创源码版权申明】:
未经小程序源码网许可,任何人不得擅自使用本站原创首发源码进行商业行为(除本站VIP用户在期限内,版权无使用限制),否则将依法承担相应赔偿责任。
【小程序源码网转载文章版权申明】:
本站所转载的QQ小程序或微信小程序源码与其他资源仅供学习,任何人不得作其他用途,违者自行承担所有责任。
【小程序源码网站长最后的屁话】:
如有您认为本站有任何侵犯您合法权益的文章,或者您有什么疑问需求,欢迎联系站长QQ,站长24小时在线,备注公司名称和源码版权问题或者需要小程序定制开发等站长业务类型可急速处理,如果您只是交流小程序的一些开发问题或源码问题可以加入QQ群讨论,就不用加站长啦,对于白嫖党,QQ群才是处理问题的天堂,当然站长也欢迎大家骚扰~
小程序源码网 » 微信小程序之如何使用自定义组件封装原生 image 组件
嘿,投喂下嘛!