微信小程序系列(八):页面跳转及组件传参至子组件

上一节,讲解的是抽象节点的使用,通过lin-ui的瀑布流开发作为demo

http://www.fcors.com/%e6%8a%80%e6%9c%af%e4%b8%8e%e6%a1%86%e6%9e%b6/%e5%be%ae%e4%bf%a1%e5%b0%8f%e7%a8%8b%e5%ba%8f%e7%b3%bb%e5%88%97%ef%bc%88%e4%b8%83%ef%bc%89%ef%bc%9a%e5%88%a9%e7%94%a8lin-ui%e5%92%8c%e6%8a%bd%e8%b1%a1%e8%8a%82%e7%82%b9%e7%bc%96%e5%86%99%e7%80%91/

本章节主要讲解页面跳转及父组件传参至子组件及子子组件的内容。

页面跳转

  • 在page的***.wxml中定义bind事件
  • 在page的***.js中method中定义bind的函数
  • 使用wx.navigateTo函数跳转

1、创建“ detail ”的page

基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图

2、在组件spu-preview的view中添加点击事件

2.1 修改组件的index.wxml

编辑绑定bing事件,”bing:tap”

<!--考虑到原价和折扣价的复用性,引入处理价格的wxs-->
<wxs src="../../wxs/price.wxs" module="p"></wxs>
<!--绑定事件,并设置跳转的id -->
<view bind:tap="onItemTap" data-pid="{{data.id}}" class="container">
    <!-- 设置高度自适应方法1 使用小程序官方的image方法-->
    <!--
    <image mode="widthFix" class="img" src="{{data.img}}" ></image>
    -->
    <!--方法二:动态计算宽高比 onImgLoad在组件的index.js的methods定义,切勿忘记后面的rpx   -->
    <image bing:load="onImgLoad" style="width:{{w}}rpx;height:{{h}}rpx" class="img" src="{{data.img}}"></image>
    <view class="content-container">
        <text class="tittle">{{data.tittle}}</text>
        <view class="tags">
            <!--因为tags不是每个都有,所以需要在index.js处理-->
            <block wx:for="{{tags}}">
            <!-- 注意此处使用了lin-ui的l-tag所以需要在APP.json或home.json引入组件-->
                <l-tag type="reading" class="m-tag" size="super-mini">{{item}}</l-tag>
            </block>
        </view>
        <view class="price-row">
            <!--原价和折扣价 考虑到复用性,所以使用wxs对价格进行处理-->
            <l-price
            color:='#157658'
            value-size='28'
            unit-size='20'
            autofix
            value="{{p.mainPrice(data.price,data.discount_price)}}"></l-price>
            <l-price l-class="discount-price" wx:if="{{data.discount_price?true:false}}" 
            deleted
            color='#999999'
            size="26"
            value="{{p.slashedPrice(data.price,data.discount_price)}}"></l-price>
        </view>
        <text class="subtitle">{{data.subtitle}}</text> 
    </view>
</view>
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图1

2.2 设置点击跳转事件,组件的修改index.js

点击跳转事件:wx.navigateTo

// components/spu-preview/index.js
Component({
    /** 组件的属性列表 */
    externalClasses:['m-tag'],
    properties: {
        data:Object
    },
    /*** 组件的初始数据 */
    data: {
        tags:Array
    },
    /** 数据处理,在tag转换成数据 */
    observers:{
        data:function(data){
            if(!data){
                return
            }
            if(!data.tags){
                return
            }
            const tags = data.tags.split('$')
            this.setData({
                tags:tags
            })
        }
    },
    /**
     * 组件的方法列表
     */
    methods: {
        /** 瀑布流重算高度 */
        onImgLoad(event){
            const {width,hegiht}=event.detail
            this.setData({
                w:340,
                h:340*height/width
            })
        },
        onItemTap(event){
            console.log(111);
            const pid = event.currentTarget.dataset.pid;
            wx.navigateTo({
              url: `/pages/detail/detail?pid=${pid}`,
            })

        }
    }
})
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图2

3、在page下的detail中引入组件

3.1在detail的index.wxml

<!--在detail.json中设置引用-->
<s-realm spu="{{spu}}"></s-realm>
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图3

3.1在detail的index.json

{
  "usingComponents": {
    "s-realm":"/components/realm/index"
  }
}

关于组件传参问题:父组件传参至子组件及子子组件

4、detail设置spu数据,并传输至realm组件中

下面将举例子说明

  • 定义spu.js,用于获取商品的spu列表
  • detail的onload事件调用spu.js方法,并绑定至detail.wxml
  • 通过detail.wxml传参至realm(父组件)中

4.1 在model中创建spu.js查询spu详情

import { Http } from "../../utils/http.js"
class Spu{
    static async getDetail(id){
        return await Http.request({
            url:`spu/id/${id}/detail`
        });
    }
}
export {
    Spu
}
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图4

4.2 在detail的绑定spu数据到组件中

import { Spu } from "../model/spu.js";

// pages/detail/detail.js
Page({

    /**
     * 页面的初始数据
     */
    data: {
        spu:Object
    },

    /**
     * 生命周期函数--监听页面加载
     */
    onLoad: async function (options) {
        /* 在model中创建查看spu.js 用于根据pid获取商品详情*/
        const pid = options.pid;
        const spu = await Spu.getDetail(pid)
        console.log(111)
        console.log(spu);
        console.log(222)
        this.setData({
            spu:spu
        })
        
    }
})
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图5

在detail.wxml中接收spu参数

<!--在detail.wxml中设置引用-->
<s-realm spu="{{spu}}"></s-realm>
基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图6

4.3在realm组件中处理数据,修改index.js

基础技术、小程序、技术与框架微信小程序系列(八):页面跳转及组件传参至子组件插图7

综上所述:传参至组件的方法

  • 在aaa.js的文件中,定义data参数
  • 通过调用api等方式获得数据中,进行数据绑定,setDate({})
  • 在aaa.wxml中标签行接收参数如:spu=”{{spu}}”
  • 组件的index.js中properties设置参数
  • 组件index.wxml的标签接收参数如spu=”{{spu}}”
  • 如果组件数据需要处理的话observers

思考一下以下两段代码:

this.setData({})和this.data.**=**

import { FenceGroup } from "../../pages/model/fence-group"
import { Judger } from "../../pages/model/judger"
// components/realm/index.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        spu:Object
    },

    /**
     * 组件的初始数据
     */
    data: {
        judger:Object
    },

    observers:{
        'spu':function(spu){
           
            if(!spu){
                return
            }
            const fenceGroup = new FenceGroup(spu)
            // fenceGroup.initFences()
            fenceGroup.initFences1()
            // console.log(fenceGroup)
            const judger = new Judger(fenceGroup)
            this.data.judger=judger;
            this.bingInitData(fenceGroup)
        }
    },

    /**
     * 组件的方法列表
     */
    methods: {
        bingInitData(fenceGroup){
            this.setData({
                fences:fenceGroup.fences
            })
            // console.log(fenceGroup.fences)
        },
        onCellTap(event){
            const cell = event.detail.cellA;
            
            const x = event.detail.x;
            const y = event.detail.y;
            
            // const x = event.detail.x;
            // const y = event.detail.y;
            /**设置x在realm的wxml中设置 y在fence.wxml 
             * 然后分别修改两个组件的js 赋值变量
             */
            const judger = this.data.judger
           judger.judge(cell,x,y)
            /**在judge类处理cell */
            this.setData({
                fences:judger.fenceGroup.fences
            })
        }
    }
})
// components/spu-preview/index.js
Component({
    /** 组件的属性列表 */
    externalClasses:['m-tag'],
    properties: {
        data:Object
    },
    /*** 组件的初始数据 */
    data: {
        tags:Array
    },
    /** 数据处理,在tag转换成数据 */
    observers:{
        data:function(data){
            if(!data){
                return
            }
            if(!data.tags){
                return
            }
            const tags = data.tags.split('$')
            this.setData({
                tags:tags
            })
        }
    },
    /**
     * 组件的方法列表
     */
    methods: {
        /** 瀑布流重算高度 */
        onImgLoad(event){
            const {width,hegiht}=event.detail
            this.setData({
                w:340,
                h:340*height/width
            })
        },
        onItemTap(event){
            console.log(111);
            const pid = event.currentTarget.dataset.pid;
            wx.navigateTo({
              url: `/pages/detail/detail?pid=${pid}`,
            })

        }
    }
})

如果数据必须要渲染出来,在wxml显示出来,则用this.setData({})

如果数据只在js文件中使用可以this. data赋值

5、处理分组数据

在model下分别创建realm(父组件)、fence-group.js、fence.js(子组件)、cell.js(子子组件)和matrix.js

  • fence-group.js,用于代表规格分组,被reaml调用
  • fence.js 代码规格分组的每个一个详细的内容
  • cell.js 用于fence.js中更细的配置,如数据绑定
  • martix主要适用于矩阵思维提取不同分组的规格

5.1、编写realm父组件

5.1.1编写父组件realm的wxml

<view class="container">
    <view>
        <image></image>
    </view>
    <!--创建自定义栅栏组件Fence,组件只在realm组件中引用
    所以只需要在realm的index.json中设置引入自定义组件-->
    <block wx:for="{{fences}}" wx:key="{{index}}">
        <s-fence fence="{{item}}"></s-fence>
    </block>

    <view class="counter-container">
        <!-- <l-conter></l-conter> -->
    </view>
</view>

5.1.2编写realm.json,设置引用子组件fence

{
    "component": true,
    "usingComponents": {
        "s-fence":"/components/fence/index"
    }
}

5.1.3编写realm.js

import { FenceGroup } from "../../pages/model/fence-group"

// components/realm/index.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        spu:Object
    },

    /**
     * 组件的初始数据
     */
    data: {

    },

    observers:{
        'spu':function(spu){
            if(!spu){
                return
            }
            const fenceGroup = new FenceGroup(spu)
            // fenceGroup.initFences()
            fenceGroup.initFences1()
            console.log(fenceGroup)
            this.bingInitData(fenceGroup)
        }
    },

    /**
     * 组件的方法列表
     */
    methods: {
        bingInitData(fenceGroup){
            this.setData({
                fences:fenceGroup.fences
            })
            console.log(fenceGroup.fences)
        }
    }
})

realm.wxss

/* components/realm/index.wxss */
.container{
    padding:30rpx
}

5.2、编写fence-group.js,用于代表规格分组,被reaml调用

/**fence-group.js */
import {Fence} from "./fence";
import {Matrix} from "./matrix";
class FenceGroup{
    spu
    skuList = []
    fences = []
    constructor(spu){
        this.spu=spu
        this.skuList=spu.sku_list
    }
    /** 矩阵提取规格值,方法1 */
    initFences(){
        const matrix = this._createMatrix(this.skuList)
        const fences = []
        let currentJ = -1
        matrix.each((element,i,j)=>{
            if(currentJ != j){
               //开启新的一行,需要创建一个新的fence
               currentJ = j
              fences[currentJ]=this._createFence(element)
            }
            // console.log(element.value)
            fences[currentJ].pushValueTitle(element.value) 
        })
        // console.log(fences)
        this.fences = fences
    }
    /** 矩阵提取规格值,方法2 */
    initFences1(){
        /**把数据转换成矩阵 */
        const matrix= this._createMatrix(this.skuList)
        const fences = []
        /**矩阵取值 */
        const AT = matrix.transpose()
        console.log(AT);

        AT.forEach(r =>{
            const fence = new Fence(r)
            fence.init()
            fences.push(fence)
        })
       this.fences=fences
      
    }
    _createFence(element){
        const fence = new Fence()
        return fence
    }
    _createMatrix(skuList){
        const m = []
        skuList.forEach(sku=>{
            m.push(sku.specs)
        })
        return new Matrix(m)
    }
}
export{
    FenceGroup
}

5.3编写fence.js 代码规格分组的每个一个详细的内容

/**fence.js */
import { Cell } from "./cell"
class Fence{
    cells = []
    specs
    title
    id
    
    constructor(specs){
        this.specs=specs
        this.title=specs[0].key
        this.id=specs[0].key_id
    }

    init(){
        this._initCells()
    }

    _initCells(){
        /* 遍历规格*/
        this.specs.forEach( s=>{
            
            const existed = this.cells.some( c =>{
                return c.id === s.value_id
            })
            /**判断cells中是否已经存在该规格,没有就继续实例化cell,并追加到cells */
            if(existed){
                return 
            }
            const cell = new Cell(s)
            this.cells.push(cell)
        })
    }

    pushValueTitle(title){
        this.valueTitles.push(title)
    }
}
export{
    Fence
}

5.4编写矩阵处理函数

/**matrix.js*/
class Matrix{
    m
    constructor(martix){
        this.m=martix

    }

    get rownum(){
        return this.m.length
    }

    get colsnum(){
        return this.m[0].length
    }
    /** 回调函数 */
    each(cb){
        for(let j=0;j<this.colsnum;j++){
            for(let i=0;i<this.rownum;i++){
                const element = this.m[i][j]
                cb(element,i,j)
            }
        }
    }

    transpose(){
        const desArr = []
        for(let j=0;j<this.colsnum;j++){
            desArr[j]=[]
            for(let i=0;i<this.rownum;i++){
                desArr[j][i]=this.m[i][j]
            }
        }
        return desArr
    }
}
export{
    Matrix
}

5.5编写cell处理每个cell格子

/**cell.js*/
class Cell{
    title
    id
    constructor(spec){
        this.title=spec.value
        this.id=spec.value_id
    }
}
export{
    Cell
}

6、编写子fence组件和子子cell组件

7.1fence组件代码

7.1.1 fencen组件的index.js

// components/fence/index.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        fence:Object
    },

    /**
     * 组件的初始数据
     */
    data: {

    },

    /**
     * 组件的方法列表
     */
    methods: {

    }
})

7.1.2 fencen组件的index.json

{
    "component": true,
    "usingComponents": {
        "s-cell":"../cell/index"

    }
}

7.1.3 fencen组件的index.wxml

<view class="container">
    <view class="tittle">{{fence.title}}</view>

    <view class="row-container">
        <block wx:for="{{fence.cells}}" wx:key="{{index}}">
            <s-cell class="cell" cell="{{item}}"></s-cell>
        </block>
        <view clas="hr"></view>
    </view>
</view>

7.1.4 fencen组件的index.wxss

/* components/fence/index.wxss */

.row-container{
    display:flex;
    flex-direction: row;
    align-items:center;
    flex-wrap:wrap;
}
.hr{
    width:690rpx;
    height:2rpx;
    background-color: #e9e9ee;
}
.title{
    color:#555555;
    font-size:24rpx;
    margin-top:28rpx;
    margin-bottom: 28rpx;
}

.cell{
    margin-bottom:30rpx;
    margin-right:20rpx;
}

7.2cell组件代码

7.2.1 cell组件的index.js

// components/cell/index.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        cell:Object
    },

    /**
     * 组件的初始数据
     */
    data: {

    },

    /**
     * 组件的方法列表
     */
    methods: {

    }
})

7.2.2 cell组件的 index.wxml

<view class="container">
    <view class="inner-container">
        <text>{{cell.title}}</text>
    </view>
</view>

7.2.3 cell组件的 index.wxss

/* components/cell/index.wxss */

.container{
    border:2px solid #333333
}

.inner-container{
    height:60rpx;
    padding-left:15rpx;
    padding-right:15rpx;
    display:flex;
    flex-direction: row;
    align-items: center;
    background-color: #ffffff;

}

标签UI基本完成

综上所述:组件传参,调用页传参与组件和父组件传参给子组件的方式一个。

  • 在aaa.js的文件中,定义data参数
  • 通过调用api等方式获得数据中,进行数据绑定,setDate({})
  • 在aaa.wxml中标签行接收参数如:spu=”{{spu}}”
  • 组件的index.js中properties设置参数
  • 组件index.wxml的标签接收参数如spu=”{{spu}}”
  • 如果组件数据需要处理的话observers