微信小程序|开发实战篇之九-image-picker图片选择器组件及其子组件

前言

实战篇内容参考:
1、Lin Ui开源组件源码分析。https://doc.mini.talelin.com/
2、开发过程遇到问题。

1、grid格子组件

在这里插入图片描述

分析:grid组件是一整个布局,为了使得布局具有灵活性,因此将grid中的单元也抽象出来成为grid-item组件。

1.1 grid骨架文件wxml

<view class="x-grid x-class" bind:tap="tapGrid">
    <view 
        bind:tap="tapGridItem"
        data-grid-index="{{item.index}}"
        class="x-grid-item x-class-grid x-grid-class {{index%rowNum !== rowNum-1 &&(showBorder||showColBorder) ? 'side-grid':''}} {{(index<gridItems.length-(gridItems.length%rowNum||rowNum)) &&(showBorder||showRowBorder)? 'center-grid':''}}" wx:for="{{gridItems}}" wx:key="key"
        style="min-width:{{100/rowNum}}%;"
    >
        <slot name="{{item.key}}"></slot>
    </view>
</view>

为了在grid布局中添加新组件,因此就在view标签之间使用slot插槽。为整体的grid添加tapGrid监听事件,每一个grid-item添加tapGridItem监听事件。

1.2 grid的js文件分析

编写跟grid-item的父子组件关系,并触发initGrids函数。

relations: {
    '../grid-item/index': {
      type: 'child',
      // 关系建立在页面节点树时触发initGrids函数
      linked() {
        this.initGrids();
      },
      unlinked() {
        this.initGrids();
      }
    },
  },
 // 初始化子组件数据,组件序号index、编号key、内容cell
    initGrids() {
      // 1、获取所有的子组件节点items
      let items = this.getRelationNodes('../grid-item/index');
      // 子节点个数不变 不需要更新
      if (this.data.childNum === items.length) return;
      // 2、js语法通过map 获取数据对象 数组
      const gridItems = items.map((item, index) => {
        item.setData({
          index,
        });
       
        return {
          index:index,
          key: item.data.key,
          cell: item.data.cell
        };
      });

      // 页面渲染grid-item数据
      this.setData({
        gridItems: gridItems,
        childNum: items.length
      });
    },

给grid整体和grid-item都添加监听事件,这样就能够提供自定义定制功能。

 // 点击grid-item
 // 获取当前排列的index,并以该index从gridItem[]中获取数据
 // data-grid-index="{{item.index}}"
 tapGridItem(e) {
   // console.log(e.target.dataset);
   const { gridIndex } = e.target.dataset;
   this.setData({
     currentIndex: gridIndex,
     currentCell: this.data.gridItems[gridIndex].cell
   });
 },

 // 点击grid整体
 tapGrid() {
   this.triggerEvent('gridtap', {
     index: this.data.currentIndex,
     cell: this.data.currentCell
   }, { bubbles: true, composed: true });

   // 重置当前item
   this.setData({
     currentIndex: -1,
     currentCell: -1
   });
 }

1.3 grid-item的wxml文件分析

使用viewhover-属性,使用isHover控制grid-item的点击事件,添加tap事件“tapGridItem

<view
  hover-class="{{isHover?'x-grid-item-hover':''}}"
  hover-start-time="20"
  hover-stay-time="50"
  class="x-grid-item x-grid-item-class grid-item"
  mut-bind:tap="tapGridItem"
  >
  <slot />
</view>

hover-class决定点击事件时,对grid-item进行半透明处理。

1.4 grid-item的wxss文件分析

每个grid-item添加布局

.grid-item {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  padding: 32rpx 16rpx;
  box-sizing: border-box
}

.x-grid-item-hover {
  /* 透明度0.5 */
  opacity: .5
}

1.5 grid在页面中的使用

index.wxml

<x-grid x-class="grid" show-border="{{true}}">
    <x-grid-item 
      bind:griditemtap="clickGrid" wx:for="{{grids1}}" wx:key="{{index}}" key="{{index}}" slot="{{index}}"
      cell="{{item}}" >
        <x-icon name="{{item.image}}" />
        <view class="text">{{item.text}}</view>
    </x-grid-item>
  </x-grid>

index.js

 clickGrid(event) {

  // console.log(event);
  wx.showToast({
    title: event.detail.cell.text,
    icon: 'none'
  }); 
  
 },

2、image-picker图片选择组件

选择需要的图片上传,可自定义上传图片的数量。在这里插入图片描述

image-picker的wxml文件:

<!--components/image-picker/index.wxml-->
<!-- 图片 -->
<x-grid row-num="{{ size }}" x-class="x-class">
  <x-grid-item wx:for="{{ urls }}" wx:key="index" key="{{ index }}" slot="{{ index }}" x-grid-item="x-grid-item">
    <view class="item x-item-class" catchtap="onPreviewTap" data-index="{{ index }}">
      <view class="close" data-index="{{ index }}" catchtap="onDelTap">
        <x-icon name="close" color="#fff" size="22" x-class="close-icon" />
      </view>
      <image class="{{size === 3? 'img': 'min-img'}}" mode="{{ mode }}" src="{{newOrOld==='old'? item:item.url }}" />
    </view>
  </x-grid-item>
  <!-- add 按钮 -->
  <x-grid-item wx:if="{{ showBtn }}" x-grid-item="x-grid-item">
    <!-- 自定义图片选择按钮 -->
    <view class="item x-item-class {{size === 3? 'img': 'min-img'}}" catchtap="onAddTap" wx:if="{{ custom }}">
      <slot></slot>
    </view>
    <view class="item x-item-class {{size === 3? 'img': 'min-img'}}" catchtap="onAddTap" wx:else>
      <image class="add-icon" src="./image/add.png" />
    </view>
  </x-grid-item>
</x-grid>

思路主要是使用grid格子布局将图片通过wx:for="{{ urls }}"展示出来,然后有add添加按钮,进行添加图片。
主要分析下preview预览图片函数,使用urlscells区分两种图片的链接,一种是字符串数组,一种是字符串对象数组。然后在组件初始化时,使用变量newOrOld变量区分两种链接类型,预览时根据对cells数组的判断,newOrOld是否为old进行判断,然后将不同结构中存储的url放入previewImgList[]数组中去,再调用wx.previewImage()预览图片。

// 点击预览图片 preview
 onPreviewTap(e) {
   // 当前图片索引 data-index
   const index = e.currentTarget.dataset.index;
   // urls = 'http://...'类似的地址数组
   const urls = this.data.urls;
   let tempFilePath = '';
   // 预览list是字符串数组
   let previewImageList = [];
   const newOrOld = this.data.newOrOld;
   const cellsIsObject = Object.prototype.toString.call(this.data.cells) === '[object Object]';

   // 第一个 if 是对 cells 的兼容处理
   // 如果cells是object对象
   if (cellsIsObject) {
     const cells = this.data.cells;
     tempFilePath = cells[index].url;
     for (let i = 0; i < cells.length; i++) {
       previewImageList.push(cells[i].url);
     }
   } else if (newOrOld === 'old') {
     // old urls是字符串数组
     tempFilePath = this.data.urls[index];
     previewImageList = this.data.urls;

   } else {
     // cells中不是object,newOrOld === 'new'...
     // url中存的url是object对象
     tempFilePath = this.data.urls[index].url;
     for (let i = 0; i < urls.length; i++) {
       previewImageList.push(urls[i].url);
     }
   }

   // 因为wx预览图片需要当前图片和预览图片组,所以每次点击预览时生成previewImageList

   let detail = {
     index, // 下标
     current: urls[index], // 当前显示图片的http链接
     all: urls // 需要预览的图片http链接列表
   };
   let option = {};
   if (this.data.preview === true) {
     wx.previewImage({
       current: tempFilePath, // 当前显示图片的http链接
       urls: previewImageList // 需要预览的图片http链接列表
     });
   }
   // 传递给父组件 当前显示的图片等数据
   this.triggerEvent('imgpreview', detail, option);

 },
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值