上一节,讲解的是抽象节点的使用,通过lin-ui的瀑布流开发作为demo
本章节主要讲解页面跳转及父组件传参至子组件及子子组件的内容。
菜单
页面跳转
- 在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>
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}`,
})
}
}
})
3、在page下的detail中引入组件
3.1在detail的index.wxml
<!--在detail.json中设置引用-->
<s-realm spu="{{spu}}"></s-realm>
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.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
})
}
})
在detail.wxml中接收spu参数
<!--在detail.wxml中设置引用-->
<s-realm spu="{{spu}}"></s-realm>
4.3在realm组件中处理数据,修改index.js
综上所述:传参至组件的方法
- 在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