No1 Document concept section

Applets official documentation for abstract nodes

The difference between slots and abstract nodes is in granularity. Slots, you just need to write the HTML snippet. Abstract nodes, however, require programmers to define their own components.

So abstract components are more flexible than slots! Because it leaves the choice up to us, we define the style of the memory node, abstract the node to do the logic processing inside the line!

No2 core algorithm

The algorithm is actually pretty simple, and the algorithm THAT I implemented myself was, according to index, odd on one side and even on the other.

<view class="water-flow-container" wx:if="{{data.length! = = 0}}">
  <view id="left">
    <block wx:for="{{Object}}" wx:if={{index%2=0}} wx:key="index"></block>
  </view>
  <view class="water-column">
    <view id="right" >
    <block wx:for="{{Object}}" wx:if={{index%2=1}} wx:key="index"></block>
    </view>
  </view>
</view>
Copy the code

But this is actually very unreasonable! It’s easier to keep one side long and the other short.

We want to add data to leftData and rightData, respectively, based on the height of the left node and the right node.

// Get the height of the nodes with ids left and right
const a=wx.createSelectorQuery().in(this);
this.columnNodes=a.selectAll("#left, #right")
this.columnNodes.boundingClientRect().exec(h= >{
    const r=h[0]
    this.data.leftHeight=r[0].height, 
    this.data.rightHeight=r[1].height
    console.log(r[0].height,r[1].height)
}
Copy the code
// Add the shorter side to the shorter side
this.data.leftHeight > this.data.rightHeight ?
this.data.rightData.push(data[e]):
this.data.leftData.push(data[e]),
this.setData({
  rightData: this.data.rightData,
  leftData: this.data.leftData
})
Copy the code

Now, notice that this is definitely going to be traversal, node by node, but you can’t use a For loop, because For is going to trigger all of these blocks at about the same time. We must wait for the view layer to render successfully before adding new data!!

At this point in time in the second parameter of setData, there is a callback function!

this.setData({
          rightData: this.data.rightData,
          leftData: this.data.leftData
},() = >{
  // Then loop
  fun()
})
Copy the code

So we can just write it as a recursion!

 _render(data,e){
   data.length>e 
   && 0! = =this.data.Object.length 
   && this.columnNodes.boundingClientRect().exec(h= >{
    const r=h[0]
    this.data.leftHeight=r[0].height, this.data.rightHeight=r[1].height
    this.data.leftHeight > this.data.rightHeight ?
    this.data.rightData.push(data[e]):
    this.data.leftData.push(data[e]),
    this.setData({
      rightData: this.data.rightData,
      leftData: this.data.leftData
    },() = >{
      this._render(data,++e)
    })
  })
}
Copy the code

No3 specific code

1. Create an abstract component

// components/water-flow/index.wxml
<view class="water-flow-container" wx:if="{{data.length! = = 0}}">
  <view class="water-column" style="margin-right:{{columnGap}}">
    <view id="left" >
    <block wx:for="{{leftData}}" wx:key="index">
      <water-flow-item data="{{item}}"></water-flow-item>
    </block>
    </view>
  </view>
  <view class="water-column">
    <view id="right" >
    <block wx:for="{{rightData}}" wx:key="index">
      <water-flow-item  data="{{item}}"></water-flow-item>
    </block>
    </view>
  </view>
</view>
Copy the code
// components/water-flow/index.json
{
  "component": true."componentGenerics": {
    "water-flow-item": true}}Copy the code
// components/water-flow/index.wxss
.water-flow-container{
  display:flex;
  width:100%;
  box-sizing:border-box;
  background:0 0
}
.water-column{flex:1}
Copy the code
// components/water-flow/index.js
Component({
  properties: {
    Object: Object.columnGap: {
      type: String.value: '15rpx'}},data: {
    leftData: [].rightData:[]
  },

  attached(){this._init()},

  methods: {
    _init(){
      this._select()
    },

    _select(){
      const a=wx.createSelectorQuery().in(this);
      this.columnNodes=a.selectAll("#left, #right")
      this._render(this.data.Object,0)},_render(data,e){
       data.length>e 
       && 0! = =this.data.Object.length 
       && this.columnNodes.boundingClientRect().exec(h= >{
        const r=h[0]
        this.data.leftHeight=r[0].height, this.data.rightHeight=r[1].height
        this.data.leftHeight > this.data.rightHeight ?
        this.data.rightData.push(data[e]):
        this.data.leftData.push(data[e]),
        this.setData({
          rightData: this.data.rightData,
          leftData: this.data.leftData
        },() = >{
          this._render(data,++e)
        })
      })
    }
  }
})
Copy the code

2. Create our custom water-item

// components/water-item/index.wxml
<view class="life-container">
  <image class="life-img" src="{{data.image}}" mode='widthFix'/>
</view>
Copy the code
// components/water-item/index.wxss
.life-container {
  box-shadow: 0px 8rpx 20rpx 0px rgba(9.36.66.0.04) !important;
  margin: 0 0 17rpx 0;
  padding: 0 0 100rpx 0; border-radius: 16rpx ! important; width: 355rpx ! important; background-color: white ! important; } .life-img { border-radius: 16rpx 16rpx0 0! important; width: 355rpx ! important; }Copy the code
// components/water-item/index.js
properties: {
   data:Object
},
Copy the code

3. Page references

// pages/index/index.wxml
<view style="margin: 13rpx 14rpx 0 14rpx">
  <water-flow generic:water-flow-item="water-item" Object="{{demo}}"/>
</view>
Copy the code
// pages/index/index.js
/ / data
Page({
  data: {
    demo:[
      {
        image: 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/16ab3222427f4201bf0e069098a38c57~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '111111'.count: '888'.delCount: '666'}, {image: 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/273dc740d51d419c86b6d8ffb9c51250~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '22222222'.count: '888'.delCount: '666'}, {image: 'https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c955cfd0598a4825907aa4e8122ba754~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '333333333'.count: '888'.delCount: '666'
    }
    ,{
      image: 'https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/0b6b701c6d6d4c60b87b84b99a132541~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '333333333'.count: '888'.delCount: '666'
    },
    {
      image: 'https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/febff6310a5f41a0b8e7ad14c485ed28~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '333333333'.count: '888'.delCount: '666'
    },
    {
      image: 'https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7c3f4a83e30a47d791c1fbd8ae6f6783~tplv-k3u1fbpfcp-watermark.image'.title: 'Slimming medium length strappy trench coat'.describe: '333333333'.count: '888'.delCount: '666'}]}})Copy the code