效果图:
*
1.在components组件里引入drag文件夹,依次引入index.js,index.json,index.wxml,index.wxss
引入index.js
/**
* 判断是否超出范围
*/
const IsOutRange = (x1, y1, x2, y2, x3, y3) => {
return x1 < 0 || x1 >= y1 || x2 < 0 || x2 >= y2 || x3 < 0 || x3 >= y3
};
/**
* 版本号比较
*/
const compareVersion = (v1, v2) => {
v1 = v1.split('.')
v2 = v2.split('.')
const len = Math.max(v1.length, v2.length)
while (v1.length < len) {
v1.push('0')
}
while (v2.length < len) {
v2.push('0')
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(v1[i])
const num2 = parseInt(v2[i])
if (num1 > num2) {
return 1
} else if (num1 < num2) {
return -1
}
}
return 0
}
Component({
options: {
multipleSlots: true
},
properties: {
beforeExtraNodes: {type: Array, value: []}, // 插入正常节点之前的额外节点
afterExtraNodes: {type: Array, value: []}, // 插入正常节点之后的额外节点
listData: {type: Array, value: []}, // 数据源
columns: {type: Number, value: 1}, // 列数
topSize: {type: Number, value: 0}, // 顶部高度
bottomSize: {type: Number, value: 0}, // 底部高度
scrollTop: {type: Number, value: 0} // 页面滚动高度
},
data: {
/* 未渲染数据 */
pageMetaSupport: false, // 当前版本是否支持 page-meta 标签
windowHeight: 0, // 视窗高度
platform: '', // 平台信息
realTopSize: 0, // 计算后顶部固定高度实际值
realBottomSize: 0, // 计算后底部固定高度实际值
rows: 0, // 行数
itemDom: {width: 0, height: 0, left: 0, top: 0}, // 每一项 item 的 dom 信息, 由于大小一样所以只存储一个
itemWrapDom: {width: 0, height: 0, left: 0, top: 0}, // 整个拖拽区域的 dom 信息
startId: 0, // 初始触摸点 identifier
preStartKey: -1, // 前一次排序时候的起始 sortKey 值
/* 渲染数据 */
list: [], // 渲染数据列
cur: -1, // 当前激活的元素
curZ: -1, // 当前激活的元素, 用于控制激活元素z轴显示
tranX: 0, // 当前激活元素的 X轴 偏移量
tranY: 0, // 当前激活元素的 Y轴 偏移量
itemWrapHeight: 0, // 动态计算父级元素高度
dragging: false, // 是否在拖拽中
itemTransition: false, // item 变换是否需要过渡动画, 首次渲染不需要
},
methods: {
/**
* 长按触发移动排序
*/
longPress(e) {
// 获取触摸点信息
let startTouch = e.changedTouches[0];
if (!startTouch) return;
// 固定项则返回
let index = e.currentTarget.dataset.index;
if (this.isFixed(index)) return;
// 防止多指触发 drag 动作, 如果已经在 drag 中则返回, touchstart 事件中有效果
if (this.data.dragging) return;
this.setData({dragging: true});
let {platform, itemDom, itemWrapDom} = this.data,
{pageX: startPageX, pageY: startPageY, identifier: startId} = startTouch;
// 计算X,Y轴初始位移, 使 item 中心移动到点击处
let tranX = startPageX - itemDom.width / 2 - itemWrapDom.left,
tranY = startPageY - itemDom.height / 2 - itemWrapDom.top;
// 单列时候X轴初始不做位移
if (this.data.columns === 1) tranX = 0;
this.data.startId = startId;
this.setData({cur: index, curZ: index, tranX, tranY});
if (platform !== "devtools") wx.vibrateShort();
},
touchMove(e) {
// 获取触摸点信息
let currentTouch = e.changedTouches[0];
if (!currentTouch) return;
if (!this.data.dragging) return;
let {pageMetaSupport, windowHeight, realTopSize, realBottomSize, itemDom, itemWrapDom, preStartKey, columns, rows} = this.data,
{pageX: currentPageX, pageY: currentPageY, identifier: currentId, clientY: currentClientY} = currentTouch;
// 如果不是同一个触发点则返回
if (this.data.startId !== currentId) return;
// 通过 当前坐标点, 初始坐标点, 初始偏移量 来计算当前偏移量
let tranX = currentPageX - itemDom.width / 2 - itemWrapDom.left,
tranY = currentPageY - itemDom.height / 2 - itemWrapDom.top;
// 单列时候X轴初始不做位移
if (columns === 1) tranX = 0;
// 到顶到底自动滑动
if (currentClientY > windowHeight - itemDom.height - realBottomSize) {
// 当前触摸点pageY + item高度 - (屏幕高度 - 底部固定区域高度)
if (pageMetaSupport) {
this.triggerEvent("scroll", {
scrollTop: currentPageY + itemDom.height - (windowHeight - realBottomSize)
});
} else {
wx.pageScrollTo({
scrollTop: currentPageY + itemDom.height - (windowHeight - realBottomSize),
duration: 300
});
}
} else if (currentClientY < itemDom.height + realTopSize) {
// 当前触摸点pageY - item高度 - 顶部固定区域高度
if (pageMetaSupport) {
this.triggerEvent("scroll", {
scrollTop: currentPageY - itemDom.height - realTopSize
});
} else {
wx.pageScrollTo({
scrollTop: currentPageY - itemDom.height - realTopSize,
duration: 300
});
}
}
// 设置当前激活元素偏移量
this.setData({tranX: tranX, tranY: tranY});
// 获取 startKey 和 endKey
let startKey = parseInt(e.currentTarget.dataset.key);
let curX = Math.round(tranX / itemDom.width), curY = Math.round(tranY / itemDom.height);
let endKey = curX + columns * curY;
// 遇到固定项和超出范围则返回
if (this.isFixed(endKey) || IsOutRange(curX, columns, curY, rows, endKey, this.data.list.length)) return;
// 防止拖拽过程中发生乱序问题
if (startKey === endKey || startKey === preStartKey) return;
this.data.preStartKey = startKey;
// 触发排序
this.sort(startKey, endKey);
},
touchEnd() {
if (!this.data.dragging) return;
this.triggerCustomEvent(this.data.list, "sortend");
this.clearData();
},
/**
* 根据 startKey 和 endKey 去重新计算每一项 sortKey
*/
sort(startKey, endKey) {
this.setData({itemTransition: true});
let list = this.data.list.map((item) => {
if (item.fixed) return item;
if (startKey < endKey) { // 正序拖动
if (item.sortKey > startKey && item.sortKey <= endKey) {
item.sortKey = this.excludeFix(item.sortKey - 1, startKey, 'reduce');
} else if (item.sortKey === startKey) {
item.sortKey = endKey;
}
return item;
} else if (startKey > endKey) { // 倒序拖动
if (item.sortKey >= endKey && item.sortKey < startKey) {
item.sortKey = this.excludeFix(item.sortKey + 1, startKey, 'add');
} else if (item.sortKey === startKey) {
item.sortKey = endKey;
}
return item;
}
});
this.updateList(list);
},
/**
* 排除固定项得到最终 sortKey
*/
excludeFix(sortKey, startKey, type) {
if (sortKey === startKey) return startKey;
if (this.data.list[sortKey].fixed) {
let _sortKey = type === 'reduce' ? sortKey - 1 : sortKey + 1;
return this.excludeFix(_sortKey, startKey, type);
} else {
return sortKey;
}
},
/**
* 根据排序后 list 数据进行位移计算
*/
updateList(data, vibrate = true) {
let {platform} = this.data;
let list = data.map((item, index) => {
item.tranX = `${(item.sortKey % this.data.columns) * 100}%`;
item.tranY = `${Math.floor(item.sortKey / this.data.columns) * 100}%`;
return item;
});
this.setData({list: list});
if (!vibrate) return;
if (platform !== "devtools") wx.vibrateShort();
this.triggerCustomEvent(list, "change");
},
/**
* 判断是否是固定的 item
*/
isFixed(index) {
let list = this.data.list;
if (list && list[index] && list[index].fixed) return 1;
return 0;
},
/**
* 清除参数
*/
clearData() {
this.setData({
preStartKey: -1,
dragging: false,
cur: -1,
tranX: 0,
tranY: 0
});
// 延迟清空
setTimeout(() => {
this.setData({
curZ: -1,
})
}, 300)
},
/**
* 点击每一项后触发事件
*/
itemClick(e) {
let {index, key} = e.currentTarget.dataset;
let list = this.data.list;
let currentItem = list[index];
if (!currentItem.extraNode) {
let _list = [];
list.forEach((item) => {
_list[item.sortKey] = item;
});
let currentKey = -1;
for (let i = 0, len = _list.length; i < len; i++) {
let item = _list[i];
if (!item.extraNode) {
currentKey++;
}
if (item.sortKey === currentItem.sortKey) {
break;
}
}
this.triggerEvent('click', {
key: currentKey,
data: currentItem.data
});
}
},
/**
* 封装自定义事件
* @param list 当前渲染的数据
* @param type 事件类型
*/
triggerCustomEvent(list, type) {
let _list = [], listData = [];
list.forEach((item) => {
_list[item.sortKey] = item;
});
_list.forEach((item) => {
if (!item.extraNode) {
listData.push(item.data);
}
});
this.triggerEvent(type, {listData: listData});
},
/**
* 初始化获取 dom 信息
*/
initDom() {
let {windowWidth, windowHeight, platform, SDKVersion} = wx.getSystemInfoSync();
this.data.pageMetaSupport = compareVersion(SDKVersion, '2.9.0') >= 0;
let remScale = (windowWidth || 375) / 375,
realTopSize = this.data.topSize * remScale / 2,
realBottomSize = this.data.bottomSize * remScale / 2;
this.data.windowHeight = windowHeight;
this.data.platform = platform;
this.data.realTopSize = realTopSize;
this.data.realBottomSize = realBottomSize;
this.createSelectorQuery().select(".item").boundingClientRect((res) => {
let rows = Math.ceil(this.data.list.length / this.data.columns);
this.data.rows = rows;
this.data.itemDom = res;
this.setData({
itemWrapHeight: rows * res.height,
});
this.createSelectorQuery().select(".item-wrap").boundingClientRect((res) => {
this.data.itemWrapDom = res;
this.data.itemWrapDom.top += this.data.scrollTop
}).exec();
}).exec();
},
/**
* 初始化函数
* {listData, columns, topSize, bottomSize} 参数改变需要重新调用初始化方法
*/
init() {
this.clearData();
this.setData({itemTransition: false});
// 避免获取不到节点信息报错问题
if (this.data.listData.length === 0) {
this.setData({list: [], itemWrapHeight: 0});
return;
}
let {listData, beforeExtraNodes, afterExtraNodes} = this.data;
let _listData = [];
let delItem = (item, extraNode) => ({
id: item.dragId,
slot: item.slot,
fixed: item.fixed,
extraNode: extraNode,
tranX: "0%",
tranY: "0%",
data: item
});
// 遍历数据源增加扩展项, 以用作排序使用
listData.forEach((item, index) => {
beforeExtraNodes.forEach((_item) => {
if (_item.destKey === index) _listData.push(delItem(_item, true));
});
_listData.push(delItem(item, false));
afterExtraNodes.forEach((_item, _index) => {
if (_item.destKey === index) _listData.push(delItem(_item, true));
});
});
let list = _listData.map((item, index) => {
return {
sortKey: index, // 初始化 sortKey 为当前项索引值
...item
};
});
this.updateList(list, false);
// 异步加载数据时候, 延迟执行 initDom 方法, 防止基础库 2.7.1 版本及以下无法正确获取 dom 信息
setTimeout(() => this.initDom(), 0);
}
},
ready() {
this.init();
}
});
引入index.json
{
"component": true
}
引入index.wxml
<view class="item-wrap" style="height: {{ itemWrapHeight }}px;">
<view
class="item {{cur == index ? 'cur':''}} {{curZ == index ? 'zIndex':''}} {{itemTransition && index !== cur ? 'itemTransition':''}} {{item.fixed ? 'fixed' : ''}}"
wx:for="{{list}}"
wx:key="id"
data-key="{{item.sortKey}}"
data-index="{{index}}"
style="transform: translate3d({{index === cur ? tranX + 'px' : item.tranX}}, {{index === cur ? tranY + 'px' : item.tranY}}, 0);width: {{100 / columns}}%"
bindtap="itemClick"
bind:longpress="longPress"
catch:touchmove="{{dragging?'touchMove':''}}"
catch:touchend="{{dragging?'touchEnd':''}}">
<!-- start:请在该区域编写自己的渲染逻辑 -->
<view wx:if="{{columns === 1 && item.extraNode}}" class="cell">
<view class="cell__bd" style="height: 160rpx;">
<slot name="{{item.slot}}"></slot>
</view>
</view>
<view wx:elif="{{columns === 1 && !item.extraNode}}" class="cell">
<view class="cell__hd">
<image class="image" mode="aspectFill" src="{{item.data.images}}" alt=""/>
</view>
<view class="cell__bd">
<view class="name">{{item.data.title}}</view>
<view class="des">{{item.data.description}}</view>
</view>
</view>
<view wx:elif="{{columns > 1 && item.extraNode}}" class="info">
<view class="info__item">
<slot name="{{item.slot}}"></slot>
</view>
</view>
<view wx:elif="{{columns > 1 && !item.extraNode}}" class="info">
<view class="info__item">
<image class="image" src="{{item.data.images}}"></image>
</view>
</view>
<!-- end:请在该区域编写自己的渲染逻辑 -->
</view>
</view>
引入wxss
.item-wrap {
position: relative; }
.item-wrap .item {
position: absolute;
width: 100%;
z-index: 1; }
.item-wrap .item.itemTransition {
transition: transform 0.3s !important; }
.item-wrap .item.zIndex {
z-index: 2; }
.item-wrap .item.cur {
transition: initial; }
.item-wrap .item.fixed {
z-index: 0 !important; }
.info {
position: relative;
padding-top: 100%;
background: #ffffff; }
.info__item {
position: absolute;
border: 1rpx solid #ebedf0;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
padding: 10rpx;
box-sizing: border-box; }
.info__item .image {
width: 100%;
height: 100%; }
.cell {
display: flex;
padding: 20rpx;
border-bottom: 1rpx solid #ebedf0;
background: #FFFFFF; }
.cell__hd {
font-size: 0; }
.cell__hd .image {
width: 160rpx;
height: 160rpx;
margin-right: 20rpx;
border-radius: 12rpx; }
.cell__bd {
flex: 1; }
.cell__bd .name {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
word-break: break-all;
font-size: 28rpx;
margin-bottom: 4rpx; }
.cell__bd .des {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
word-break: break-all;
color: #666666;
font-size: 24rpx; }
2.在所要显示页面引入drag.wpy
<template>
<view>
<page-meta scroll-top="{{pageMetaScrollTop}}"></page-meta>
<view class="tip">
<text style="color: red;">长按触发拖拽排序!!</text>
<text style="color: #3F82FD;">最新版本增加顶部固定区域高度和底部固定区域高度, 以响应超过一屏时候可以正确滑动</text>
</view>
<drag id="drag"
bind:click="itemClick"
bind:change="change"
bind:sortend="sortEnd"
bind:scroll="scroll"
before-extra-nodes="{{beforeExtraNodes}}"
after-extra-nodes="{{afterExtraNodes}}"
list-data="{{listData}}"
columns="{{size}}"
scroll-top="{{scrollTop}}"
top-size="110"
bottom-size="{{isIphoneX ? 380 : 300 }}">
<!-- <view slot="before" class="extra">
第0个元素之前插入该元素, 该元素不参与排序
</view>
<view slot="after" class="extra">
第0个元素之后插入该元素, 该元素不参与排序
</view> -->
<view slot="plus" class="plus-wrap" bindtap="add">
<view class="plus"></view>
</view>
</drag>
<view class="empty-bottom {{isIphoneX ? 'isX' : ''}}"></view>
<view class="control-panel {{isIphoneX ? 'isX' : ''}}">
<view class="panel-item">
<view class="panel-item__hd">请选择需要固定住的item:</view>
</view>
<view class="radio">
<view wx:for="{{listData}}" wx:key="index" bind:tap="toggleFixed" data-key="{{index}}" class="circle-wrap">
<view wx:if="{{item.fixed}}" class="circle cur">✓</view>
<view wx:else class="circle"></view>
<view>{{index}}</view>
</view>
</view>
<view class="panel-item">
<view class="panel-item__hd">columns:</view>
<view class="panel-item__bd">
<slider bindchanging="sizeChange" value="{{size}}" show-value="{{true}}" min="1" max="8" step="1"/>
</view>
</view>
</view>
</view>
</template>
<script>
import wepy from 'wepy'
export default class canvanss extends wepy.page {
config = {
component: true,
navigationBarTitleText: '脱拽效果', // 手机横屏展示
enablePullDownRefresh: false
};
data = {
// isIphoneX: app.globalData.isIphoneX, // 需要全局获取手机型号
size: 4,
listData: [],
// beforeExtraNodes: [
// {
// dragId: 'before0',
// destKey: 0,
// slot: 'before',
// fixed: true
// }
// ],
// afterExtraNodes: [
// {
// dragId: 'after0',
// destKey: 0,
// slot: 'after',
// fixed: true
// },
// {
// dragId: 'after9',
// destKey: 9,
// slot: 'plus',
// fixed: true
// }
// ],
pageMetaScrollTop: 0,
scrollTop: 0
}
methods = {
sortEnd(e) {
console.log('sortEnd', e.detail.listData)
this.listData = e.detail.listData
this.$apply()
},
change(e) {
console.log('change', e.detail.listData)
},
sizeChange(e) {
wx.pageScrollTo({ scrollTop: 0 })
this.size = e.detail.value
this.$apply()
this.drag.init()
},
itemClick(e) {
console.log(e)
},
toggleFixed(e) {
const key = e.currentTarget.dataset.key
const { listData } = this.data
listData[key].fixed = !listData[key].fixed
this.listData = listData
this.$apply()
this.drag.init()
},
add(e) {
const listData = this.data.listData
listData.push({
dragId: `item${listData.length}`,
title: '这个绝望的世界没有存在的价值,所剩的只有痛楚',
description: '思念、愿望什么的都是一场空,被这种虚幻的东西绊住脚,什么都做不到',
images: '../../images/swipe/1.png',
fixed: false
})
this.listData = listData
// this.afterExtraNodes = [
// {
// destKey: 0,
// slot: 'after',
// fixed: true
// },
// {
// destKey: listData.length - 1,
// slot: 'plus',
// fixed: true
// }
// ]
this.$apply()
this.drag.init()
// setTimeout(() => {
// this.setData({
// listData,
// afterExtraNodes: [
// {
// destKey: 0,
// slot: 'after',
// fixed: true
// },
// {
// destKey: listData.length - 1,
// slot: 'plus',
// fixed: true
// }
// ]
// })
// this.drag.init()
// }, 300)
},
scroll(e) {
this.pageMetaScrollTop = e.detail.scrollTop
this.$apply()
}, // 页面滚动
onPageScroll(e) {
this.setData({
scrollTop: e.scrollTop
})
}
}
onLoad() {
//此数组为要展示的页面元素
const listData = [
{
dragId: 'item0',
title: '这个绝望的世界没有存在的价值,所剩的只有痛楚',
description: '思念、愿望什么的都是一场空,被这种虚幻的东西绊住脚,什么都做不到',
images: '../../images/swipe/1.png',
fixed: false
},
{
dragId: 'item1',
title: '我早已闭上了双眼,我的目的,只有在黑暗中才能实现',
description: '有太多的羁绊只会让自己迷惘,强烈的想法和珍惜的思念,只会让自己变弱',
images: '../../images/swipe/2.png',
fixed: false
},
{
dragId: 'item2',
title: '感受痛苦吧,体验痛苦吧,接受痛苦吧,了解痛苦吧。不知道痛苦的人是不会知道什么是和平',
description: '但我已经在无限存在的痛苦之中,有了超越凡人的成长。从凡人化为神',
images: '../../images/swipe/3.png',
fixed: false
},
{
dragId: 'item3',
title: '我决定了 从今天起 我要选择一条不会让自己后悔的路 我要创造出属于自己的忍道 ',
description: '我才不要在这种时候放弃,即使当不成中忍,我也会通过其他的途径成为火影的,这就是我的忍道',
images: '../../images/swipe/4.png',
fixed: false
},
{
dragId: 'item4',
title: '为什么你会这么弱?就是因为你对我的仇恨...还不够深...',
description: '你没有杀的价值...愚蠢的弟弟啊...想要杀死我的话...仇恨吧!憎恨吧!然后丑陋地活下去吧!逃吧 逃吧...然后苟且偷生下去吧!',
images: '../../images/swipe/5.png',
fixed: false
},
{
dragId: 'item5',
title: '对于忍者而言怎样活着无所谓,怎样死去才是最重要的...',
description: '所谓的忍者就是忍人所不能忍,忍受不了饿肚子,而沦落为盗贼的人,根本不能称之为忍者',
images: '../../images/swipe/6.png',
fixed: false
},
{
dragId: 'item6',
title: '在这世上,有光的地方就必定有黑暗,所谓的胜者,也就是相对败者而言',
description: '若以一己之思念要维持和平,必会招致战争,为了守护爱,变回孕育出恨。此间因果,是无法斩断的。现实就是如此',
images: '../../images/swipe/7.png',
fixed: false
},
{
dragId: 'item7',
title: '世界上...只有没有实力的人,才整天希望别人赞赏...',
description: '很不巧的是我只有一个人,你说的那些家伙们已经一个都没有了,已经??全部被杀死了',
images: '../../images/swipe/8.png',
fixed: false
},
{
dragId: 'item8',
title: '千代婆婆,父亲大人和母亲大人回来了吗???',
description: '明明剩下的只有痛苦了,既然你这么想活命,我就方你一条生路好了。不过,你中的毒不出三日就会要了你的命',
images: '../../images/swipe/9.png',
fixed: false
},
{
dragId: 'item9',
title: '艺术就是爆炸!!~~ 嗯 ~~ 芸术は爆発します!',
description: '我的艺术就是爆炸那一瞬,和蝎那种让人吃惊的人偶喜剧从根本上就是不同的!',
images: '../../images/swipe/10.png',
fixed: false
}
] // 模仿异步加载数据
this.drag = this.$wxpage.selectComponent('#drag')
this.listData = listData
}
watch = {
}
}
</script>
<style lang="less">
page {
padding-top: 110rpx; }
.empty-bottom {
padding-bottom: 300rpx; }
.empty-bottom.isX {
padding-bottom: 380rpx; }
.tip {
position: fixed;
top: 0;
left: 0;
right: 0;
padding: 20rpx;
font-size: 24rpx;
color: #999999;
z-index: 999;
background: #FFFFFF;
box-sizing: border-box;
border-bottom: 1rpx solid #ebedf0; }
.control-panel {
border-top: 1rpx solid #ebedf0;
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 111;
background: #ffffff;
padding: 20rpx;
box-sizing: border-box; }
.control-panel.isX {
padding-bottom: 80rpx; }
.panel-item {
display: flex;
align-items: center; }
.panel-item__bd {
flex: 1; }
.circle-wrap {
display: inline-block;
text-align: center;
padding: 20rpx 8rpx; }
.circle-wrap .circle {
width: 50rpx;
height: 50rpx;
border: 2rpx solid #ebedf0;
border-radius: 50%; }
.circle-wrap .cur {
color: #fff;
line-height: 50rpx;
background: #3F82FD;
border: 2rpx solid #3F82FD; }
.plus-wrap {
position: relative;
width: 100%;
height: 100%; }
.plus {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0; }
.plus::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
height: 60rpx;
margin-top: -30rpx;
margin-left: -2rpx;
border-left: 4rpx solid #cccccc; }
.plus::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 60rpx;
margin-left: -30rpx;
margin-top: -2rpx;
border-top: 4rpx solid #cccccc; }
.radio {
overflow-x: auto;
white-space: nowrap; }
.extra {
background: #cccccc;
color: #3F82FD;
font-size: 24rpx;
padding: 10rpx;
width: 100%;
height: 100%;
box-sizing: border-box;
overflow: hidden; }
</style>
3.由于组件使用需要开箱即用,所以需要在app.wpy中的usingComponents注入’drag’: ‘./components/drag/index’
注: 根据其他文档编写wepy组件,如有侵权,联系博主,谢谢