diff --git a/app.json b/app.json
index 7e6dcb9..2976a53 100644
--- a/app.json
+++ b/app.json
@@ -69,19 +69,23 @@
"pages/signup/index",
"pages/signup/status",
"pages/clues/index",
- "pages/clues/detail/index"
+ "pages/clues/detail/index",
+ "pages/score/index",
+ "pages/score/detail"
],
"permission": {
"scope.userLocation": {
"desc": "你的位置信息将用于线下车卖场到访签到"
}
},
- "echarts": [{
- "root": "ecCanvas",
- "pages": [
- "pages/index/index"
- ]
- }],
+ "echarts": [
+ {
+ "root": "ecCanvas",
+ "pages": [
+ "pages/index/index"
+ ]
+ }
+ ],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
@@ -104,7 +108,7 @@
"navigateToMiniProgramAppIdList": [
"wx98e64c11aac45966"
],
- "requiredPrivateInfos":[
+ "requiredPrivateInfos": [
"getLocation"
]
}
\ No newline at end of file
diff --git a/commons/css/base/background.wxss b/commons/css/base/background.wxss
index 9b07ffe..b79a345 100644
--- a/commons/css/base/background.wxss
+++ b/commons/css/base/background.wxss
@@ -39,4 +39,16 @@
.bg-ffedeb{background-color:#ffedeb;}
.bg-f0f4ff{background-color:#f0f4ff;}
-.bg-fffaf3{background-color:#fffaf3;}
\ No newline at end of file
+.bg-fffaf3{background-color:#fffaf3;}
+
+.bg-size-cover{background-size: cover;}
+.bg-size-fullwidth{background-size: 100% auto;}
+.bg-size-fullheight{background-size: auto 100%;}
+.bg-no-repeat{background-repeat: no-repeat;}
+.bg-repeat-x{background-repeat:repeat-x;}
+.bg-repeat-y{background-repeat: repeat-y;}
+.bg-pos-top{background-position: top center;}
+.bg-pos-bottom{background-position: bottom center;}
+.bg-pos-center{background-position: center;}
+
+.bg-custom-linear-bottom{background-image: linear-gradient(to bottom, var(--linearcolor), transparent);}
\ No newline at end of file
diff --git a/commons/css/base/border.wxss b/commons/css/base/border.wxss
index 72308f0..4b48aed 100644
--- a/commons/css/base/border.wxss
+++ b/commons/css/base/border.wxss
@@ -25,3 +25,5 @@
.bbs-1-474a65{border-bottom:#474a65 1rpx solid; box-sizing:border-box;}
.last-b-none:last-child{border-bottom:none;}
+
+.bbs-1-f6{border-bottom:#f6f6f6 1rpx solid;box-sizing:border-box;}
diff --git a/commons/css/base/imgSize.wxss b/commons/css/base/imgSize.wxss
index 0b9b9fa..ab94f44 100644
--- a/commons/css/base/imgSize.wxss
+++ b/commons/css/base/imgSize.wxss
@@ -1,4 +1,7 @@
.img-24x24{width:24rpx;height:24rpx;box-sizing:border-box;}
+.img-28x28{width:28rpx;height:28rpx;box-sizing:border-box;}
+.img-32x32{width:32rpx;height:32rpx;box-sizing:border-box;}
+.img-38x38{width:38rpx;height:38rpx;box-sizing:border-box;}
.img-45x45{width:45rpx;height:45rpx;box-sizing:border-box;}
.img-50x50{width:50rpx;height:50rpx;box-sizing:border-box;}
.img-55x55{width:55rpx;height:55rpx;box-sizing:border-box;}
@@ -15,6 +18,7 @@
.img-130x130{width:130rpx;height:130rpx;box-sizing:border-box;}
.img-135x135{width:135rpx;height:135rpx;box-sizing:border-box;}
.img-140x140{width:140rpx;height:140rpx;box-sizing:border-box;}
+.img-154x154{width:154rpx;height:154rpx;box-sizing:border-box;}
.img-160x160{width:160rpx;height:160rpx;box-sizing:border-box;}
.img-190x175{width:190rpx;height:175rpx;box-sizing:border-box;}
.img-200x180{width:200rpx;height:180rpx;box-sizing:border-box;}
diff --git a/commons/css/base/layout.wxss b/commons/css/base/layout.wxss
index db9390b..2191d29 100644
--- a/commons/css/base/layout.wxss
+++ b/commons/css/base/layout.wxss
@@ -20,8 +20,16 @@
.overflowXhidden{overflow-x:hidden;}
.overflow-initial{overflow:initial;}
.opacity-0{opacity:0;}
+.opacity-5{opacity:.05;}
+.opacity-10{opacity:.1;}
+.opacity-20{opacity:.2;}
+.opacity-30{opacity:.3;}
+.opacity-40{opacity:.4;}
.opacity-50{opacity:.5;}
+.opacity-60{opacity:.6;}
+.opacity-70{opacity:.7;}
.opacity-80{opacity:.8;}
+.opacity-90{opacity:.9;}
/*line-clamp*/
.line-clamp-2{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;}
@@ -44,6 +52,7 @@
.fn-flex-around{justify-content: space-around;}/*各项周围留有空白*/
.fn-flex-middle{align-items:center;}/*交叉轴上上下居中对齐*/
.fn-flex-center{justify-content: center;}/*居中对齐*/
+.fn-flex-column{flex-direction:column;}
.wp25{width:25%;box-sizing:border-box;}
.wp31{width:31%;box-sizing:border-box;}
@@ -135,4 +144,6 @@
.safe-pb{padding-bottom:calc(constant(safe-area-inset-bottom) - 15px );padding-bottom:calc(env(safe-area-inset-bottom) - 15px);}
.datecell{width:14.28%;padding:30rpx 0;text-align:center;box-sizing:border-box;}
-.datecell.active{background-color:#36afa2;color:#fff;}
\ No newline at end of file
+.datecell.active{background-color:#36afa2;color:#fff;}
+
+.transition-all{transition: all .2s ease;}
\ No newline at end of file
diff --git a/commons/css/base/margin.wxss b/commons/css/base/margin.wxss
index 8584c59..7ddef5f 100644
--- a/commons/css/base/margin.wxss
+++ b/commons/css/base/margin.wxss
@@ -61,6 +61,7 @@
.mr50{margin-right:50rpx;}
.mr60{margin-right:60rpx;}
.mr70{margin-right:70rpx;}
+.mr100{margin-right:100rpx;}
.mr150{margin-right:150rpx;}
.mr160{margin-right:160rpx;}
.mr170{margin-right:170rpx;}
diff --git a/commons/js/config.js b/commons/js/config.js
index b9778ce..9a150cb 100644
--- a/commons/js/config.js
+++ b/commons/js/config.js
@@ -189,6 +189,8 @@ api = {
//远程图片存储地址
var imgUrl = 'https://qs.haodian.cn/wechat_app/lichebao/'
+var licheImgUrl = 'https://img.liche.cn/lichebao/'
+
/**
* 默认头像
@@ -238,6 +240,7 @@ export default {
version,
app_id,
imgUrl,
+ licheImgUrl,
defaultAvartar,
elementScrollTop,
bookTmpId,
diff --git a/components/mp-html/index.js b/components/mp-html/index.js
new file mode 100644
index 0000000..1d9caec
--- /dev/null
+++ b/components/mp-html/index.js
@@ -0,0 +1,393 @@
+/*!
+ * mp-html v2.4.0
+ * https://github.com/jin-yufeng/mp-html
+ *
+ * Released under the MIT license
+ * Author: Jin Yufeng
+ */
+const Parser = require('./parser')
+const plugins = []
+
+Component({
+ data: {
+ nodes: []
+ },
+ properties: {
+ /**
+ * @description 容器的样式
+ * @type {String}
+ */
+ containerStyle: String,
+
+ /**
+ * @description 用于渲染的 html 字符串
+ * @type {String}
+ */
+ content: {
+ type: String,
+ value: '',
+ observer (content) {
+ this.setContent(content)
+ }
+ },
+
+ /**
+ * @description 是否允许外部链接被点击时自动复制
+ * @type {Boolean}
+ * @default true
+ */
+ copyLink: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * @description 主域名,用于拼接链接
+ * @type {String}
+ */
+ domain: String,
+
+ /**
+ * @description 图片出错时的占位图链接
+ * @type {String}
+ */
+ errorImg: String,
+
+ /**
+ * @description 是否开启图片懒加载
+ * @type {Boolean}
+ * @default false
+ */
+ lazyLoad: Boolean,
+
+ /**
+ * @description 图片加载过程中的占位图链接
+ * @type {String}
+ */
+ loadingImg: String,
+
+ /**
+ * @description 是否在播放一个视频时自动暂停其他视频
+ * @type {Boolean}
+ * @default true
+ */
+ pauseVideo: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * @description 是否允许图片被点击时自动预览
+ * @type {Boolean}
+ * @default true
+ */
+ previewImg: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * @description 是否给每个表格添加一个滚动层使其能单独横向滚动
+ * @type {Boolean}
+ * @default false
+ */
+ scrollTable: Boolean,
+
+ /**
+ * @description 是否开启长按复制
+ * @type {Boolean | String}
+ * @default false
+ */
+ selectable: null,
+
+ /**
+ * @description 是否将 title 标签的内容设置到页面标题
+ * @type {Boolean}
+ * @default true
+ */
+ setTitle: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * @description 是否允许图片被长按时显示菜单
+ * @type {Boolean}
+ * @default true
+ */
+ showImgMenu: {
+ type: Boolean,
+ value: true
+ },
+
+ /**
+ * @description 标签的默认样式
+ * @type {Object}
+ */
+ tagStyle: Object,
+
+ /**
+ * @description 是否使用锚点链接
+ * @type {Boolean | Number}
+ * @default false
+ */
+ useAnchor: null
+ },
+
+ created () {
+ this.plugins = []
+ for (let i = plugins.length; i--;) {
+ this.plugins.push(new plugins[i](this))
+ }
+
+ // #ifdef MP-ALIPAY
+ if (this.properties.content) {
+ this.setContent(this.properties.content)
+ }
+ // #endif
+ },
+
+ // #ifdef MP-ALIPAY
+ didUpdate (e) {
+ if (e.content !== this.properties.content) {
+ this.setContent(this.properties.content)
+ }
+ },
+ // #endif
+
+ detached () {
+ // 注销插件
+ this._hook('onDetached')
+ },
+
+ methods: {
+ /**
+ * @description 将锚点跳转的范围限定在一个 scroll-view 内
+ * @param {Object} page scroll-view 所在页面的示例
+ * @param {String} selector scroll-view 的选择器
+ * @param {String} scrollTop scroll-view scroll-top 属性绑定的变量名
+ */
+ in (page, selector, scrollTop) {
+ if (page && selector && scrollTop) {
+ this._in = {
+ page,
+ selector,
+ scrollTop
+ }
+ }
+ },
+
+ /**
+ * @description 锚点跳转
+ * @param {String} id 要跳转的锚点 id
+ * @param {Number} offset 跳转位置的偏移量
+ * @returns {Promise}
+ */
+ navigateTo (id, offset) {
+ return new Promise((resolve, reject) => {
+ if (!this.properties.useAnchor) {
+ reject(Error('Anchor is disabled'))
+ return
+ }
+ // 跨组件选择器
+ const deep =
+ // #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO
+ '>>>'
+ // #endif
+ // #ifdef MP-BAIDU || MP-ALIPAY
+ ' ' // eslint-disable-line
+ // #endif
+ const selector = wx.createSelectorQuery()
+ // #ifndef MP-ALIPAY
+ .in(this._in ? this._in.page : this)
+ // #endif
+ .select((this._in ? this._in.selector : '._root') + (id ? `${deep}#${id}` : '')).boundingClientRect()
+ if (this._in) {
+ selector.select(this._in.selector).scrollOffset()
+ .select(this._in.selector).boundingClientRect()
+ } else {
+ // 获取 scroll-view 的位置和滚动距离
+ selector.selectViewport().scrollOffset() // 获取窗口的滚动距离
+ }
+ selector.exec(res => {
+ if (!res[0]) {
+ reject(Error('Label not found'))
+ return
+ }
+ const scrollTop = res[1].scrollTop + res[0].top - (res[2] ? res[2].top : 0) + (offset || parseInt(this.properties.useAnchor) || 0)
+ if (this._in) {
+ // scroll-view 跳转
+ this._in.page.setData({
+ [this._in.scrollTop]: scrollTop
+ })
+ } else {
+ // 页面跳转
+ wx.pageScrollTo({
+ scrollTop,
+ duration: 300
+ })
+ }
+ resolve()
+ })
+ })
+ },
+
+ /**
+ * @description 获取文本内容
+ * @returns {String}
+ */
+ getText (nodes) {
+ let text = '';
+ (function traversal (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ const node = nodes[i]
+ if (node.type === 'text') {
+ text += node.text.replace(/&/g, '&')
+ } else if (node.name === 'br') {
+ text += '\n'
+ } else {
+ // 块级标签前后加换行
+ const isBlock = node.name === 'p' || node.name === 'div' || node.name === 'tr' || node.name === 'li' || (node.name[0] === 'h' && node.name[1] > '0' && node.name[1] < '7')
+ if (isBlock && text && text[text.length - 1] !== '\n') {
+ text += '\n'
+ }
+ // 递归获取子节点的文本
+ if (node.children) {
+ traversal(node.children)
+ }
+ if (isBlock && text[text.length - 1] !== '\n') {
+ text += '\n'
+ } else if (node.name === 'td' || node.name === 'th') {
+ text += '\t'
+ }
+ }
+ }
+ })(nodes || this.data.nodes)
+ return text
+ },
+
+ /**
+ * @description 获取内容大小
+ * @returns {Promise}
+ */
+ getRect () {
+ return new Promise((resolve, reject) => {
+ wx.createSelectorQuery()
+ // #ifndef MP-ALIPAY
+ .in(this)
+ // #endif
+ .select('._root').boundingClientRect().exec(res => res[0] ? resolve(res[0]) : reject(Error('Root label not found')))
+ })
+ },
+
+ /**
+ * @description 暂停播放媒体
+ */
+ pauseMedia () {
+ for (let i = (this._videos || []).length; i--;) {
+ this._videos[i].pause()
+ }
+ },
+
+ /**
+ * @description 设置媒体播放速率
+ * @param {Number} rate 播放速率
+ */
+ setPlaybackRate (rate) {
+ this.playbackRate = rate
+ for (let i = (this._videos || []).length; i--;) {
+ this._videos[i].playbackRate(rate)
+ }
+ },
+
+ /**
+ * @description 设置富文本内容
+ * @param {string} content 要渲染的 html 字符串
+ * @param {boolean} append 是否在尾部追加
+ */
+ setContent (content, append) {
+ if (!this.imgList || !append) {
+ this.imgList = []
+ }
+ this._videos = []
+
+ const data = {}
+ const nodes = new Parser(this).parse(content)
+ // 尾部追加内容
+ if (append) {
+ for (let i = this.data.nodes.length, j = nodes.length; j--;) {
+ data[`nodes[${i + j}]`] = nodes[j]
+ }
+ } else {
+ data.nodes = nodes
+ }
+
+ this.setData(data,
+ // #ifndef MP-TOUTIAO
+ () => {
+ this._hook('onLoad')
+ this.triggerEvent('load')
+ }
+ // #endif
+ )
+
+ // #ifdef MP-TOUTIAO
+ this.selectComponent('#_root', child => {
+ child.root = this
+ this._hook('onLoad')
+ this.triggerEvent('load')
+ })
+ // #endif
+
+ if (this.properties.lazyLoad || this.imgList._unloadimgs < this.imgList.length / 2) {
+ // 设置懒加载,每 350ms 获取高度,不变则认为加载完毕
+ let height
+ const callback = rect => {
+ // 350ms 总高度无变化就触发 ready 事件
+ if (rect.height === height) {
+ this.triggerEvent('ready', rect)
+ } else {
+ height = rect.height
+ setTimeout(() => {
+ this.getRect().then(callback)
+ }, 350)
+ }
+ }
+ this.getRect().then(callback)
+ } else {
+ // 未设置懒加载,等待所有图片加载完毕
+ if (!this.imgList._unloadimgs) {
+ this.getRect(rect => {
+ this.triggerEvent('ready', rect)
+ })
+ }
+ }
+ },
+
+ /**
+ * @description 调用插件的钩子函数
+ * @private
+ */
+ _hook (name) {
+ for (let i = plugins.length; i--;) {
+ if (this.plugins[i][name]) {
+ this.plugins[i][name]()
+ }
+ }
+ },
+
+ // #ifndef MP-TOUTIAO
+ /**
+ * @description 添加子组件
+ * @private
+ */
+ _add (e) {
+ e
+ // #ifndef MP-ALIPAY
+ .detail
+ // #endif
+ .root = this
+ }
+ // #endif
+ }
+})
diff --git a/components/mp-html/index.json b/components/mp-html/index.json
new file mode 100644
index 0000000..f55f207
--- /dev/null
+++ b/components/mp-html/index.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "node": "./node/node"
+ }
+}
\ No newline at end of file
diff --git a/components/mp-html/index.wxml b/components/mp-html/index.wxml
new file mode 100644
index 0000000..6e98f0a
--- /dev/null
+++ b/components/mp-html/index.wxml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/mp-html/index.wxss b/components/mp-html/index.wxss
new file mode 100644
index 0000000..abf4467
--- /dev/null
+++ b/components/mp-html/index.wxss
@@ -0,0 +1,2 @@
+._root{padding:0;overflow-x:auto;overflow-y:hidden;-webkit-overflow-scrolling:touch;}
+._select{-webkit-user-select:text;user-select:text;}
\ No newline at end of file
diff --git a/components/mp-html/node/node.js b/components/mp-html/node/node.js
new file mode 100644
index 0000000..e205176
--- /dev/null
+++ b/components/mp-html/node/node.js
@@ -0,0 +1,237 @@
+/**
+ * @fileoverview 递归子组件,用于显示节点树
+ */
+Component({
+ data: {
+ ctrl: {}, // 控制信号
+ // #ifdef MP-WEIXIN
+ isiOS: wx.getSystemInfoSync().system.includes('iOS')
+ // #endif
+ },
+ properties: {
+ childs: Array, // 子节点列表
+ opts: Array // 设置 [是否开启懒加载, 加载中占位图, 错误占位图, 是否使用长按菜单]
+ },
+ options: {
+ addGlobalClass: true
+ },
+ // #ifndef MP-TOUTIAO
+ attached () {
+ // #ifndef MP-ALIPAY
+ this.triggerEvent('add', this, {
+ bubbles: true,
+ composed: true
+ })
+ // #endif
+ // #ifdef MP-ALIPAY
+ // this.props.onAdd(this)
+ // #endif
+ },
+ // #endif
+ methods: {
+ noop () { },
+ /**
+ * @description 获取标签
+ * @param {String} path 路径
+ */
+ getNode (path) {
+ try {
+ const nums = path.split('_')
+ let node = this.properties.childs[nums[0]]
+ for (let i = 1; i < nums.length; i++) {
+ node = node.children[nums[i]]
+ }
+ return node
+ } catch {
+ return {
+ text: '',
+ attrs: {},
+ children: []
+ }
+ }
+ },
+ /**
+ * @description 播放视频事件
+ * @param {Event} e
+ */
+ play (e) {
+ this.root.triggerEvent('play')
+ if (this.root.properties.pauseVideo) {
+ let flag = false
+ const id = e.target.id
+ for (let i = this.root._videos.length; i--;) {
+ if (this.root._videos[i].id === id) {
+ flag = true
+ } else {
+ this.root._videos[i].pause() // 自动暂停其他视频
+ }
+ }
+ // 将自己加入列表
+ if (!flag) {
+ const ctx = wx.createVideoContext(id
+ // #ifndef MP-BAIDU
+ , this
+ // #endif
+ )
+ ctx.id = id
+ if (this.root.playbackRate) {
+ ctx.playbackRate(this.root.playbackRate)
+ }
+ this.root._videos.push(ctx)
+ }
+ }
+ },
+
+ /**
+ * @description 图片点击事件
+ * @param {Event} e
+ */
+ imgTap (e) {
+ const node = this.getNode(e.target.dataset.i)
+ // 父级中有链接
+ if (node.a) return this.linkTap(node.a)
+ if (node.attrs.ignore) return
+ this.root.triggerEvent('imgtap', node.attrs)
+ if (this.root.properties.previewImg) {
+ const current =
+ // #ifndef MP-ALIPAY
+ this.root.imgList[node.i]
+ // #endif
+ // #ifdef MP-ALIPAY
+ node.i // eslint-disable-line
+ // #endif
+ // 自动预览图片
+ wx.previewImage({
+ // #ifdef MP-WEIXIN
+ showmenu: this.root.properties.showImgMenu,
+ // #endif
+ // #ifdef MP-ALIPAY
+ enablesavephoto: this.root.properties.showImgMenu,
+ enableShowPhotoDownload: this.root.properties.showImgMenu,
+ // #endif
+ current,
+ urls: this.root.imgList
+ })
+ }
+ },
+
+ /**
+ * @description 图片加载完成事件
+ * @param {Event} e
+ */
+ imgLoad (e) {
+ const i = e.target.dataset.i
+ const node = this.getNode(i)
+ let val
+ if (!node.w) {
+ val = e.detail.width
+ } else if ((this.properties.opts[1] && !this.data.ctrl[i]) || this.data.ctrl[i] === -1) {
+ // 加载完毕,取消加载中占位图
+ val = 1
+ }
+ if (val
+ // #ifdef MP-TOUTIAO
+ && val !== this.data.ctrl[i] // eslint-disable-line
+ // #endif
+ ) {
+ this.setData({
+ ['ctrl.' + i]: val
+ })
+ }
+ this.checkReady()
+ },
+
+ /**
+ * @description 检查是否所有图片加载完毕
+ */
+ checkReady () {
+ if (!this.root.properties.lazyLoad) {
+ this.root.imgList._unloadimgs -= 1
+ if (!this.root.imgList._unloadimgs) {
+ setTimeout(() => {
+ this.root.getRect().then(rect => {
+ this.root.triggerEvent('ready', rect)
+ })
+ }, 350)
+ }
+ }
+ },
+
+ /**
+ * @description 链接点击事件
+ * @param {Event} e
+ */
+ linkTap (e) {
+ const node = e.currentTarget ? this.getNode(e.currentTarget.dataset.i) : {}
+ const attrs = node.attrs || e
+ const href = attrs.href
+ this.root.triggerEvent('linktap', Object.assign({
+ innerText: this.root.getText(node.children || []) // 链接内的文本内容
+ }, attrs))
+ if (href) {
+ if (href[0] === '#') {
+ // 跳转锚点
+ this.root.navigateTo(href.substring(1)).catch(() => { })
+ } else if (href.split('?')[0].includes('://')) {
+ // 复制外部链接
+ if (this.root.properties.copyLink) {
+ wx.setClipboardData({
+ data: href,
+ success: () =>
+ wx.showToast({
+ title: '链接已复制'
+ })
+ })
+ }
+ } else {
+ // 跳转页面
+ wx.navigateTo({
+ url: href,
+ fail () {
+ wx.switchTab({
+ url: href,
+ fail () { }
+ })
+ }
+ })
+ }
+ }
+ },
+
+ /**
+ * @description 错误事件
+ * @param {Event} e
+ */
+ mediaError (e) {
+ const i = e.target.dataset.i
+ const node = this.getNode(i)
+ if (node.name === 'video' || node.name === 'audio') {
+ // 加载其他源
+ let index = (this.data.ctrl[i] || 0) + 1
+ if (index > node.src.length) {
+ index = 0
+ }
+ if (index < node.src.length) {
+ return this.setData({
+ ['ctrl.' + i]: index
+ })
+ }
+ } else if (node.name === 'img') {
+ // 显示错误占位图
+ if (this.properties.opts[2]) {
+ this.setData({
+ ['ctrl.' + i]: -1
+ })
+ }
+ this.checkReady()
+ }
+ if (this.root) {
+ this.root.triggerEvent('error', {
+ source: node.name,
+ attrs: node.attrs,
+ errMsg: e.detail.errMsg
+ })
+ }
+ }
+ }
+})
diff --git a/components/mp-html/node/node.json b/components/mp-html/node/node.json
new file mode 100644
index 0000000..7bebc99
--- /dev/null
+++ b/components/mp-html/node/node.json
@@ -0,0 +1,6 @@
+{
+ "component": true,
+ "usingComponents": {
+ "node": "./node"
+ }
+}
\ No newline at end of file
diff --git a/components/mp-html/node/node.wxml b/components/mp-html/node/node.wxml
new file mode 100644
index 0000000..1eeb6d4
--- /dev/null
+++ b/components/mp-html/node/node.wxml
@@ -0,0 +1,112 @@
+
+
+
+ // 行内标签列表
+ var inlineTags = {
+ abbr: true,
+ b: true,
+ big: true,
+ code: true,
+ del: true,
+ em: true,
+ i: true,
+ ins: true,
+ label: true,
+ q: true,
+ small: true,
+ span: true,
+ strong: true,
+ sub: true,
+ sup: true
+ }
+ /**
+ * @description 判断是否为行内标签
+ */
+ module.exports = function (tagName, style) {
+ return inlineTags[tagName] || (style || '').indexOf('inline') !== -1
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{n.text}}
+
+ \n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/components/mp-html/node/node.wxss b/components/mp-html/node/node.wxss
new file mode 100644
index 0000000..ec770b4
--- /dev/null
+++ b/components/mp-html/node/node.wxss
@@ -0,0 +1,169 @@
+/* a 标签默认效果 */
+._a {
+ padding: 1.5px 0 1.5px 0;
+ color: #366092;
+ word-break: break-all;
+}
+
+/* a 标签点击态效果 */
+._hover {
+ text-decoration: underline;
+ opacity: 0.7;
+}
+
+/* 图片默认效果 */
+._img {
+ max-width: 100%;
+ -webkit-touch-callout: none;
+ vertical-align:top;
+ margin-bottom: -2rpx;
+}
+._img_block{
+ /* display: block!important; */
+}
+
+/* 内部样式 */
+
+._b,
+._strong {
+ font-weight: bold;
+}
+
+._code {
+ font-family: monospace;
+}
+
+._del {
+ text-decoration: line-through;
+}
+
+._em,
+._i {
+ font-style: italic;
+}
+
+._h1 {
+ font-size: 2em;
+}
+
+._h2 {
+ font-size: 1.5em;
+}
+
+._h3 {
+ font-size: 1.17em;
+}
+
+._h5 {
+ font-size: 0.83em;
+}
+
+._h6 {
+ font-size: 0.67em;
+}
+
+._h1,
+._h2,
+._h3,
+._h4,
+._h5,
+._h6 {
+ display: block;
+ font-weight: bold;
+}
+
+._ins {
+ text-decoration: underline;
+}
+
+._li {
+ display: list-item;
+}
+
+._ol {
+ list-style-type: decimal;
+}
+
+._ol,
+._ul {
+ display: block;
+ padding-left: 40px;
+ margin: 1em 0;
+}
+
+._q::before {
+ content: '"';
+}
+
+._q::after {
+ content: '"';
+}
+
+._sub {
+ font-size: smaller;
+ vertical-align: sub;
+}
+
+._sup {
+ font-size: smaller;
+ vertical-align: super;
+}
+
+._thead,
+._tbody,
+._tfoot {
+ display: table-row-group;
+}
+
+._tr {
+ display: table-row;
+}
+
+._td,
+._th {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+._th {
+ font-weight: bold;
+ text-align: center;
+}
+
+._ul {
+ list-style-type: disc;
+}
+
+._ul ._ul {
+ margin: 0;
+ list-style-type: circle;
+}
+
+._ul ._ul ._ul {
+ list-style-type: square;
+}
+
+._abbr,
+._b,
+._code,
+._del,
+._em,
+._i,
+._ins,
+._label,
+._q,
+._span,
+._strong,
+._sub,
+._sup {
+ display: inline;
+}
+
+/* #ifndef MP-ALIPAY || MP-TOUTIAO */
+._blockquote,
+._div,
+._p {
+ display: block;
+}
+
+/* #endif */
\ No newline at end of file
diff --git a/components/mp-html/parser.js b/components/mp-html/parser.js
new file mode 100644
index 0000000..f25bd85
--- /dev/null
+++ b/components/mp-html/parser.js
@@ -0,0 +1,1214 @@
+/**
+ * @fileoverview html 解析器
+ */
+
+// 配置
+const config = {
+ // 信任的标签(保持标签名不变)
+ trustTags: makeMap('a,abbr,ad,audio,b,blockquote,br,code,col,colgroup,dd,del,dl,dt,div,em,fieldset,h1,h2,h3,h4,h5,h6,hr,i,img,ins,label,legend,li,ol,p,q,ruby,rt,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video'),
+
+ // 块级标签(转为 div,其他的非信任标签转为 span)
+ blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,pre,section'),
+
+ // 要移除的标签
+ ignoreTags: makeMap('area,base,canvas,embed,frame,head,iframe,input,link,map,meta,param,rp,script,source,style,textarea,title,track,wbr'),
+
+ // 自闭合标签
+ voidTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
+
+ // html 实体
+ entities: {
+ lt: '<',
+ gt: '>',
+ quot: '"',
+ apos: "'",
+ ensp: '\u2002',
+ emsp: '\u2003',
+ nbsp: '\xA0',
+ semi: ';',
+ ndash: '–',
+ mdash: '—',
+ middot: '·',
+ lsquo: '‘',
+ rsquo: '’',
+ ldquo: '“',
+ rdquo: '”',
+ bull: '•',
+ hellip: '…',
+ larr: '←',
+ uarr: '↑',
+ rarr: '→',
+ darr: '↓'
+ },
+
+ // 默认的标签样式
+ tagStyle: {
+ address: 'font-style:italic',
+ big: 'display:inline;font-size:1.2em',
+ caption: 'display:table-caption;text-align:center',
+ center: 'text-align:center',
+ cite: 'font-style:italic',
+ dd: 'margin-left:40px',
+ mark: 'background-color:yellow',
+ pre: 'font-family:monospace;white-space:pre',
+ s: 'text-decoration:line-through',
+ small: 'display:inline;font-size:0.8em',
+ strike: 'text-decoration:line-through',
+ u: 'text-decoration:underline'
+ },
+
+ // svg 大小写对照表
+ svgDict: {
+ animatetransform: 'animateTransform',
+ lineargradient: 'linearGradient',
+ viewbox: 'viewBox',
+ attributename: 'attributeName',
+ repeatcount: 'repeatCount',
+ repeatdur: 'repeatDur'
+ }
+}
+const tagSelector = {}
+const {
+ windowWidth,
+ // #ifdef MP-WEIXIN
+ system
+ // #endif
+} = wx.getSystemInfoSync()
+const blankChar = makeMap(' ,\r,\n,\t,\f')
+let idIndex = 0
+
+/**
+ * @description 创建 map
+ * @param {String} str 逗号分隔
+ */
+function makeMap (str) {
+ const map = Object.create(null)
+ const list = str.split(',')
+ for (let i = list.length; i--;) {
+ map[list[i]] = true
+ }
+ return map
+}
+
+/**
+ * @description 解码 html 实体
+ * @param {String} str 要解码的字符串
+ * @param {Boolean} amp 要不要解码 &
+ * @returns {String} 解码后的字符串
+ */
+function decodeEntity (str, amp) {
+ let i = str.indexOf('&')
+ while (i !== -1) {
+ const j = str.indexOf(';', i + 3)
+ let code
+ if (j === -1) break
+ if (str[i + 1] === '#') {
+ // { 形式的实体
+ code = parseInt((str[i + 2] === 'x' ? '0' : '') + str.substring(i + 2, j))
+ if (!isNaN(code)) {
+ str = str.substr(0, i) + String.fromCharCode(code) + str.substr(j + 1)
+ }
+ } else {
+ // 形式的实体
+ code = str.substring(i + 1, j)
+ if (config.entities[code] || (code === 'amp' && amp)) {
+ str = str.substr(0, i) + (config.entities[code] || '&') + str.substr(j + 1)
+ }
+ }
+ i = str.indexOf('&', i + 1)
+ }
+ return str
+}
+
+/**
+ * @description 合并多个块级标签,加快长内容渲染
+ * @param {Array} nodes 要合并的标签数组
+ */
+function mergeNodes (nodes) {
+ let i = nodes.length - 1
+ for (let j = i; j >= -1; j--) {
+ if (j === -1 || nodes[j].c || !nodes[j].name || (nodes[j].name !== 'div' && nodes[j].name !== 'p' && nodes[j].name[0] !== 'h') || (nodes[j].attrs.style || '').includes('inline')) {
+ if (i - j >= 5) {
+ nodes.splice(j + 1, i - j, {
+ name: 'div',
+ attrs: {},
+ children: nodes.slice(j + 1, i + 1)
+ })
+ }
+ i = j - 1
+ }
+ }
+}
+
+/**
+ * @description html 解析器
+ * @param {Object} vm 组件实例
+ */
+function Parser (vm) {
+ this.options = vm.properties || {}
+ this.tagStyle = Object.assign({}, config.tagStyle, this.options.tagStyle)
+ this.imgList = vm.imgList || []
+ this.imgList._unloadimgs = 0
+ this.plugins = vm.plugins || []
+ this.attrs = Object.create(null)
+ this.stack = []
+ this.nodes = []
+ this.pre = (this.options.containerStyle || '').includes('white-space') && this.options.containerStyle.includes('pre') ? 2 : 0
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Parser.prototype.parse = function (content) {
+ // 插件处理
+ for (let i = this.plugins.length; i--;) {
+ if (this.plugins[i].onUpdate) {
+ content = this.plugins[i].onUpdate(content, config) || content
+ }
+ }
+
+ new Lexer(this).parse(content)
+ // 出栈未闭合的标签
+ while (this.stack.length) {
+ this.popNode()
+ }
+ if (this.nodes.length > 50) {
+ mergeNodes(this.nodes)
+ }
+ return this.nodes
+}
+
+/**
+ * @description 将标签暴露出来(不被 rich-text 包含)
+ */
+Parser.prototype.expose = function () {
+ for (let i = this.stack.length; i--;) {
+ const item = this.stack[i]
+ if (item.c || item.name === 'a' || item.name === 'video' || item.name === 'audio') return
+ item.c = 1
+ }
+}
+
+/**
+ * @description 处理插件
+ * @param {Object} node 要处理的标签
+ * @returns {Boolean} 是否要移除此标签
+ */
+Parser.prototype.hook = function (node) {
+ for (let i = this.plugins.length; i--;) {
+ if (this.plugins[i].onParse && this.plugins[i].onParse(node, this) === false) return false
+ }
+ return true
+}
+
+/**
+ * @description 将链接拼接上主域名
+ * @param {String} url 需要拼接的链接
+ * @returns {String} 拼接后的链接
+ */
+Parser.prototype.getUrl = function (url) {
+ const domain = this.options.domain
+ if (url[0] === '/') {
+ if (url[1] === '/') {
+ // // 开头的补充协议名
+ url = (domain ? domain.split('://')[0] : 'http') + ':' + url
+ } else if (domain) {
+ // 否则补充整个域名
+ url = domain + url
+ }
+ } else if (domain && !url.includes('data:') && !url.includes('://')) {
+ url = domain + '/' + url
+ }
+ return url
+}
+
+/**
+ * @description 解析样式表
+ * @param {Object} node 标签
+ * @returns {Object}
+ */
+Parser.prototype.parseStyle = function (node) {
+ const attrs = node.attrs
+ const list = (this.tagStyle[node.name] || '').split(';').concat((attrs.style || '').split(';'))
+ const styleObj = {}
+ let tmp = ''
+
+ if (attrs.id && !this.xml) {
+ // 暴露锚点
+ if (this.options.useAnchor) {
+ this.expose()
+ } else if (node.name !== 'img' && node.name !== 'a' && node.name !== 'video' && node.name !== 'audio') {
+ attrs.id = undefined
+ }
+ }
+
+ // 转换 width 和 height 属性
+ if (attrs.width) {
+ styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px')
+ attrs.width = undefined
+ }
+ if (attrs.height) {
+ styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px')
+ attrs.height = undefined
+ }
+
+ for (let i = 0, len = list.length; i < len; i++) {
+ const info = list[i].split(':')
+ if (info.length < 2) continue
+ const key = info.shift().trim().toLowerCase()
+ let value = info.join(':').trim()
+ if ((value[0] === '-' && value.lastIndexOf('-') > 0) || value.includes('safe')) {
+ // 兼容性的 css 不压缩
+ tmp += `;${key}:${value}`
+ } else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import')) {
+ // 重复的样式进行覆盖
+ if (value.includes('url')) {
+ // 填充链接
+ let j = value.indexOf('(') + 1
+ if (j) {
+ while (value[j] === '"' || value[j] === "'" || blankChar[value[j]]) {
+ j++
+ }
+ value = value.substr(0, j) + this.getUrl(value.substr(j))
+ }
+ } else if (value.includes('rpx')) {
+ // 转换 rpx(rich-text 内部不支持 rpx)
+ value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px')
+ }
+ styleObj[key] = value
+ }
+ }
+
+ node.attrs.style = tmp
+ return styleObj
+}
+
+/**
+ * @description 解析到标签名
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onTagName = function (name) {
+ this.tagName = this.xml ? name : name.toLowerCase()
+ if (this.tagName === 'svg') {
+ this.xml = (this.xml || 0) + 1 // svg 标签内大小写敏感
+ }
+}
+
+/**
+ * @description 解析到属性名
+ * @param {String} name 属性名
+ * @private
+ */
+Parser.prototype.onAttrName = function (name) {
+ name = this.xml ? name : name.toLowerCase()
+ if (name.substr(0, 5) === 'data-') {
+ if (name === 'data-src' && !this.attrs.src) {
+ // data-src 自动转为 src
+ this.attrName = 'src'
+ } else if (this.tagName === 'img' || this.tagName === 'a') {
+ // a 和 img 标签保留 data- 的属性,可以在 imgtap 和 linktap 事件中使用
+ this.attrName = name
+ } else {
+ // 剩余的移除以减小大小
+ this.attrName = undefined
+ }
+ } else {
+ this.attrName = name
+ this.attrs[name] = 'T' // boolean 型属性缺省设置
+ }
+}
+
+/**
+ * @description 解析到属性值
+ * @param {String} val 属性值
+ * @private
+ */
+Parser.prototype.onAttrVal = function (val) {
+ const name = this.attrName || ''
+ if (name === 'style' || name === 'href') {
+ // 部分属性进行实体解码
+ this.attrs[name] = decodeEntity(val, true)
+ } else if (name.includes('src')) {
+ // 拼接主域名
+ this.attrs[name] = this.getUrl(decodeEntity(val, true))
+ } else if (name) {
+ this.attrs[name] = val
+ }
+}
+
+/**
+ * @description 解析到标签开始
+ * @param {Boolean} selfClose 是否有自闭合标识 />
+ * @private
+ */
+Parser.prototype.onOpenTag = function (selfClose) {
+ // 拼装 node
+ const node = Object.create(null)
+ node.name = this.tagName
+ node.attrs = this.attrs
+ this.attrs = Object.create(null)
+
+ const attrs = node.attrs
+ const parent = this.stack[this.stack.length - 1]
+ const siblings = parent ? parent.children : this.nodes
+ const close = this.xml ? selfClose : config.voidTags[node.name]
+
+ // 替换标签名选择器
+ if (tagSelector[node.name]) {
+ attrs.class = tagSelector[node.name] + (attrs.class ? ' ' + attrs.class : '')
+ }
+
+ // 转换 embed 标签
+ if (node.name === 'embed') {
+ const src = attrs.src || ''
+ // 按照后缀名和 type 将 embed 转为 video 或 audio
+ if (src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8') || (attrs.type || '').includes('video')) {
+ node.name = 'video'
+ } else if (src.includes('.mp3') || src.includes('.wav') || src.includes('.aac') || src.includes('.m4a') || (attrs.type || '').includes('audio')) {
+ node.name = 'audio'
+ }
+ if (attrs.autostart) {
+ attrs.autoplay = 'T'
+ }
+ attrs.controls = 'T'
+ }
+
+ // 处理音视频
+ if (node.name === 'video' || node.name === 'audio') {
+ // 设置 id,用于获取 context
+ if (node.name === 'video' && !attrs.id) {
+ attrs.id = 'v' + idIndex++
+ }
+ // 没有设置 controls 也没有设置 autoplay 的自动设置 controls
+ if (!attrs.controls && !attrs.autoplay) {
+ attrs.controls = 'T'
+ }
+ // 用数组存储所有可用的 source
+ node.src = []
+ if (attrs.src) {
+ node.src.push(attrs.src)
+ attrs.src = undefined
+ }
+ this.expose()
+ }
+
+ // 处理自闭合标签
+ if (close) {
+ // 要被移除的标签
+ if (!this.hook(node) || config.ignoreTags[node.name]) {
+ if (node.name === 'base' && !this.options.domain) {
+ // 通过 base 标签设置主域名
+ this.options.domain = attrs.href
+ } else if (node.name === 'source' && parent && (parent.name === 'video' || parent.name === 'audio') && attrs.src) {
+ // 设置 source 标签(仅父节点为 video 或 audio 时有效)
+ parent.src.push(attrs.src)
+ }
+ return
+ }
+
+ // 解析 style
+ const styleObj = this.parseStyle(node)
+
+ // 处理图片
+ if (node.name === 'img') {
+ if (attrs.src) {
+ // 标记 webp
+ if (attrs.src.includes('webp')) {
+ node.webp = 'T'
+ }
+ // data url 图片如果没有设置 original-src 默认为不可预览的小图片
+ if (attrs.src.includes('data:') && !attrs['original-src']) {
+ attrs.ignore = 'T'
+ }
+ if (!attrs.ignore || node.webp || attrs.src.includes('cloud://')) {
+ for (let i = this.stack.length; i--;) {
+ const item = this.stack[i]
+ if (item.name === 'a') {
+ node.a = item.attrs
+ }
+ if (item.name === 'table' && !node.webp && !attrs.src.includes('cloud://')) {
+ if (!styleObj.display || styleObj.display.includes('inline')) {
+ node.t = 'inline-block'
+ } else {
+ node.t = styleObj.display
+ }
+ styleObj.display = undefined
+ }
+ const style = item.attrs.style || ''
+ if (style.includes('flex:') && !style.includes('flex:0') && !style.includes('flex: 0') && (!styleObj.width || parseInt(styleObj.width) > 100)) {
+ styleObj.width = '100% !important'
+ styleObj.height = ''
+ for (let j = i + 1; j < this.stack.length; j++) {
+ this.stack[j].attrs.style = (this.stack[j].attrs.style || '').replace('inline-', '')
+ }
+ } else if (style.includes('flex') && styleObj.width === '100%') {
+ for (let j = i + 1; j < this.stack.length; j++) {
+ const style = this.stack[j].attrs.style || ''
+ if (!style.includes(';width') && !style.includes(' width') && style.indexOf('width') !== 0) {
+ styleObj.width = ''
+ break
+ }
+ }
+ } else if (style.includes('inline-block')) {
+ if (styleObj.width && styleObj.width[styleObj.width.length - 1] === '%') {
+ item.attrs.style += ';max-width:' + styleObj.width
+ styleObj.width = ''
+ } else {
+ item.attrs.style += ';max-width:100%'
+ }
+ }
+ item.c = 1
+ }
+ node.i = this.imgList.length
+ let src = attrs['original-src'] || attrs.src
+ // #ifndef MP-ALIPAY
+ if (this.imgList.includes(src)) {
+ // 如果有重复的链接则对域名进行随机大小写变换避免预览时错位
+ let i = src.indexOf('://')
+ if (i !== -1) {
+ i += 3
+ let newSrc = src.substr(0, i)
+ for (; i < src.length; i++) {
+ if (src[i] === '/') break
+ newSrc += Math.random() > 0.5 ? src[i].toUpperCase() : src[i]
+ }
+ newSrc += src.substr(i)
+ src = newSrc
+ }
+ }
+ // #endif
+ this.imgList.push(src)
+ if (!node.t) {
+ this.imgList._unloadimgs += 1
+ }
+ }
+ }
+ if (styleObj.display === 'inline') {
+ styleObj.display = ''
+ }
+ if (attrs.ignore) {
+ styleObj['max-width'] = styleObj['max-width'] || '100%'
+ attrs.style += ';-webkit-touch-callout:none'
+ }
+ // 设置的宽度超出屏幕,为避免变形,高度转为自动
+ if (parseInt(styleObj.width) > windowWidth) {
+ styleObj.height = undefined
+ }
+ // 记录是否设置了宽高
+ if (!isNaN(parseInt(styleObj.width))) {
+ node.w = 'T'
+ }
+ if (!isNaN(parseInt(styleObj.height)) && (!styleObj.height.includes('%') || (parent && (parent.attrs.style || '').includes('height')))) {
+ node.h = 'T'
+ }
+ } else if (node.name === 'svg') {
+ siblings.push(node)
+ this.stack.push(node)
+ this.popNode()
+ return
+ }
+ for (const key in styleObj) {
+ if (styleObj[key]) {
+ attrs.style += `;${key}:${styleObj[key].replace(' !important', '')}`
+ }
+ }
+ attrs.style = attrs.style.substr(1) || undefined
+ // #ifdef MP-BAIDU
+ if (!attrs.style) {
+ delete attrs.style
+ }
+ // #endif
+ } else {
+ if ((node.name === 'pre' || ((attrs.style || '').includes('white-space') && attrs.style.includes('pre'))) && this.pre !== 2) {
+ this.pre = node.pre = 1
+ }
+ node.children = []
+ this.stack.push(node)
+ }
+ // 加入节点树
+ siblings.push(node)
+}
+
+/**
+ * @description 解析到标签结束
+ * @param {String} name 标签名
+ * @private
+ */
+Parser.prototype.onCloseTag = function (name) {
+ // 依次出栈到匹配为止
+ name = this.xml ? name : name.toLowerCase()
+ let i
+ for (i = this.stack.length; i--;) {
+ if (this.stack[i].name === name) break
+ }
+ if (i !== -1) {
+ while (this.stack.length > i) {
+ this.popNode()
+ }
+ } else if (name === 'p' || name === 'br') {
+ const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+ siblings.push({
+ name,
+ attrs: {
+ class: tagSelector[name],
+ style: this.tagStyle[name]
+ }
+ })
+ }
+}
+
+/**
+ * @description 处理标签出栈
+ * @private
+ */
+Parser.prototype.popNode = function () {
+ const node = this.stack.pop()
+ let attrs = node.attrs
+ const children = node.children
+ const parent = this.stack[this.stack.length - 1]
+ const siblings = parent ? parent.children : this.nodes
+
+ if (!this.hook(node) || config.ignoreTags[node.name]) {
+ // 获取标题
+ if (node.name === 'title' && children.length && children[0].type === 'text' && this.options.setTitle) {
+ wx.setNavigationBarTitle({
+ title: children[0].text
+ })
+ }
+
+ siblings.pop()
+ return
+ }
+
+ if (node.pre && this.pre !== 2) {
+ // 是否合并空白符标识
+ this.pre = node.pre = undefined
+ for (let i = this.stack.length; i--;) {
+ if (this.stack[i].pre) {
+ this.pre = 1
+ }
+ }
+ }
+
+ // 转换 svg
+ if (node.name === 'svg') {
+ if (this.xml > 1) {
+ // 多层 svg 嵌套
+ this.xml--
+ return
+ }
+ let src = ''
+ const style = attrs.style
+ attrs.style = ''
+ attrs.xmlns = 'http://www.w3.org/2000/svg';
+ (function traversal (node) {
+ if (node.type === 'text') {
+ src += node.text
+ return
+ }
+ const name = config.svgDict[node.name] || node.name
+ src += '<' + name
+ for (const item in node.attrs) {
+ const val = node.attrs[item]
+ if (val) {
+ src += ` ${config.svgDict[item] || item}="${val}"`
+ }
+ }
+ if (!node.children) {
+ src += '/>'
+ } else {
+ src += '>'
+ for (let i = 0; i < node.children.length; i++) {
+ traversal(node.children[i])
+ }
+ src += '' + name + '>'
+ }
+ })(node)
+ node.name = 'img'
+ node.attrs = {
+ src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
+ style,
+ ignore: 'T'
+ }
+ node.children = undefined
+ this.xml = false
+ return
+ }
+
+ const styleObj = {}
+
+ // 转换 align 属性
+ if (attrs.align) {
+ if (node.name === 'table') {
+ if (attrs.align === 'center') {
+ styleObj['margin-inline-start'] = styleObj['margin-inline-end'] = 'auto'
+ } else {
+ styleObj.float = attrs.align
+ }
+ } else {
+ styleObj['text-align'] = attrs.align
+ }
+ attrs.align = undefined
+ }
+
+ // 转换 dir 属性
+ if (attrs.dir) {
+ styleObj.direction = attrs.dir
+ attrs.dir = undefined
+ }
+
+ // 转换 font 标签的属性
+ if (node.name === 'font') {
+ if (attrs.color) {
+ styleObj.color = attrs.color
+ attrs.color = undefined
+ }
+ if (attrs.face) {
+ styleObj['font-family'] = attrs.face
+ attrs.face = undefined
+ }
+ if (attrs.size) {
+ let size = parseInt(attrs.size)
+ if (!isNaN(size)) {
+ if (size < 1) {
+ size = 1
+ } else if (size > 7) {
+ size = 7
+ }
+ styleObj['font-size'] = ['x-small', 'small', 'medium', 'large', 'x-large', 'xx-large', 'xxx-large'][size - 1]
+ }
+ attrs.size = undefined
+ }
+ }
+
+ // 一些编辑器的自带 class
+ if ((attrs.class || '').includes('align-center')) {
+ styleObj['text-align'] = 'center'
+ }
+
+ Object.assign(styleObj, this.parseStyle(node))
+
+ if (node.name !== 'table' && parseInt(styleObj.width) > windowWidth) {
+ styleObj['max-width'] = '100%'
+ styleObj['box-sizing'] = 'border-box'
+ }
+
+ if (config.blockTags[node.name]) {
+ node.name = 'div'
+ } else if (!config.trustTags[node.name] && !this.xml) {
+ // 未知标签转为 span,避免无法显示
+ node.name = 'span'
+ } else if (node.name === 'a' || node.name === 'ad') {
+ this.expose()
+ } else if (node.name === 'video' || node.name === 'audio') {
+ if ((styleObj.height || '').includes('auto')) {
+ styleObj.height = undefined
+ }
+ node.children = undefined
+ } else if ((node.name === 'ul' || node.name === 'ol') && node.c) {
+ // 列表处理
+ const types = {
+ a: 'lower-alpha',
+ A: 'upper-alpha',
+ i: 'lower-roman',
+ I: 'upper-roman'
+ }
+ if (types[attrs.type]) {
+ attrs.style += ';list-style-type:' + types[attrs.type]
+ attrs.type = undefined
+ }
+ node.c = 1
+ for (let i = children.length; i--;) {
+ if (children[i].name === 'li') {
+ children[i].c = 1
+ }
+ }
+ } else if (node.name === 'table') {
+ // 表格处理
+ // cellpadding、cellspacing、border 这几个常用表格属性需要通过转换实现
+ let padding = parseFloat(attrs.cellpadding)
+ let spacing = parseFloat(attrs.cellspacing)
+ const border = parseFloat(attrs.border)
+ const bordercolor = styleObj['border-color']
+ const borderstyle = styleObj['border-style']
+ if (node.c) {
+ // padding 和 spacing 默认 2
+ if (isNaN(padding)) {
+ padding = 2
+ }
+ if (isNaN(spacing)) {
+ spacing = 2
+ }
+ }
+ if (border) {
+ attrs.style += `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}`
+ }
+ if (node.flag && node.c) {
+ node.flag = undefined
+ // 有 colspan 或 rowspan 且含有链接的表格通过 grid 布局实现
+ styleObj.display = 'grid'
+ if (spacing) {
+ styleObj['grid-gap'] = spacing + 'px'
+ styleObj.padding = spacing + 'px'
+ } else if (border) {
+ // 无间隔的情况下避免边框重叠
+ attrs.style += ';border-left:0;border-top:0'
+ }
+
+ const width = [] // 表格的列宽
+ const trList = [] // tr 列表
+ const cells = [] // 保存新的单元格
+ const map = {}; // 被合并单元格占用的格子
+
+ (function traversal (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ if (nodes[i].name === 'tr') {
+ trList.push(nodes[i])
+ } else {
+ traversal(nodes[i].children || [])
+ }
+ }
+ })(children)
+
+ for (let row = 1; row <= trList.length; row++) {
+ let col = 1
+ for (let j = 0; j < trList[row - 1].children.length; j++) {
+ const td = trList[row - 1].children[j]
+ if (td.name === 'td' || td.name === 'th') {
+ // 这个格子被上面的单元格占用,则列号++
+ while (map[row + '.' + col]) {
+ col++
+ }
+ td.c = 1
+ let style = td.attrs.style || ''
+ let start = style.indexOf('width') ? style.indexOf(';width') : 0
+ // 提取出 td 的宽度
+ if (start !== -1) {
+ let end = style.indexOf(';', start + 6)
+ if (end === -1) {
+ end = style.length
+ }
+ if (!td.attrs.colspan) {
+ width[col] = style.substring(start ? start + 7 : 6, end)
+ }
+ style = style.substr(0, start) + style.substr(end)
+ }
+ // 设置竖直对齐
+ style += ';display:flex'
+ start = style.indexOf('vertical-align')
+ if (start !== -1) {
+ const val = style.substr(start + 15, 10)
+ if (val.includes('middle')) {
+ style += ';align-items:center'
+ } else if (val.includes('bottom')) {
+ style += ';align-items:flex-end'
+ }
+ } else {
+ style += ';align-items:center'
+ }
+ // 设置水平对齐
+ start = style.indexOf('text-align')
+ if (start !== -1) {
+ const val = style.substr(start + 11, 10)
+ if (val.includes('center')) {
+ style += ';justify-content: center'
+ } else if (val.includes('right')) {
+ style += ';justify-content: right'
+ }
+ }
+ style = (border ? `;border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'}` + (spacing ? '' : ';border-right:0;border-bottom:0') : '') + (padding ? `;padding:${padding}px` : '') + ';' + style
+ // 处理列合并
+ if (td.attrs.colspan) {
+ style += `;grid-column-start:${col};grid-column-end:${col + parseInt(td.attrs.colspan)}`
+ if (!td.attrs.rowspan) {
+ style += `;grid-row-start:${row};grid-row-end:${row + 1}`
+ }
+ col += parseInt(td.attrs.colspan) - 1
+ }
+ // 处理行合并
+ if (td.attrs.rowspan) {
+ style += `;grid-row-start:${row};grid-row-end:${row + parseInt(td.attrs.rowspan)}`
+ if (!td.attrs.colspan) {
+ style += `;grid-column-start:${col};grid-column-end:${col + 1}`
+ }
+ // 记录下方单元格被占用
+ for (let rowspan = 1; rowspan < td.attrs.rowspan; rowspan++) {
+ for (let colspan = 0; colspan < (td.attrs.colspan || 1); colspan++) {
+ map[(row + rowspan) + '.' + (col - colspan)] = 1
+ }
+ }
+ }
+ if (style) {
+ td.attrs.style = style
+ }
+ cells.push(td)
+ col++
+ }
+ }
+ if (row === 1) {
+ let temp = ''
+ for (let i = 1; i < col; i++) {
+ temp += (width[i] ? width[i] : 'auto') + ' '
+ }
+ styleObj['grid-template-columns'] = temp
+ }
+ }
+ node.children = cells
+ } else {
+ // 没有使用合并单元格的表格通过 table 布局实现
+ if (node.c) {
+ styleObj.display = 'table'
+ }
+ if (!isNaN(spacing)) {
+ styleObj['border-spacing'] = spacing + 'px'
+ }
+ if (border || padding || node.c) {
+ // 遍历
+ (function traversal (nodes) {
+ for (let i = 0; i < nodes.length; i++) {
+ const td = nodes[i]
+ if (node.c) {
+ td.c = 1
+ }
+ if (td.name === 'th' || td.name === 'td') {
+ if (border) {
+ td.attrs.style = `border:${border}px ${borderstyle || 'solid'} ${bordercolor || 'gray'};${td.attrs.style || ''}`
+ }
+ if (padding) {
+ td.attrs.style = `padding:${padding}px;${td.attrs.style || ''}`
+ }
+ } else if (td.children) {
+ traversal(td.children)
+ }
+ }
+ })(children)
+ }
+ }
+ // 给表格添加一个单独的横向滚动层
+ if (this.options.scrollTable && !(attrs.style || '').includes('inline')) {
+ const table = Object.assign({}, node)
+ node.name = 'div'
+ node.attrs = {
+ style: 'overflow-x:auto;padding:1px'
+ }
+ node.children = [table]
+ attrs = table.attrs
+ }
+ } else if ((node.name === 'td' || node.name === 'th') && (attrs.colspan || attrs.rowspan)) {
+ for (let i = this.stack.length; i--;) {
+ if (this.stack[i].name === 'table') {
+ this.stack[i].flag = 1 // 指示含有合并单元格
+ break
+ }
+ }
+ } else if (node.name === 'ruby') {
+ // 转换 ruby
+ node.name = 'span'
+ for (let i = 0; i < children.length - 1; i++) {
+ if (children[i].type === 'text' && children[i + 1].name === 'rt') {
+ children[i] = {
+ name: 'span',
+ attrs: {
+ style: 'display:inline-block;text-align:center'
+ },
+ children: [{
+ name: 'div',
+ attrs: {
+ style: 'font-size:50%;' + (children[i + 1].attrs.style || '')
+ },
+ children: children[i + 1].children
+ }, children[i]]
+ }
+ children.splice(i + 1, 1)
+ }
+ }
+ }
+
+ if ((styleObj.display || '').includes('flex') && !node.c) {
+ for (let i = children.length; i--;) {
+ const item = children[i]
+ if (item.f) {
+ item.attrs.style = (item.attrs.style || '') + item.f
+ item.f = undefined
+ }
+ }
+ }
+
+ // flex 布局时部分样式需要提取到 rich-text 外层
+ const flex = parent && ((parent.attrs.style || '').includes('flex') || (parent.attrs.style || '').includes('grid')) && !node.c
+ // #ifdef MP-WEIXIN || MP-QQ
+ && !(styleObj.display || '').includes('inline') // eslint-disable-line
+ // #endif
+ if (flex) {
+ node.f = ';max-width:100%'
+ }
+
+ if (children.length >= 50 && node.c && !(styleObj.display || '').includes('flex')) {
+ mergeNodes(children)
+ }
+
+ for (const key in styleObj) {
+ if (styleObj[key]) {
+ const val = `;${key}:${styleObj[key].replace(' !important', '')}`
+ if (flex && ((key.includes('flex') && key !== 'flex-direction') || key === 'align-self' || key.includes('grid') || styleObj[key][0] === '-' || (key.includes('width') && val.includes('%')))) {
+ node.f += val
+ if (key === 'width') {
+ attrs.style += ';width:100%'
+ }
+ } else {
+ attrs.style += val
+ }
+ }
+ }
+ attrs.style = attrs.style.substr(1) || undefined
+ // #ifdef MP-BAIDU
+ if (!attrs.style) {
+ delete attrs.style
+ }
+ // #endif
+}
+
+/**
+ * @description 解析到文本
+ * @param {String} text 文本内容
+ */
+Parser.prototype.onText = function (text) {
+ if (!this.pre) {
+ // 合并空白符
+ let trim = ''
+ let flag
+ for (let i = 0, len = text.length; i < len; i++) {
+ if (!blankChar[text[i]]) {
+ trim += text[i]
+ } else {
+ if (trim[trim.length - 1] !== ' ') {
+ trim += ' '
+ }
+ if (text[i] === '\n' && !flag) {
+ flag = true
+ }
+ }
+ }
+ // 去除含有换行符的空串
+ if (trim === ' ' && flag) return
+ text = trim
+ }
+ const node = Object.create(null)
+ node.type = 'text'
+ node.text = decodeEntity(text)
+ if (this.hook(node)) {
+ // #ifdef MP-WEIXIN
+ if (this.options.selectable === 'force' && system.includes('iOS') && !wx.canIUse('rich-text.user-select')) {
+ this.expose()
+ }
+ // #endif
+ const siblings = this.stack.length ? this.stack[this.stack.length - 1].children : this.nodes
+ siblings.push(node)
+ }
+}
+
+/**
+ * @description html 词法分析器
+ * @param {Object} handler 高层处理器
+ */
+function Lexer (handler) {
+ this.handler = handler
+}
+
+/**
+ * @description 执行解析
+ * @param {String} content 要解析的文本
+ */
+Lexer.prototype.parse = function (content) {
+ this.content = content || ''
+ this.i = 0 // 标记解析位置
+ this.start = 0 // 标记一个单词的开始位置
+ this.state = this.text // 当前状态
+ for (let len = this.content.length; this.i !== -1 && this.i < len;) {
+ this.state()
+ }
+}
+
+/**
+ * @description 检查标签是否闭合
+ * @param {String} method 如果闭合要进行的操作
+ * @returns {Boolean} 是否闭合
+ * @private
+ */
+Lexer.prototype.checkClose = function (method) {
+ const selfClose = this.content[this.i] === '/'
+ if (this.content[this.i] === '>' || (selfClose && this.content[this.i + 1] === '>')) {
+ if (method) {
+ this.handler[method](this.content.substring(this.start, this.i))
+ }
+ this.i += selfClose ? 2 : 1
+ this.start = this.i
+ this.handler.onOpenTag(selfClose)
+ if (this.handler.tagName === 'script') {
+ this.i = this.content.indexOf('', this.i)
+ if (this.i !== -1) {
+ this.i += 2
+ this.start = this.i
+ }
+ this.state = this.endTag
+ } else {
+ this.state = this.text
+ }
+ return true
+ }
+ return false
+}
+
+/**
+ * @description 文本状态
+ * @private
+ */
+Lexer.prototype.text = function () {
+ this.i = this.content.indexOf('<', this.i) // 查找最近的标签
+ if (this.i === -1) {
+ // 没有标签了
+ if (this.start < this.content.length) {
+ this.handler.onText(this.content.substring(this.start, this.content.length))
+ }
+ return
+ }
+ const c = this.content[this.i + 1]
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
+ // 标签开头
+ if (this.start !== this.i) {
+ this.handler.onText(this.content.substring(this.start, this.i))
+ }
+ this.start = ++this.i
+ this.state = this.tagName
+ } else if (c === '/' || c === '!' || c === '?') {
+ if (this.start !== this.i) {
+ this.handler.onText(this.content.substring(this.start, this.i))
+ }
+ const next = this.content[this.i + 2]
+ if (c === '/' && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
+ // 标签结尾
+ this.i += 2
+ this.start = this.i
+ this.state = this.endTag
+ return
+ }
+ // 处理注释
+ let end = '-->'
+ if (c !== '!' || this.content[this.i + 2] !== '-' || this.content[this.i + 3] !== '-') {
+ end = '>'
+ }
+ this.i = this.content.indexOf(end, this.i)
+ if (this.i !== -1) {
+ this.i += end.length
+ this.start = this.i
+ }
+ } else {
+ this.i++
+ }
+}
+
+/**
+ * @description 标签名状态
+ * @private
+ */
+Lexer.prototype.tagName = function () {
+ if (blankChar[this.content[this.i]]) {
+ // 解析到标签名
+ this.handler.onTagName(this.content.substring(this.start, this.i))
+ while (blankChar[this.content[++this.i]]);
+ if (this.i < this.content.length && !this.checkClose()) {
+ this.start = this.i
+ this.state = this.attrName
+ }
+ } else if (!this.checkClose('onTagName')) {
+ this.i++
+ }
+}
+
+/**
+ * @description 属性名状态
+ * @private
+ */
+Lexer.prototype.attrName = function () {
+ let c = this.content[this.i]
+ if (blankChar[c] || c === '=') {
+ // 解析到属性名
+ this.handler.onAttrName(this.content.substring(this.start, this.i))
+ let needVal = c === '='
+ const len = this.content.length
+ while (++this.i < len) {
+ c = this.content[this.i]
+ if (!blankChar[c]) {
+ if (this.checkClose()) return
+ if (needVal) {
+ // 等号后遇到第一个非空字符
+ this.start = this.i
+ this.state = this.attrVal
+ return
+ }
+ if (this.content[this.i] === '=') {
+ needVal = true
+ } else {
+ this.start = this.i
+ this.state = this.attrName
+ return
+ }
+ }
+ }
+ } else if (!this.checkClose('onAttrName')) {
+ this.i++
+ }
+}
+
+/**
+ * @description 属性值状态
+ * @private
+ */
+Lexer.prototype.attrVal = function () {
+ const c = this.content[this.i]
+ const len = this.content.length
+ if (c === '"' || c === "'") {
+ // 有冒号的属性
+ this.start = ++this.i
+ this.i = this.content.indexOf(c, this.i)
+ if (this.i === -1) return
+ this.handler.onAttrVal(this.content.substring(this.start, this.i))
+ } else {
+ // 没有冒号的属性
+ for (; this.i < len; this.i++) {
+ if (blankChar[this.content[this.i]]) {
+ this.handler.onAttrVal(this.content.substring(this.start, this.i))
+ break
+ } else if (this.checkClose('onAttrVal')) return
+ }
+ }
+ while (blankChar[this.content[++this.i]]);
+ if (this.i < len && !this.checkClose()) {
+ this.start = this.i
+ this.state = this.attrName
+ }
+}
+
+/**
+ * @description 结束标签状态
+ * @returns {String} 结束的标签名
+ * @private
+ */
+Lexer.prototype.endTag = function () {
+ const c = this.content[this.i]
+ if (blankChar[c] || c === '>' || c === '/') {
+ this.handler.onCloseTag(this.content.substring(this.start, this.i))
+ if (c !== '>') {
+ this.i = this.content.indexOf('>', this.i)
+ if (this.i === -1) return
+ }
+ this.start = ++this.i
+ this.state = this.text
+ } else {
+ this.i++
+ }
+}
+
+module.exports = Parser
diff --git a/pages/index/index.js b/pages/index/index.js
index 0736757..4b9b7ed 100644
--- a/pages/index/index.js
+++ b/pages/index/index.js
@@ -66,6 +66,29 @@ Page({
// '修改【保单上传】的相应内容,上传后需补充相应保单信息。',
],
},
+ //0924 新增参数
+ data_bg_img: _.config.licheImgUrl + 'score/index-panel-bg.png',
+ icon_trend_up: _.config.licheImgUrl + 'score/score-trend-up.png',
+ icon_trend_down: _.config.licheImgUrl + 'score/score-trend-down.png',
+ icon_score_top_1: _.config.licheImgUrl + 'score/score-top-1.png',
+ icon_score_top_2: _.config.licheImgUrl + 'score/score-top-2.png',
+ icon_score_top_3: _.config.licheImgUrl + 'score/score-top-3.png',
+ score_index_bg_up: _.config.licheImgUrl + 'score/score-bg-up.jpg',
+ score_index_bg_down: _.config.licheImgUrl + 'score/score-bg-down.jpg',
+ score_detail_bg_up: _.config.licheImgUrl + 'score/score-detail-up.png',
+ score_detail_bg_down: _.config.licheImgUrl + 'score/score-detail-up.jpg',
+ score_up_color: '#31cbad',
+ score_down_color: '#ff895b',
+ score_trend: 1, //用这个参数控制样式:1 上升 、2 下降
+ score_role_tab: [{
+ id: 1,
+ name: '个人'
+ },{
+ id: 2,
+ name: '门店'
+ }],
+ score_role_cur: 0
+ //0924 end
},
onLoad(options) {
@@ -518,6 +541,13 @@ Page({
})
},
+ //0924
+ changeScoreRoleTab(e){
+ this.setData({
+ score_role_cur:e.currentTarget.dataset.index
+ })
+ },
+
//页面相关事件处理函数--监听用户下拉动作
onPullDownRefresh: function () {
this.setData({
diff --git a/pages/index/index.json b/pages/index/index.json
index a0accc8..a87abcc 100644
--- a/pages/index/index.json
+++ b/pages/index/index.json
@@ -5,6 +5,7 @@
"backgroundColor": "#ffffff",
"backgroundColorTop": "#1a1c26",
"usingComponents": {
- "ec-canvas": "../../ecCanvas/components/ec-canvas/ec-canvas"
+ "ec-canvas": "../../ecCanvas/components/ec-canvas/ec-canvas",
+ "van-circle": "/vant/circle/index"
}
}
\ No newline at end of file
diff --git a/pages/index/index.wxml b/pages/index/index.wxml
index 6fd0f8f..3a7c1a0 100644
--- a/pages/index/index.wxml
+++ b/pages/index/index.wxml
@@ -39,25 +39,62 @@
-
-
-
- 数据看板
-
- 详细
-
+
+
+
+
+ 今日看榜
+
+ 详情
+
+
+
+ {{item.today.value}}/{{item.month.value}}
+ {{item.today.title}}/{{item.month.title}}
+
+
+
-
-
-
- {{item.today.value}}/{{item.month.value}}
- {{item.today.title}}/{{item.month.title}}
+
+
+
+
+ 最新运营分
+
+
+
+ {{item.name}}
+
+
-
+
+
+
+
+
+
+
+
+ 较上日上升100分
+
+
+ *更新于09月10日
+ 当前显示为昨日运营情况评分
+
+
+ 详情
+
+
diff --git a/pages/score/detail.js b/pages/score/detail.js
new file mode 100644
index 0000000..4af3895
--- /dev/null
+++ b/pages/score/detail.js
@@ -0,0 +1,146 @@
+// pages/score/detail.js
+import _ from '../../commons/js/commons'
+const app = getApp()
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ data_bg_img: _.config.licheImgUrl + 'score/index-panel-bg.png',
+ icon_trend_up: _.config.licheImgUrl + 'score/score-trend-up.png',
+ icon_trend_down: _.config.licheImgUrl + 'score/score-trend-down.png',
+ icon_score_top_1: _.config.licheImgUrl + 'score/score-top-1.png',
+ icon_score_top_2: _.config.licheImgUrl + 'score/score-top-2.png',
+ icon_score_top_3: _.config.licheImgUrl + 'score/score-top-3.png',
+ score_index_bg_up: _.config.licheImgUrl + 'score/score-bg-up.jpg',
+ score_index_bg_down: _.config.licheImgUrl + 'score/score-bg-down.jpg',
+ score_detail_bg_up: _.config.licheImgUrl + 'score/score-detail-up.png',
+ score_detail_bg_down: _.config.licheImgUrl + 'score/score-detail-down.png',
+ score_up_color: '#31cbad',
+ score_down_color: '#ff895b',
+ score_trend: 1, //用这个参数控制样式:1 上升 、2 下降
+ list: [{
+ name: '基础分',
+ score: 60,
+ trend: 1,
+ data: [{
+ name: '正常开工',
+ score: '+180'
+ }]
+ }, {
+ name: '线索分',
+ score: 660,
+ trend: 1,
+ data: [{
+ name: '线索建档',
+ score: '+180'
+ },{
+ name: '添加微信',
+ score: '+180'
+ },{
+ name: '跟进小记',
+ score: '+180'
+ },{
+ name: '语音通话',
+ score: '+180'
+ },{
+ name: '二次派发',
+ score: '+180'
+ },{
+ name: '首次跟进',
+ score: '+180'
+ }]
+ }, {
+ name: '订单分',
+ score: 260,
+ trend: 1,
+ data: [{
+ name: '成交数',
+ score: '+180'
+ },{
+ name: '成交率',
+ score: '+180'
+ },{
+ name: '开票率',
+ score: '+180'
+ },{
+ name: '交付率',
+ score: '+180'
+ }]
+ }, {
+ name: '扣分项',
+ score: 260,
+ trend: 2,
+ data: [{
+ name: '逾期未跟进',
+ score: '-80'
+ },{
+ name: '战败未处理',
+ score: '-180'
+ },{
+ name: '开票后录单',
+ score: '-180'
+ },{
+ name: '建档即订单',
+ score: '-180'
+ }]
+ }]
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ }
+})
\ No newline at end of file
diff --git a/pages/score/detail.json b/pages/score/detail.json
new file mode 100644
index 0000000..8835af0
--- /dev/null
+++ b/pages/score/detail.json
@@ -0,0 +1,3 @@
+{
+ "usingComponents": {}
+}
\ No newline at end of file
diff --git a/pages/score/detail.wxml b/pages/score/detail.wxml
new file mode 100644
index 0000000..e8cfefe
--- /dev/null
+++ b/pages/score/detail.wxml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+ 昨日运营分
+ 798
+
+
+ 上一日运营分
+ 798
+
+
+
+
+ 较上日上升100分
+
+
+
+ 本期分数组成
+
+
+
+
+
+ {{item.score}}
+ {{item.name}}
+
+
+
+
+ {{it.name}}
+ {{it.score}}
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/score/detail.wxss b/pages/score/detail.wxss
new file mode 100644
index 0000000..d0fcbbc
--- /dev/null
+++ b/pages/score/detail.wxss
@@ -0,0 +1 @@
+/* pages/score/detail.wxss */
\ No newline at end of file
diff --git a/pages/score/index.js b/pages/score/index.js
new file mode 100644
index 0000000..5a2f4b3
--- /dev/null
+++ b/pages/score/index.js
@@ -0,0 +1,187 @@
+// pages/score/index.js
+import _ from '../../commons/js/commons'
+const app = getApp()
+Page({
+
+ /**
+ * 页面的初始数据
+ */
+ data: {
+ data_bg_img: _.config.licheImgUrl + 'score/index-panel-bg.png',
+ icon_trend_up: _.config.licheImgUrl + 'score/score-trend-up.png',
+ icon_trend_down: _.config.licheImgUrl + 'score/score-trend-down.png',
+ icon_score_top_1: _.config.licheImgUrl + 'score/score-top-1.png',
+ icon_score_top_2: _.config.licheImgUrl + 'score/score-top-2.png',
+ icon_score_top_3: _.config.licheImgUrl + 'score/score-top-3.png',
+ score_index_bg_up: _.config.licheImgUrl + 'score/score-bg-up.jpg',
+ score_index_bg_down: _.config.licheImgUrl + 'score/score-bg-down.jpg',
+ score_detail_bg_up: _.config.licheImgUrl + 'score/score-detail-up.png',
+ score_detail_bg_down: _.config.licheImgUrl + 'score/score-detail-up.jpg',
+ score_up_color: '#31cbad',
+ score_down_color: '#ff895b',
+ score_trend: 1, //用这个参数控制样式:1 上升 、2 下降
+ tab_date: [{
+ id: 1,
+ name: '昨日'
+ }, {
+ id: 2,
+ name: '本月'
+ }],
+ tab_date_cur: 0,
+
+ score_detail_data: [{
+ name: '998',
+ tip: '运营分'
+ }, {
+ name: '=',
+ tip: ''
+ }, {
+ name: '98',
+ tip: '运营分'
+ }, {
+ name: '+',
+ tip: ''
+ }, {
+ name: '98',
+ tip: '运营分'
+ }, {
+ name: '+',
+ tip: ''
+ }, {
+ name: '98',
+ tip: '运营分'
+ }, {
+ name: '+',
+ tip: ''
+ }, {
+ name: '98',
+ tip: '运营分'
+ }],
+
+ tab_rank: [{
+ id: 1,
+ name: '店内排名'
+ }, {
+ id: 2,
+ name: '门店排名'
+ }],
+ tab_rank_cur: 0,
+ rank_data: [{
+ name: '张三',
+ is_manager: true,
+ trend: 1, //1 上升 、2 下降
+ score: '180分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '5分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '80分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 1, //1 上升 、2 下降
+ score: '80分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '5分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '80分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 1, //1 上升 、2 下降
+ score: '80分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '5分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 2, //1 上升 、2 下降
+ score: '80分'
+ }, {
+ name: '张三',
+ is_manager: false,
+ trend: 1, //1 上升 、2 下降
+ score: '80分'
+ }],
+ content: 'asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
asdfasdf
',
+ setid: ''
+ },
+
+ /**
+ * 生命周期函数--监听页面加载
+ */
+ onLoad(options) {
+ wx.setNavigationBarTitle({
+ 'title': '个人运营分'
+ })
+ },
+
+ /**
+ * 生命周期函数--监听页面初次渲染完成
+ */
+ onReady() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面显示
+ */
+ onShow() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面隐藏
+ */
+ onHide() {
+
+ },
+
+ /**
+ * 生命周期函数--监听页面卸载
+ */
+ onUnload() {
+
+ },
+
+ /**
+ * 页面相关事件处理函数--监听用户下拉动作
+ */
+ onPullDownRefresh() {
+
+ },
+
+ /**
+ * 页面上拉触底事件的处理函数
+ */
+ onReachBottom() {
+
+ },
+
+ /**
+ * 用户点击右上角分享
+ */
+ onShareAppMessage() {
+
+ },
+
+ scrollToRule(){
+ this.setData({
+ setid: 'richhtml'
+ })
+ }
+})
\ No newline at end of file
diff --git a/pages/score/index.json b/pages/score/index.json
new file mode 100644
index 0000000..52885e1
--- /dev/null
+++ b/pages/score/index.json
@@ -0,0 +1,6 @@
+{
+ "usingComponents": {
+ "van-circle": "/vant/circle/index",
+ "com-html": "/components/mp-html/index"
+ }
+}
\ No newline at end of file
diff --git a/pages/score/index.wxml b/pages/score/index.wxml
new file mode 100644
index 0000000..709053e
--- /dev/null
+++ b/pages/score/index.wxml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+ {{item.name}}
+
+
+
+ 规则说明
+
+
+
+
+
+
+
+
+ 较上日上升100分
+
+
+ *更新于09月10日
+ 当前显示为昨日运营情况评分
+
+
+
+
+
+
+ {{item.name}}
+ {{item.tip}}
+
+
+
+
+ 查看明细
+
+
+
+
+
+ {{item.name}}
+
+
+
+
+
+
+ {{index+1}}
+
+ {{item.name}}
+ 店长
+
+
+
+ {{item.score}}
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pages/score/index.wxss b/pages/score/index.wxss
new file mode 100644
index 0000000..df76bdb
--- /dev/null
+++ b/pages/score/index.wxss
@@ -0,0 +1,34 @@
+/* pages/score/index.wxss */
+.tab-item::before{
+ content: '';
+ position: absolute;
+ bottom: -12rpx;
+ left:50%;
+ transform: translateX(-50%);
+ width: 0;
+ height: 6rpx;
+ border-radius: 100rpx;
+ background-color: var(--circle-text-color);
+}
+.tab-item-cur{
+ color: var(--circle-text-color);
+}
+.tab-item-cur::before{
+ width: 50rpx;
+}
+
+.link-detail{
+ color: var(--circle-text-color);
+ /* background-color: ; */
+}
+
+.link-detail::after{
+ content: '';
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+ background-color: var(--circle-text-color);
+ opacity: 0.1;
+}
diff --git a/vant/circle/canvas.d.ts b/vant/circle/canvas.d.ts
new file mode 100644
index 0000000..8a0b71e
--- /dev/null
+++ b/vant/circle/canvas.d.ts
@@ -0,0 +1,4 @@
+///
+type CanvasContext = WechatMiniprogram.CanvasContext;
+export declare function adaptor(ctx: CanvasContext & Record): CanvasContext;
+export {};
diff --git a/vant/circle/canvas.js b/vant/circle/canvas.js
new file mode 100644
index 0000000..3ade4cd
--- /dev/null
+++ b/vant/circle/canvas.js
@@ -0,0 +1,43 @@
+export function adaptor(ctx) {
+ // @ts-ignore
+ return Object.assign(ctx, {
+ setStrokeStyle(val) {
+ ctx.strokeStyle = val;
+ },
+ setLineWidth(val) {
+ ctx.lineWidth = val;
+ },
+ setLineCap(val) {
+ ctx.lineCap = val;
+ },
+ setFillStyle(val) {
+ ctx.fillStyle = val;
+ },
+ setFontSize(val) {
+ ctx.font = String(val);
+ },
+ setGlobalAlpha(val) {
+ ctx.globalAlpha = val;
+ },
+ setLineJoin(val) {
+ ctx.lineJoin = val;
+ },
+ setTextAlign(val) {
+ ctx.textAlign = val;
+ },
+ setMiterLimit(val) {
+ ctx.miterLimit = val;
+ },
+ setShadow(offsetX, offsetY, blur, color) {
+ ctx.shadowOffsetX = offsetX;
+ ctx.shadowOffsetY = offsetY;
+ ctx.shadowBlur = blur;
+ ctx.shadowColor = color;
+ },
+ setTextBaseline(val) {
+ ctx.textBaseline = val;
+ },
+ createCircularGradient() { },
+ draw() { },
+ });
+}
diff --git a/vant/circle/index.d.ts b/vant/circle/index.d.ts
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/vant/circle/index.d.ts
@@ -0,0 +1 @@
+export {};
diff --git a/vant/circle/index.js b/vant/circle/index.js
new file mode 100644
index 0000000..0b60888
--- /dev/null
+++ b/vant/circle/index.js
@@ -0,0 +1,197 @@
+import { BLUE, WHITE } from '../common/color';
+import { VantComponent } from '../common/component';
+import { getSystemInfoSync } from '../common/utils';
+import { isObj } from '../common/validator';
+import { canIUseCanvas2d } from '../common/version';
+import { adaptor } from './canvas';
+function format(rate) {
+ return Math.min(Math.max(rate, 0), 100);
+}
+const PERIMETER = 2 * Math.PI;
+const BEGIN_ANGLE = -Math.PI / 2;
+const STEP = 1;
+VantComponent({
+ props: {
+ text: String,
+ lineCap: {
+ type: String,
+ value: 'round',
+ },
+ value: {
+ type: Number,
+ value: 0,
+ observer: 'reRender',
+ },
+ speed: {
+ type: Number,
+ value: 50,
+ },
+ size: {
+ type: Number,
+ value: 100,
+ observer() {
+ this.drawCircle(this.currentValue);
+ },
+ },
+ fill: String,
+ layerColor: {
+ type: String,
+ value: WHITE,
+ },
+ color: {
+ type: null,
+ value: BLUE,
+ observer() {
+ this.setHoverColor().then(() => {
+ this.drawCircle(this.currentValue);
+ });
+ },
+ },
+ type: {
+ type: String,
+ value: '',
+ },
+ strokeWidth: {
+ type: Number,
+ value: 4,
+ },
+ clockwise: {
+ type: Boolean,
+ value: true,
+ },
+ },
+ data: {
+ hoverColor: BLUE,
+ },
+ methods: {
+ getContext() {
+ const { type, size } = this.data;
+ if (type === '' || !canIUseCanvas2d()) {
+ const ctx = wx.createCanvasContext('van-circle', this);
+ return Promise.resolve(ctx);
+ }
+ const dpr = getSystemInfoSync().pixelRatio;
+ return new Promise((resolve) => {
+ wx.createSelectorQuery()
+ .in(this)
+ .select('#van-circle')
+ .node()
+ .exec((res) => {
+ const canvas = res[0].node;
+ const ctx = canvas.getContext(type);
+ if (!this.inited) {
+ this.inited = true;
+ canvas.width = size * dpr;
+ canvas.height = size * dpr;
+ ctx.scale(dpr, dpr);
+ }
+ resolve(adaptor(ctx));
+ });
+ });
+ },
+ setHoverColor() {
+ const { color, size } = this.data;
+ if (isObj(color)) {
+ return this.getContext().then((context) => {
+ if (!context)
+ return;
+ const LinearColor = context.createLinearGradient(size, 0, 0, 0);
+ Object.keys(color)
+ .sort((a, b) => parseFloat(a) - parseFloat(b))
+ .map((key) => LinearColor.addColorStop(parseFloat(key) / 100, color[key]));
+ this.hoverColor = LinearColor;
+ });
+ }
+ this.hoverColor = color;
+ return Promise.resolve();
+ },
+ presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {
+ const { strokeWidth, lineCap, clockwise, size } = this.data;
+ const position = size / 2;
+ const radius = position - strokeWidth / 2;
+ context.setStrokeStyle(strokeStyle);
+ context.setLineWidth(strokeWidth);
+ context.setLineCap(lineCap);
+ context.beginPath();
+ context.arc(position, position, radius, beginAngle, endAngle, !clockwise);
+ context.stroke();
+ if (fill) {
+ context.setFillStyle(fill);
+ context.fill();
+ }
+ },
+ renderLayerCircle(context) {
+ const { layerColor, fill } = this.data;
+ this.presetCanvas(context, layerColor, 0, PERIMETER, fill);
+ },
+ renderHoverCircle(context, formatValue) {
+ const { clockwise } = this.data;
+ // 结束角度
+ const progress = PERIMETER * (formatValue / 100);
+ const endAngle = clockwise
+ ? BEGIN_ANGLE + progress
+ : 3 * Math.PI - (BEGIN_ANGLE + progress);
+ this.presetCanvas(context, this.hoverColor, BEGIN_ANGLE, endAngle);
+ },
+ drawCircle(currentValue) {
+ const { size } = this.data;
+ this.getContext().then((context) => {
+ if (!context)
+ return;
+ context.clearRect(0, 0, size, size);
+ this.renderLayerCircle(context);
+ const formatValue = format(currentValue);
+ if (formatValue !== 0) {
+ this.renderHoverCircle(context, formatValue);
+ }
+ context.draw();
+ });
+ },
+ reRender() {
+ // tofector 动画暂时没有想到好的解决方案
+ const { value, speed } = this.data;
+ if (speed <= 0 || speed > 1000) {
+ this.drawCircle(value);
+ return;
+ }
+ this.clearMockInterval();
+ this.currentValue = this.currentValue || 0;
+ const run = () => {
+ this.interval = setTimeout(() => {
+ if (this.currentValue !== value) {
+ if (Math.abs(this.currentValue - value) < STEP) {
+ this.currentValue = value;
+ }
+ else if (this.currentValue < value) {
+ this.currentValue += STEP;
+ }
+ else {
+ this.currentValue -= STEP;
+ }
+ this.drawCircle(this.currentValue);
+ run();
+ }
+ else {
+ this.clearMockInterval();
+ }
+ }, 1000 / speed);
+ };
+ run();
+ },
+ clearMockInterval() {
+ if (this.interval) {
+ clearTimeout(this.interval);
+ this.interval = null;
+ }
+ },
+ },
+ mounted() {
+ this.currentValue = this.data.value;
+ this.setHoverColor().then(() => {
+ this.drawCircle(this.currentValue);
+ });
+ },
+ destroyed() {
+ this.clearMockInterval();
+ },
+});
diff --git a/vant/circle/index.json b/vant/circle/index.json
new file mode 100644
index 0000000..467ce29
--- /dev/null
+++ b/vant/circle/index.json
@@ -0,0 +1,3 @@
+{
+ "component": true
+}
diff --git a/vant/circle/index.wxml b/vant/circle/index.wxml
new file mode 100644
index 0000000..52bc59f
--- /dev/null
+++ b/vant/circle/index.wxml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+ {{ text }}
+
diff --git a/vant/circle/index.wxss b/vant/circle/index.wxss
new file mode 100644
index 0000000..2200751
--- /dev/null
+++ b/vant/circle/index.wxss
@@ -0,0 +1 @@
+@import '../common/index.wxss';.van-circle{display:inline-block;position:relative;text-align:center}.van-circle__text{color:var(--circle-text-color,#323233);left:0;position:absolute;top:50%;transform:translateY(-50%);width:100%}
\ No newline at end of file
diff --git a/vant/common/color.d.ts b/vant/common/color.d.ts
new file mode 100644
index 0000000..386f307
--- /dev/null
+++ b/vant/common/color.d.ts
@@ -0,0 +1,7 @@
+export declare const RED = "#ee0a24";
+export declare const BLUE = "#1989fa";
+export declare const WHITE = "#fff";
+export declare const GREEN = "#07c160";
+export declare const ORANGE = "#ff976a";
+export declare const GRAY = "#323233";
+export declare const GRAY_DARK = "#969799";
diff --git a/vant/common/color.js b/vant/common/color.js
new file mode 100644
index 0000000..6b285bd
--- /dev/null
+++ b/vant/common/color.js
@@ -0,0 +1,7 @@
+export const RED = '#ee0a24';
+export const BLUE = '#1989fa';
+export const WHITE = '#fff';
+export const GREEN = '#07c160';
+export const ORANGE = '#ff976a';
+export const GRAY = '#323233';
+export const GRAY_DARK = '#969799';
diff --git a/vant/common/component.d.ts b/vant/common/component.d.ts
new file mode 100644
index 0000000..1d0fd27
--- /dev/null
+++ b/vant/common/component.d.ts
@@ -0,0 +1,4 @@
+///
+import { VantComponentOptions } from 'definitions/index';
+declare function VantComponent(vantOptions: VantComponentOptions): void;
+export { VantComponent };
diff --git a/vant/common/component.js b/vant/common/component.js
new file mode 100644
index 0000000..938d96b
--- /dev/null
+++ b/vant/common/component.js
@@ -0,0 +1,46 @@
+import { basic } from '../mixins/basic';
+function mapKeys(source, target, map) {
+ Object.keys(map).forEach((key) => {
+ if (source[key]) {
+ target[map[key]] = source[key];
+ }
+ });
+}
+function VantComponent(vantOptions) {
+ const options = {};
+ mapKeys(vantOptions, options, {
+ data: 'data',
+ props: 'properties',
+ watch: 'observers',
+ mixins: 'behaviors',
+ methods: 'methods',
+ beforeCreate: 'created',
+ created: 'attached',
+ mounted: 'ready',
+ destroyed: 'detached',
+ classes: 'externalClasses',
+ });
+ // add default externalClasses
+ options.externalClasses = options.externalClasses || [];
+ options.externalClasses.push('custom-class');
+ // add default behaviors
+ options.behaviors = options.behaviors || [];
+ options.behaviors.push(basic);
+ // add relations
+ const { relation } = vantOptions;
+ if (relation) {
+ options.relations = relation.relations;
+ options.behaviors.push(relation.mixin);
+ }
+ // map field to form-field behavior
+ if (vantOptions.field) {
+ options.behaviors.push('wx://form-field');
+ }
+ // add default options
+ options.options = {
+ multipleSlots: true,
+ addGlobalClass: true,
+ };
+ Component(options);
+}
+export { VantComponent };
diff --git a/vant/common/index.wxss b/vant/common/index.wxss
new file mode 100644
index 0000000..a73bb7a
--- /dev/null
+++ b/vant/common/index.wxss
@@ -0,0 +1 @@
+.van-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.van-multi-ellipsis--l3{-webkit-line-clamp:3}.van-clearfix:after{clear:both;content:"";display:table}.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{border:0 solid #ebedf0;bottom:-50%;box-sizing:border-box;content:" ";left:-50%;pointer-events:none;position:absolute;right:-50%;top:-50%;transform:scale(.5);transform-origin:center}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
\ No newline at end of file
diff --git a/vant/common/relation.d.ts b/vant/common/relation.d.ts
new file mode 100644
index 0000000..10193fa
--- /dev/null
+++ b/vant/common/relation.d.ts
@@ -0,0 +1,15 @@
+///
+type TrivialInstance = WechatMiniprogram.Component.TrivialInstance;
+export declare function useParent(name: string, onEffect?: (this: TrivialInstance) => void): {
+ relations: {
+ [x: string]: WechatMiniprogram.Component.RelationOption;
+ };
+ mixin: string;
+};
+export declare function useChildren(name: string, onEffect?: (this: TrivialInstance, target: TrivialInstance) => void): {
+ relations: {
+ [x: string]: WechatMiniprogram.Component.RelationOption;
+ };
+ mixin: string;
+};
+export {};
diff --git a/vant/common/relation.js b/vant/common/relation.js
new file mode 100644
index 0000000..04e2934
--- /dev/null
+++ b/vant/common/relation.js
@@ -0,0 +1,56 @@
+export function useParent(name, onEffect) {
+ const path = `../${name}/index`;
+ return {
+ relations: {
+ [path]: {
+ type: 'ancestor',
+ linked() {
+ onEffect && onEffect.call(this);
+ },
+ linkChanged() {
+ onEffect && onEffect.call(this);
+ },
+ unlinked() {
+ onEffect && onEffect.call(this);
+ },
+ },
+ },
+ mixin: Behavior({
+ created() {
+ Object.defineProperty(this, 'parent', {
+ get: () => this.getRelationNodes(path)[0],
+ });
+ Object.defineProperty(this, 'index', {
+ // @ts-ignore
+ get: () => { var _a, _b; return (_b = (_a = this.parent) === null || _a === void 0 ? void 0 : _a.children) === null || _b === void 0 ? void 0 : _b.indexOf(this); },
+ });
+ },
+ }),
+ };
+}
+export function useChildren(name, onEffect) {
+ const path = `../${name}/index`;
+ return {
+ relations: {
+ [path]: {
+ type: 'descendant',
+ linked(target) {
+ onEffect && onEffect.call(this, target);
+ },
+ linkChanged(target) {
+ onEffect && onEffect.call(this, target);
+ },
+ unlinked(target) {
+ onEffect && onEffect.call(this, target);
+ },
+ },
+ },
+ mixin: Behavior({
+ created() {
+ Object.defineProperty(this, 'children', {
+ get: () => this.getRelationNodes(path) || [],
+ });
+ },
+ }),
+ };
+}
diff --git a/vant/common/style/clearfix.wxss b/vant/common/style/clearfix.wxss
new file mode 100644
index 0000000..442246f
--- /dev/null
+++ b/vant/common/style/clearfix.wxss
@@ -0,0 +1 @@
+.van-clearfix:after{clear:both;content:"";display:table}
\ No newline at end of file
diff --git a/vant/common/style/ellipsis.wxss b/vant/common/style/ellipsis.wxss
new file mode 100644
index 0000000..ee701df
--- /dev/null
+++ b/vant/common/style/ellipsis.wxss
@@ -0,0 +1 @@
+.van-ellipsis{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.van-multi-ellipsis--l2{-webkit-line-clamp:2}.van-multi-ellipsis--l2,.van-multi-ellipsis--l3{-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden;text-overflow:ellipsis}.van-multi-ellipsis--l3{-webkit-line-clamp:3}
\ No newline at end of file
diff --git a/vant/common/style/hairline.wxss b/vant/common/style/hairline.wxss
new file mode 100644
index 0000000..f7c6260
--- /dev/null
+++ b/vant/common/style/hairline.wxss
@@ -0,0 +1 @@
+.van-hairline,.van-hairline--bottom,.van-hairline--left,.van-hairline--right,.van-hairline--surround,.van-hairline--top,.van-hairline--top-bottom{position:relative}.van-hairline--bottom:after,.van-hairline--left:after,.van-hairline--right:after,.van-hairline--surround:after,.van-hairline--top-bottom:after,.van-hairline--top:after,.van-hairline:after{border:0 solid #ebedf0;bottom:-50%;box-sizing:border-box;content:" ";left:-50%;pointer-events:none;position:absolute;right:-50%;top:-50%;transform:scale(.5);transform-origin:center}.van-hairline--top:after{border-top-width:1px}.van-hairline--left:after{border-left-width:1px}.van-hairline--right:after{border-right-width:1px}.van-hairline--bottom:after{border-bottom-width:1px}.van-hairline--top-bottom:after{border-width:1px 0}.van-hairline--surround:after{border-width:1px}
\ No newline at end of file
diff --git a/vant/common/style/mixins/clearfix.wxss b/vant/common/style/mixins/clearfix.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/vant/common/style/mixins/ellipsis.wxss b/vant/common/style/mixins/ellipsis.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/vant/common/style/mixins/hairline.wxss b/vant/common/style/mixins/hairline.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/vant/common/style/var.wxss b/vant/common/style/var.wxss
new file mode 100644
index 0000000..e69de29
diff --git a/vant/common/utils.d.ts b/vant/common/utils.d.ts
new file mode 100644
index 0000000..a77d8c6
--- /dev/null
+++ b/vant/common/utils.d.ts
@@ -0,0 +1,21 @@
+///
+///
+///
+///
+///
+export { isDef } from './validator';
+export { getSystemInfoSync } from './version';
+export declare function range(num: number, min: number, max: number): number;
+export declare function nextTick(cb: (...args: any[]) => void): void;
+export declare function addUnit(value?: string | number): string | undefined;
+export declare function requestAnimationFrame(cb: () => void): NodeJS.Timeout;
+export declare function pickExclude(obj: unknown, keys: string[]): {};
+export declare function getRect(context: WechatMiniprogram.Component.TrivialInstance, selector: string): Promise;
+export declare function getAllRect(context: WechatMiniprogram.Component.TrivialInstance, selector: string): Promise;
+export declare function groupSetData(context: WechatMiniprogram.Component.TrivialInstance, cb: () => void): void;
+export declare function toPromise(promiseLike: Promise | unknown): Promise;
+export declare function addNumber(num1: any, num2: any): number;
+export declare const clamp: (num: any, min: any, max: any) => number;
+export declare function getCurrentPage(): T & WechatMiniprogram.OptionalInterface & WechatMiniprogram.Page.InstanceProperties & WechatMiniprogram.Page.InstanceMethods & WechatMiniprogram.Page.Data & WechatMiniprogram.IAnyObject;
+export declare const isPC: boolean;
+export declare const isWxWork: boolean;
diff --git a/vant/common/utils.js b/vant/common/utils.js
new file mode 100644
index 0000000..c84e32b
--- /dev/null
+++ b/vant/common/utils.js
@@ -0,0 +1,86 @@
+import { isDef, isNumber, isPlainObject, isPromise } from './validator';
+import { canIUseGroupSetData, canIUseNextTick, getSystemInfoSync, } from './version';
+export { isDef } from './validator';
+export { getSystemInfoSync } from './version';
+export function range(num, min, max) {
+ return Math.min(Math.max(num, min), max);
+}
+export function nextTick(cb) {
+ if (canIUseNextTick()) {
+ wx.nextTick(cb);
+ }
+ else {
+ setTimeout(() => {
+ cb();
+ }, 1000 / 30);
+ }
+}
+export function addUnit(value) {
+ if (!isDef(value)) {
+ return undefined;
+ }
+ value = String(value);
+ return isNumber(value) ? `${value}px` : value;
+}
+export function requestAnimationFrame(cb) {
+ return setTimeout(() => {
+ cb();
+ }, 1000 / 30);
+}
+export function pickExclude(obj, keys) {
+ if (!isPlainObject(obj)) {
+ return {};
+ }
+ return Object.keys(obj).reduce((prev, key) => {
+ if (!keys.includes(key)) {
+ prev[key] = obj[key];
+ }
+ return prev;
+ }, {});
+}
+export function getRect(context, selector) {
+ return new Promise((resolve) => {
+ wx.createSelectorQuery()
+ .in(context)
+ .select(selector)
+ .boundingClientRect()
+ .exec((rect = []) => resolve(rect[0]));
+ });
+}
+export function getAllRect(context, selector) {
+ return new Promise((resolve) => {
+ wx.createSelectorQuery()
+ .in(context)
+ .selectAll(selector)
+ .boundingClientRect()
+ .exec((rect = []) => resolve(rect[0]));
+ });
+}
+export function groupSetData(context, cb) {
+ if (canIUseGroupSetData()) {
+ context.groupSetData(cb);
+ }
+ else {
+ cb();
+ }
+}
+export function toPromise(promiseLike) {
+ if (isPromise(promiseLike)) {
+ return promiseLike;
+ }
+ return Promise.resolve(promiseLike);
+}
+// 浮点数精度处理
+export function addNumber(num1, num2) {
+ const cardinal = Math.pow(10, 10);
+ return Math.round((num1 + num2) * cardinal) / cardinal;
+}
+// 限制value在[min, max]之间
+export const clamp = (num, min, max) => Math.min(Math.max(num, min), max);
+export function getCurrentPage() {
+ const pages = getCurrentPages();
+ return pages[pages.length - 1];
+}
+export const isPC = ['mac', 'windows'].includes(getSystemInfoSync().platform);
+// 是否企业微信
+export const isWxWork = getSystemInfoSync().environment === 'wxwork';
diff --git a/vant/common/validator.d.ts b/vant/common/validator.d.ts
new file mode 100644
index 0000000..152894a
--- /dev/null
+++ b/vant/common/validator.d.ts
@@ -0,0 +1,9 @@
+export declare function isFunction(val: unknown): val is Function;
+export declare function isPlainObject(val: unknown): val is Record;
+export declare function isPromise(val: unknown): val is Promise;
+export declare function isDef(value: unknown): boolean;
+export declare function isObj(x: unknown): x is Record;
+export declare function isNumber(value: string): boolean;
+export declare function isBoolean(value: unknown): value is boolean;
+export declare function isImageUrl(url: string): boolean;
+export declare function isVideoUrl(url: string): boolean;
diff --git a/vant/common/validator.js b/vant/common/validator.js
new file mode 100644
index 0000000..f11f844
--- /dev/null
+++ b/vant/common/validator.js
@@ -0,0 +1,31 @@
+// eslint-disable-next-line @typescript-eslint/ban-types
+export function isFunction(val) {
+ return typeof val === 'function';
+}
+export function isPlainObject(val) {
+ return val !== null && typeof val === 'object' && !Array.isArray(val);
+}
+export function isPromise(val) {
+ return isPlainObject(val) && isFunction(val.then) && isFunction(val.catch);
+}
+export function isDef(value) {
+ return value !== undefined && value !== null;
+}
+export function isObj(x) {
+ const type = typeof x;
+ return x !== null && (type === 'object' || type === 'function');
+}
+export function isNumber(value) {
+ return /^\d+(\.\d+)?$/.test(value);
+}
+export function isBoolean(value) {
+ return typeof value === 'boolean';
+}
+const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i;
+const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv)/i;
+export function isImageUrl(url) {
+ return IMAGE_REGEXP.test(url);
+}
+export function isVideoUrl(url) {
+ return VIDEO_REGEXP.test(url);
+}
diff --git a/vant/common/version.d.ts b/vant/common/version.d.ts
new file mode 100644
index 0000000..3393221
--- /dev/null
+++ b/vant/common/version.d.ts
@@ -0,0 +1,15 @@
+///
+interface WxWorkSystemInfo extends WechatMiniprogram.SystemInfo {
+ environment?: 'wxwork';
+}
+interface SystemInfo extends WxWorkSystemInfo, WechatMiniprogram.SystemInfo {
+}
+export declare function getSystemInfoSync(): SystemInfo;
+export declare function canIUseModel(): boolean;
+export declare function canIUseFormFieldButton(): boolean;
+export declare function canIUseAnimate(): boolean;
+export declare function canIUseGroupSetData(): boolean;
+export declare function canIUseNextTick(): boolean;
+export declare function canIUseCanvas2d(): boolean;
+export declare function canIUseGetUserProfile(): boolean;
+export {};
diff --git a/vant/common/version.js b/vant/common/version.js
new file mode 100644
index 0000000..c675e1f
--- /dev/null
+++ b/vant/common/version.js
@@ -0,0 +1,59 @@
+let systemInfo;
+export function getSystemInfoSync() {
+ if (systemInfo == null) {
+ systemInfo = wx.getSystemInfoSync();
+ }
+ return systemInfo;
+}
+function 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], 10);
+ const num2 = parseInt(v2[i], 10);
+ if (num1 > num2) {
+ return 1;
+ }
+ if (num1 < num2) {
+ return -1;
+ }
+ }
+ return 0;
+}
+function gte(version) {
+ const system = getSystemInfoSync();
+ return compareVersion(system.SDKVersion, version) >= 0;
+}
+export function canIUseModel() {
+ return gte('2.9.3');
+}
+export function canIUseFormFieldButton() {
+ return gte('2.10.3');
+}
+export function canIUseAnimate() {
+ return gte('2.9.0');
+}
+export function canIUseGroupSetData() {
+ return gte('2.4.0');
+}
+export function canIUseNextTick() {
+ try {
+ return wx.canIUse('nextTick');
+ }
+ catch (e) {
+ return gte('2.7.1');
+ }
+}
+export function canIUseCanvas2d() {
+ return gte('2.9.0');
+}
+export function canIUseGetUserProfile() {
+ return !!wx.getUserProfile;
+}
diff --git a/vant/mixins/basic.d.ts b/vant/mixins/basic.d.ts
new file mode 100644
index 0000000..b273369
--- /dev/null
+++ b/vant/mixins/basic.d.ts
@@ -0,0 +1 @@
+export declare const basic: string;
diff --git a/vant/mixins/basic.js b/vant/mixins/basic.js
new file mode 100644
index 0000000..62da6f9
--- /dev/null
+++ b/vant/mixins/basic.js
@@ -0,0 +1,26 @@
+export const basic = Behavior({
+ methods: {
+ $emit(name, detail, options) {
+ this.triggerEvent(name, detail, options);
+ },
+ set(data) {
+ this.setData(data);
+ return new Promise((resolve) => wx.nextTick(resolve));
+ },
+ // high performance setData
+ setView(data, callback) {
+ const target = {};
+ let hasChange = false;
+ Object.keys(data).forEach((key) => {
+ if (data[key] !== this.data[key]) {
+ target[key] = data[key];
+ hasChange = true;
+ }
+ });
+ if (hasChange) {
+ return this.setData(target, callback);
+ }
+ return callback && callback();
+ },
+ },
+});
diff --git a/vant/mixins/button.d.ts b/vant/mixins/button.d.ts
new file mode 100644
index 0000000..b51db87
--- /dev/null
+++ b/vant/mixins/button.d.ts
@@ -0,0 +1 @@
+export declare const button: string;
diff --git a/vant/mixins/button.js b/vant/mixins/button.js
new file mode 100644
index 0000000..ce22c93
--- /dev/null
+++ b/vant/mixins/button.js
@@ -0,0 +1,51 @@
+import { canIUseGetUserProfile } from '../common/version';
+export const button = Behavior({
+ externalClasses: ['hover-class'],
+ properties: {
+ id: String,
+ buttonId: String,
+ lang: String,
+ businessId: Number,
+ sessionFrom: String,
+ sendMessageTitle: String,
+ sendMessagePath: String,
+ sendMessageImg: String,
+ showMessageCard: Boolean,
+ appParameter: String,
+ ariaLabel: String,
+ openType: String,
+ getUserProfileDesc: String,
+ },
+ data: {
+ canIUseGetUserProfile: canIUseGetUserProfile(),
+ },
+ methods: {
+ onGetUserInfo(event) {
+ this.triggerEvent('getuserinfo', event.detail);
+ },
+ onContact(event) {
+ this.triggerEvent('contact', event.detail);
+ },
+ onGetPhoneNumber(event) {
+ this.triggerEvent('getphonenumber', event.detail);
+ },
+ onGetRealTimePhoneNumber(event) {
+ this.triggerEvent('getrealtimephonenumber', event.detail);
+ },
+ onError(event) {
+ this.triggerEvent('error', event.detail);
+ },
+ onLaunchApp(event) {
+ this.triggerEvent('launchapp', event.detail);
+ },
+ onOpenSetting(event) {
+ this.triggerEvent('opensetting', event.detail);
+ },
+ onAgreePrivacyAuthorization(event) {
+ this.triggerEvent('agreeprivacyauthorization', event.detail);
+ },
+ onChooseAvatar(event) {
+ this.triggerEvent('chooseavatar', event.detail);
+ },
+ },
+});
diff --git a/vant/mixins/link.d.ts b/vant/mixins/link.d.ts
new file mode 100644
index 0000000..d58043b
--- /dev/null
+++ b/vant/mixins/link.d.ts
@@ -0,0 +1 @@
+export declare const link: string;
diff --git a/vant/mixins/link.js b/vant/mixins/link.js
new file mode 100644
index 0000000..8c274e1
--- /dev/null
+++ b/vant/mixins/link.js
@@ -0,0 +1,23 @@
+export const link = Behavior({
+ properties: {
+ url: String,
+ linkType: {
+ type: String,
+ value: 'navigateTo',
+ },
+ },
+ methods: {
+ jumpLink(urlKey = 'url') {
+ const url = this.data[urlKey];
+ if (url) {
+ if (this.data.linkType === 'navigateTo' &&
+ getCurrentPages().length > 9) {
+ wx.redirectTo({ url });
+ }
+ else {
+ wx[this.data.linkType]({ url });
+ }
+ }
+ },
+ },
+});
diff --git a/vant/mixins/page-scroll.d.ts b/vant/mixins/page-scroll.d.ts
new file mode 100644
index 0000000..4625447
--- /dev/null
+++ b/vant/mixins/page-scroll.d.ts
@@ -0,0 +1,6 @@
+///
+///
+type IPageScrollOption = WechatMiniprogram.Page.IPageScrollOption;
+type Scroller = (this: WechatMiniprogram.Component.TrivialInstance, event?: IPageScrollOption) => void;
+export declare function pageScrollMixin(scroller: Scroller): string;
+export {};
diff --git a/vant/mixins/page-scroll.js b/vant/mixins/page-scroll.js
new file mode 100644
index 0000000..e08fb6e
--- /dev/null
+++ b/vant/mixins/page-scroll.js
@@ -0,0 +1,42 @@
+import { isFunction } from '../common/validator';
+import { getCurrentPage, isDef } from '../common/utils';
+function onPageScroll(event) {
+ const { vanPageScroller = [] } = getCurrentPage();
+ vanPageScroller.forEach((scroller) => {
+ if (typeof scroller === 'function') {
+ // @ts-ignore
+ scroller(event);
+ }
+ });
+}
+export function pageScrollMixin(scroller) {
+ return Behavior({
+ attached() {
+ const page = getCurrentPage();
+ if (!isDef(page)) {
+ return;
+ }
+ const _scroller = scroller.bind(this);
+ const { vanPageScroller = [] } = page;
+ if (isFunction(page.onPageScroll) && page.onPageScroll !== onPageScroll) {
+ vanPageScroller.push(page.onPageScroll.bind(page));
+ }
+ vanPageScroller.push(_scroller);
+ page.vanPageScroller = vanPageScroller;
+ page.onPageScroll = onPageScroll;
+ this._scroller = _scroller;
+ },
+ detached() {
+ const page = getCurrentPage();
+ if (!isDef(page) || !isDef(page.vanPageScroller)) {
+ return;
+ }
+ const { vanPageScroller } = page;
+ const index = vanPageScroller.findIndex((v) => v === this._scroller);
+ if (index > -1) {
+ page.vanPageScroller.splice(index, 1);
+ }
+ this._scroller = undefined;
+ },
+ });
+}
diff --git a/vant/mixins/touch.d.ts b/vant/mixins/touch.d.ts
new file mode 100644
index 0000000..35ee831
--- /dev/null
+++ b/vant/mixins/touch.d.ts
@@ -0,0 +1 @@
+export declare const touch: string;
diff --git a/vant/mixins/touch.js b/vant/mixins/touch.js
new file mode 100644
index 0000000..ecefae8
--- /dev/null
+++ b/vant/mixins/touch.js
@@ -0,0 +1,37 @@
+// @ts-nocheck
+const MIN_DISTANCE = 10;
+function getDirection(x, y) {
+ if (x > y && x > MIN_DISTANCE) {
+ return 'horizontal';
+ }
+ if (y > x && y > MIN_DISTANCE) {
+ return 'vertical';
+ }
+ return '';
+}
+export const touch = Behavior({
+ methods: {
+ resetTouchStatus() {
+ this.direction = '';
+ this.deltaX = 0;
+ this.deltaY = 0;
+ this.offsetX = 0;
+ this.offsetY = 0;
+ },
+ touchStart(event) {
+ this.resetTouchStatus();
+ const touch = event.touches[0];
+ this.startX = touch.clientX;
+ this.startY = touch.clientY;
+ },
+ touchMove(event) {
+ const touch = event.touches[0];
+ this.deltaX = touch.clientX - this.startX;
+ this.deltaY = touch.clientY - this.startY;
+ this.offsetX = Math.abs(this.deltaX);
+ this.offsetY = Math.abs(this.deltaY);
+ this.direction =
+ this.direction || getDirection(this.offsetX, this.offsetY);
+ },
+ },
+});
diff --git a/vant/mixins/transition.d.ts b/vant/mixins/transition.d.ts
new file mode 100644
index 0000000..dd829e5
--- /dev/null
+++ b/vant/mixins/transition.d.ts
@@ -0,0 +1 @@
+export declare function transition(showDefaultValue: boolean): string;
diff --git a/vant/mixins/transition.js b/vant/mixins/transition.js
new file mode 100644
index 0000000..5b027ed
--- /dev/null
+++ b/vant/mixins/transition.js
@@ -0,0 +1,129 @@
+// @ts-nocheck
+import { requestAnimationFrame } from '../common/utils';
+import { isObj } from '../common/validator';
+const getClassNames = (name) => ({
+ enter: `van-${name}-enter van-${name}-enter-active enter-class enter-active-class`,
+ 'enter-to': `van-${name}-enter-to van-${name}-enter-active enter-to-class enter-active-class`,
+ leave: `van-${name}-leave van-${name}-leave-active leave-class leave-active-class`,
+ 'leave-to': `van-${name}-leave-to van-${name}-leave-active leave-to-class leave-active-class`,
+});
+export function transition(showDefaultValue) {
+ return Behavior({
+ properties: {
+ customStyle: String,
+ // @ts-ignore
+ show: {
+ type: Boolean,
+ value: showDefaultValue,
+ observer: 'observeShow',
+ },
+ // @ts-ignore
+ duration: {
+ type: null,
+ value: 300,
+ },
+ name: {
+ type: String,
+ value: 'fade',
+ },
+ },
+ data: {
+ type: '',
+ inited: false,
+ display: false,
+ },
+ ready() {
+ if (this.data.show === true) {
+ this.observeShow(true, false);
+ }
+ },
+ methods: {
+ observeShow(value, old) {
+ if (value === old) {
+ return;
+ }
+ value ? this.enter() : this.leave();
+ },
+ enter() {
+ if (this.enterFinishedPromise)
+ return;
+ this.enterFinishedPromise = new Promise((resolve) => {
+ const { duration, name } = this.data;
+ const classNames = getClassNames(name);
+ const currentDuration = isObj(duration) ? duration.enter : duration;
+ if (this.status === 'enter') {
+ return;
+ }
+ this.status = 'enter';
+ this.$emit('before-enter');
+ requestAnimationFrame(() => {
+ if (this.status !== 'enter') {
+ return;
+ }
+ this.$emit('enter');
+ this.setData({
+ inited: true,
+ display: true,
+ classes: classNames.enter,
+ currentDuration,
+ });
+ requestAnimationFrame(() => {
+ if (this.status !== 'enter') {
+ return;
+ }
+ this.transitionEnded = false;
+ this.setData({ classes: classNames['enter-to'] });
+ resolve();
+ });
+ });
+ });
+ },
+ leave() {
+ if (!this.enterFinishedPromise)
+ return;
+ this.enterFinishedPromise.then(() => {
+ if (!this.data.display) {
+ return;
+ }
+ const { duration, name } = this.data;
+ const classNames = getClassNames(name);
+ const currentDuration = isObj(duration) ? duration.leave : duration;
+ this.status = 'leave';
+ this.$emit('before-leave');
+ requestAnimationFrame(() => {
+ if (this.status !== 'leave') {
+ return;
+ }
+ this.$emit('leave');
+ this.setData({
+ classes: classNames.leave,
+ currentDuration,
+ });
+ requestAnimationFrame(() => {
+ if (this.status !== 'leave') {
+ return;
+ }
+ this.transitionEnded = false;
+ setTimeout(() => {
+ this.onTransitionEnd();
+ this.enterFinishedPromise = null;
+ }, currentDuration);
+ this.setData({ classes: classNames['leave-to'] });
+ });
+ });
+ });
+ },
+ onTransitionEnd() {
+ if (this.transitionEnded) {
+ return;
+ }
+ this.transitionEnded = true;
+ this.$emit(`after-${this.status}`);
+ const { show, display } = this.data;
+ if (!show && display) {
+ this.setData({ display: false });
+ }
+ },
+ },
+ });
+}
diff --git a/vant/wxs/add-unit.wxs b/vant/wxs/add-unit.wxs
new file mode 100644
index 0000000..4f33462
--- /dev/null
+++ b/vant/wxs/add-unit.wxs
@@ -0,0 +1,12 @@
+/* eslint-disable */
+var REGEXP = getRegExp('^-?\d+(\.\d+)?$');
+
+function addUnit(value) {
+ if (value == null) {
+ return undefined;
+ }
+
+ return REGEXP.test('' + value) ? value + 'px' : value;
+}
+
+module.exports = addUnit;
diff --git a/vant/wxs/array.wxs b/vant/wxs/array.wxs
new file mode 100644
index 0000000..610089c
--- /dev/null
+++ b/vant/wxs/array.wxs
@@ -0,0 +1,5 @@
+function isArray(array) {
+ return array && array.constructor === 'Array';
+}
+
+module.exports.isArray = isArray;
diff --git a/vant/wxs/bem.wxs b/vant/wxs/bem.wxs
new file mode 100644
index 0000000..1efa129
--- /dev/null
+++ b/vant/wxs/bem.wxs
@@ -0,0 +1,39 @@
+/* eslint-disable */
+var array = require('./array.wxs');
+var object = require('./object.wxs');
+var PREFIX = 'van-';
+
+function join(name, mods) {
+ name = PREFIX + name;
+ mods = mods.map(function(mod) {
+ return name + '--' + mod;
+ });
+ mods.unshift(name);
+ return mods.join(' ');
+}
+
+function traversing(mods, conf) {
+ if (!conf) {
+ return;
+ }
+
+ if (typeof conf === 'string' || typeof conf === 'number') {
+ mods.push(conf);
+ } else if (array.isArray(conf)) {
+ conf.forEach(function(item) {
+ traversing(mods, item);
+ });
+ } else if (typeof conf === 'object') {
+ object.keys(conf).forEach(function(key) {
+ conf[key] && mods.push(key);
+ });
+ }
+}
+
+function bem(name, conf) {
+ var mods = [];
+ traversing(mods, conf);
+ return join(name, mods);
+}
+
+module.exports = bem;
diff --git a/vant/wxs/memoize.wxs b/vant/wxs/memoize.wxs
new file mode 100644
index 0000000..8f7f46d
--- /dev/null
+++ b/vant/wxs/memoize.wxs
@@ -0,0 +1,55 @@
+/**
+ * Simple memoize
+ * wxs doesn't support fn.apply, so this memoize only support up to 2 args
+ */
+/* eslint-disable */
+
+function isPrimitive(value) {
+ var type = typeof value;
+ return (
+ type === 'boolean' ||
+ type === 'number' ||
+ type === 'string' ||
+ type === 'undefined' ||
+ value === null
+ );
+}
+
+// mock simple fn.call in wxs
+function call(fn, args) {
+ if (args.length === 2) {
+ return fn(args[0], args[1]);
+ }
+
+ if (args.length === 1) {
+ return fn(args[0]);
+ }
+
+ return fn();
+}
+
+function serializer(args) {
+ if (args.length === 1 && isPrimitive(args[0])) {
+ return args[0];
+ }
+ var obj = {};
+ for (var i = 0; i < args.length; i++) {
+ obj['key' + i] = args[i];
+ }
+ return JSON.stringify(obj);
+}
+
+function memoize(fn) {
+ var cache = {};
+
+ return function() {
+ var key = serializer(arguments);
+ if (cache[key] === undefined) {
+ cache[key] = call(fn, arguments);
+ }
+
+ return cache[key];
+ };
+}
+
+module.exports = memoize;
diff --git a/vant/wxs/object.wxs b/vant/wxs/object.wxs
new file mode 100644
index 0000000..e077107
--- /dev/null
+++ b/vant/wxs/object.wxs
@@ -0,0 +1,13 @@
+/* eslint-disable */
+var REGEXP = getRegExp('{|}|"', 'g');
+
+function keys(obj) {
+ return JSON.stringify(obj)
+ .replace(REGEXP, '')
+ .split(',')
+ .map(function(item) {
+ return item.split(':')[0];
+ });
+}
+
+module.exports.keys = keys;
diff --git a/vant/wxs/style.wxs b/vant/wxs/style.wxs
new file mode 100644
index 0000000..d88ca7c
--- /dev/null
+++ b/vant/wxs/style.wxs
@@ -0,0 +1,42 @@
+/* eslint-disable */
+var object = require('./object.wxs');
+var array = require('./array.wxs');
+
+function kebabCase(word) {
+ var newWord = word
+ .replace(getRegExp("[A-Z]", 'g'), function (i) {
+ return '-' + i;
+ })
+ .toLowerCase()
+
+ return newWord;
+}
+
+function style(styles) {
+ if (array.isArray(styles)) {
+ return styles
+ .filter(function (item) {
+ return item != null && item !== '';
+ })
+ .map(function (item) {
+ return style(item);
+ })
+ .join(';');
+ }
+
+ if ('Object' === styles.constructor) {
+ return object
+ .keys(styles)
+ .filter(function (key) {
+ return styles[key] != null && styles[key] !== '';
+ })
+ .map(function (key) {
+ return [kebabCase(key), [styles[key]]].join(':');
+ })
+ .join(';');
+ }
+
+ return styles;
+}
+
+module.exports = style;
diff --git a/vant/wxs/utils.wxs b/vant/wxs/utils.wxs
new file mode 100644
index 0000000..f66d33a
--- /dev/null
+++ b/vant/wxs/utils.wxs
@@ -0,0 +1,10 @@
+/* eslint-disable */
+var bem = require('./bem.wxs');
+var memoize = require('./memoize.wxs');
+var addUnit = require('./add-unit.wxs');
+
+module.exports = {
+ bem: memoize(bem),
+ memoize: memoize,
+ addUnit: addUnit
+};