创建仓库
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
project.config.json
|
||||
.idea
|
370
app.js
Normal file
@ -0,0 +1,370 @@
|
||||
/**
|
||||
* tabBar页面路径列表 (用于链接跳转时判断)
|
||||
* tabBarLinks为常量, 无需修改
|
||||
*/
|
||||
const tabBarLinks = [
|
||||
'pages/index/index',
|
||||
'pages/category/index',
|
||||
'pages/flow/index',
|
||||
'pages/user/index'
|
||||
];
|
||||
|
||||
// 站点信息
|
||||
import siteInfo from 'siteinfo.js';
|
||||
|
||||
App({
|
||||
|
||||
/**
|
||||
* 全局变量
|
||||
*/
|
||||
globalData: {
|
||||
user_id: null,
|
||||
},
|
||||
|
||||
api_root: '', // api地址
|
||||
|
||||
/**
|
||||
* 生命周期函数--监听小程序初始化
|
||||
*/
|
||||
onLaunch() {
|
||||
let App = this;
|
||||
// 设置api地址
|
||||
App.setApiRoot();
|
||||
wx.getSystemInfo({
|
||||
success: e => {
|
||||
// 设计稿一般是 750 rpx, 但是 canvas 是 px;
|
||||
// 1rpx 转换成 px 的时候
|
||||
this.globalData.rpx2px = 1 / 750 * e.windowWidth;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 当小程序启动,或从后台进入前台显示,会触发 onShow
|
||||
*/
|
||||
onShow(options) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置api地址
|
||||
*/
|
||||
setApiRoot() {
|
||||
let App = this;
|
||||
App.api_root = `${siteInfo.siteroot}index.php?s=/api/`;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取小程序基础信息
|
||||
*/
|
||||
getWxappBase(callback) {
|
||||
let App = this;
|
||||
App._get('wxapp/base', {}, result => {
|
||||
// 记录小程序基础信息
|
||||
wx.setStorageSync('wxapp', result.data.wxapp);
|
||||
callback && callback(result.data.wxapp);
|
||||
}, false, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* 执行用户登录
|
||||
*/
|
||||
doLogin() {
|
||||
// 保存当前页面
|
||||
let pages = getCurrentPages();
|
||||
if (pages.length) {
|
||||
let currentPage = pages[pages.length - 1];
|
||||
"pages/login/login" != currentPage.route &&
|
||||
wx.setStorageSync("currentPage", currentPage);
|
||||
}
|
||||
// 跳转授权页面
|
||||
wx.navigateTo({
|
||||
url: "/pages/login/login"
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 当前用户id
|
||||
*/
|
||||
getUserId() {
|
||||
return wx.getStorageSync('user_id') || 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示成功提示框
|
||||
*/
|
||||
showSuccess(msg, callback) {
|
||||
wx.showToast({
|
||||
title: msg,
|
||||
icon: 'success',
|
||||
success() {
|
||||
callback && (setTimeout(() => {
|
||||
callback();
|
||||
}, 1500));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 显示失败提示框
|
||||
*/
|
||||
showError(msg, callback) {
|
||||
wx.showModal({
|
||||
title: '友情提示',
|
||||
content: msg,
|
||||
showCancel: false,
|
||||
success(res) {
|
||||
// callback && (setTimeout(() => {
|
||||
// callback();
|
||||
// }, 1500));
|
||||
callback && callback();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* get请求
|
||||
*/
|
||||
_get(url, data, success, fail, complete, check_login) {
|
||||
let App = this;
|
||||
wx.showNavigationBarLoading();
|
||||
|
||||
// 构造请求参数
|
||||
data = Object.assign({
|
||||
wxapp_id: 10001,
|
||||
token: wx.getStorageSync('token')
|
||||
}, data);
|
||||
|
||||
// if (typeof check_login === 'undefined')
|
||||
// check_login = true;
|
||||
|
||||
// 构造get请求
|
||||
let request = () => {
|
||||
data.token = wx.getStorageSync('token');
|
||||
wx.request({
|
||||
url: App.api_root + url,
|
||||
header: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
data,
|
||||
success(res) {
|
||||
if (res.statusCode !== 200 || typeof res.data !== 'object') {
|
||||
console.log(res);
|
||||
App.showError('网络请求出错');
|
||||
return false;
|
||||
}
|
||||
if (res.data.code === -1) {
|
||||
// 登录态失效, 重新登录
|
||||
wx.hideNavigationBarLoading();
|
||||
App.doLogin();
|
||||
} else if (res.data.code === 0) {
|
||||
App.showError(res.data.msg);
|
||||
return false;
|
||||
} else {
|
||||
success && success(res.data);
|
||||
}
|
||||
},
|
||||
fail(res) {
|
||||
// console.log(res);
|
||||
App.showError(res.errMsg, () => {
|
||||
fail && fail(res);
|
||||
});
|
||||
},
|
||||
complete(res) {
|
||||
wx.hideNavigationBarLoading();
|
||||
complete && complete(res);
|
||||
},
|
||||
});
|
||||
};
|
||||
// 判断是否需要验证登录
|
||||
check_login ? App.doLogin(request) : request();
|
||||
},
|
||||
|
||||
/**
|
||||
* post提交
|
||||
*/
|
||||
_post_form(url, data, success, fail, complete) {
|
||||
wx.showNavigationBarLoading();
|
||||
let App = this;
|
||||
// 构造请求参数
|
||||
data = Object.assign({
|
||||
wxapp_id: 10001,
|
||||
token: wx.getStorageSync('token')
|
||||
}, data);
|
||||
wx.request({
|
||||
url: App.api_root + url,
|
||||
header: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
method: 'POST',
|
||||
data,
|
||||
success(res) {
|
||||
if (res.statusCode !== 200 || typeof res.data !== 'object') {
|
||||
App.showError('网络请求出错');
|
||||
return false;
|
||||
}
|
||||
if (res.data.code === -1) {
|
||||
// 登录态失效, 重新登录
|
||||
App.doLogin(() => {
|
||||
App._post_form(url, data, success, fail);
|
||||
});
|
||||
return false;
|
||||
} else if (res.data.code === 0) {
|
||||
App.showError(res.data.msg, () => {
|
||||
fail && fail(res);
|
||||
});
|
||||
return false;
|
||||
}
|
||||
success && success(res.data);
|
||||
},
|
||||
fail(res) {
|
||||
// console.log(res);
|
||||
App.showError(res.errMsg, () => {
|
||||
fail && fail(res);
|
||||
});
|
||||
},
|
||||
complete(res) {
|
||||
wx.hideLoading();
|
||||
wx.hideNavigationBarLoading();
|
||||
complete && complete(res);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证是否存在user_info
|
||||
*/
|
||||
validateUserInfo() {
|
||||
let user_info = wx.getStorageSync('user_info');
|
||||
return !!wx.getStorageSync('user_info');
|
||||
},
|
||||
|
||||
/**
|
||||
* 对象转URL
|
||||
*/
|
||||
urlEncode(data) {
|
||||
var _result = [];
|
||||
for (var key in data) {
|
||||
var value = data[key];
|
||||
if (value.constructor == Array) {
|
||||
value.forEach(_value => {
|
||||
_result.push(key + "=" + _value);
|
||||
});
|
||||
} else {
|
||||
_result.push(key + '=' + value);
|
||||
}
|
||||
}
|
||||
return _result.join('&');
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置当前页面标题
|
||||
*/
|
||||
setTitle() {
|
||||
let App = this,
|
||||
wxapp;
|
||||
if (wxapp = wx.getStorageSync('wxapp')) {
|
||||
wx.setNavigationBarTitle({
|
||||
title: wxapp.navbar.wxapp_title
|
||||
});
|
||||
} else {
|
||||
App.getWxappBase(() => {
|
||||
App.setTitle();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 设置navbar标题、颜色
|
||||
*/
|
||||
setNavigationBar() {
|
||||
let App = this;
|
||||
// 获取小程序基础信息
|
||||
App.getWxappBase(wxapp => {
|
||||
// 设置navbar标题、颜色
|
||||
wx.setNavigationBarColor({
|
||||
frontColor: wxapp.navbar.top_text_color.text,
|
||||
backgroundColor: wxapp.navbar.top_background_color
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取tabBar页面路径列表
|
||||
*/
|
||||
getTabBarLinks() {
|
||||
return tabBarLinks;
|
||||
},
|
||||
|
||||
/**
|
||||
* 验证登录
|
||||
*/
|
||||
checkIsLogin() {
|
||||
return wx.getStorageSync('user_id') != '';
|
||||
},
|
||||
|
||||
/**
|
||||
* 授权登录
|
||||
*/
|
||||
getUserInfo(userInfo,user_id, callback) {
|
||||
let App = this;
|
||||
wx.showLoading({
|
||||
title: "正在授权",
|
||||
mask: true
|
||||
});
|
||||
// 执行微信登录
|
||||
wx.login({
|
||||
success(res) {
|
||||
// 发送用户信息
|
||||
App._post_form('user/login', {
|
||||
code: res.code,
|
||||
user_id: user_id,
|
||||
user_info: JSON.stringify(userInfo)
|
||||
}, result => {
|
||||
// 记录token user_id
|
||||
wx.setStorageSync('token', result.data.token);
|
||||
// 执行回调函数
|
||||
callback && callback();
|
||||
}, false, () => {
|
||||
wx.hideLoading();
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 绑定用户身份证号
|
||||
*/
|
||||
getUserInfoByIdCard(idCard, callback) {
|
||||
let App = this;
|
||||
wx.showLoading({
|
||||
title: "正在验证身份证号",
|
||||
mask: true
|
||||
});
|
||||
App._post_form('user/checkIdCard',{
|
||||
idCard:idCard
|
||||
}, result => {
|
||||
//记录user_id
|
||||
if(!result.data.user_id){
|
||||
wx.showToast({
|
||||
title: '身份证号不存在',
|
||||
icon: 'error',
|
||||
duration: 2000
|
||||
})
|
||||
}else{
|
||||
wx.setStorageSync('user_id', result.data.user_id);
|
||||
// 执行回调函数
|
||||
callback(result.data.user_id);
|
||||
}
|
||||
|
||||
}, false, () => {
|
||||
wx.hideLoading();
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
});
|
75
app.json
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/index/index",
|
||||
"pages/rank/index",
|
||||
"pages/rank/address",
|
||||
"pages/rank/addInfo",
|
||||
"pages/category/index",
|
||||
"pages/category/challenge",
|
||||
"pages/user/index",
|
||||
"pages/user/sign",
|
||||
"pages/login/login",
|
||||
"pages/topic/index",
|
||||
"pages/topic/addList",
|
||||
"pages/topic/addInfo",
|
||||
"pages/topic/xunzhang",
|
||||
"pages/topic/address",
|
||||
"pages/topic/detail",
|
||||
"pages/category/team"
|
||||
],
|
||||
"subpackages": [
|
||||
{
|
||||
"root": "packageA",
|
||||
"pages": [
|
||||
"user/help",
|
||||
"user/myChallenge",
|
||||
"user/myMedal",
|
||||
"user/profile",
|
||||
"user/editProfile"
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "packageB",
|
||||
"pages": [
|
||||
"index/index",
|
||||
"rule/index",
|
||||
"user/sign"
|
||||
]
|
||||
}
|
||||
],
|
||||
"window": {
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTitleText": "",
|
||||
"navigationBarTextStyle": "black",
|
||||
"backgroundTextStyle": "dark"
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#6e6d6b",
|
||||
"selectedColor": "#890001",
|
||||
"borderStyle": "black",
|
||||
"backgroundColor": "#ffffff",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页",
|
||||
"iconPath": "images/tabBar/home.png",
|
||||
"selectedIconPath": "images/tabBar/home_on.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/rank/index",
|
||||
"text": "排行榜",
|
||||
"iconPath": "images/tabBar/cate.png",
|
||||
"selectedIconPath": "images/tabBar/cate_on.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/user/index",
|
||||
"text": "我的",
|
||||
"iconPath": "images/tabBar/user.png",
|
||||
"selectedIconPath": "images/tabBar/user_on.png"
|
||||
}
|
||||
],
|
||||
"position": "bottom"
|
||||
},
|
||||
"debug": false,
|
||||
"sitemapLocation": "sitemap.json"
|
||||
}
|
927
app.wxss
Normal file
@ -0,0 +1,927 @@
|
||||
/* common.wxss */
|
||||
@import "/utils/common.wxss";
|
||||
@import "/common.wxss";
|
||||
@import 'weui.wxss';
|
||||
page {
|
||||
background: #f7f7f7;
|
||||
}
|
||||
|
||||
.common-header-xian {
|
||||
border-top: 1rpx solid #eee;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.del {
|
||||
text-decoration: line-through;
|
||||
padding-left: 10rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 没有更多 */
|
||||
|
||||
.no-more {
|
||||
text-align: center;
|
||||
color: #737373;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.yoshop-notcont {
|
||||
margin: 130rpx 100rpx;
|
||||
}
|
||||
|
||||
.yoshop-notcont .cont {
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 30rpx;
|
||||
color: #999;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.yoshop-notcont .iconfont {
|
||||
font-size: 150rpx;
|
||||
color: #ccc;
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.yoshop-notcont .img {
|
||||
width: 200px;
|
||||
height: 120px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.yoshop-notcont .img image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.category-list {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.category-list .list {
|
||||
box-sizing: border-box;
|
||||
width: 50%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.category-list .list:nth-child(2n) {
|
||||
border-left: 2px solid #f7f7f7;
|
||||
border-bottom: 4px solid #f7f7f7;
|
||||
}
|
||||
|
||||
.category-list .list:nth-child(2n-1) {
|
||||
border-right: 2px solid #f7f7f7;
|
||||
border-bottom: 4px solid #f7f7f7;
|
||||
}
|
||||
|
||||
.category-list .list .left, .category-list .right {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.category-list .list .left .img image {
|
||||
width: 100%;
|
||||
height: 375rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.category-list .right .cont {
|
||||
padding: 0 12rpx;
|
||||
}
|
||||
|
||||
.category-list .right .cont .title {
|
||||
height: 76rpx;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.category-list.arrange .list {
|
||||
overflow: hidden;
|
||||
padding: 15rpx;
|
||||
border-bottom: 1rpx solid #f7f7f7;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.category-list.arrange .list .left {
|
||||
width: 35%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.category-list.arrange .list .right {
|
||||
width: 65%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.category-list.arrange .list .left .img image {
|
||||
width: 220rpx;
|
||||
height: 220rpx;
|
||||
}
|
||||
|
||||
.button-common button {
|
||||
background: none;
|
||||
line-height: inherit;
|
||||
border-radius: 0;
|
||||
border: 0;
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.button-common button[disabled]:not([type]) {
|
||||
color: #fff;
|
||||
background-color: #ff495e;
|
||||
}
|
||||
|
||||
.button-common button::after {
|
||||
content: " ";
|
||||
width: 0;
|
||||
height: 0;
|
||||
border: none;
|
||||
transform: scale(0);
|
||||
transform-origin: 0 0;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.commont-fixed-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #fff;
|
||||
border-top: 1rpx solid #ddd;
|
||||
padding: 3px 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.commont-fixed-footer .li {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.commont-fixed-footer .li.active {
|
||||
color: #ff495e;
|
||||
}
|
||||
|
||||
.commont-fixed-footer .li image {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
}
|
||||
|
||||
.bargain-mol {
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: -100%;
|
||||
z-index: 120;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.bargain-mol.active {
|
||||
bottom: 0;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.bargain-mol .header {
|
||||
background: #f1f1f5;
|
||||
}
|
||||
|
||||
.bargain-mol .footer {
|
||||
background: #ff495e;
|
||||
padding: 26rpx 0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.bargain-mol .max-cont {
|
||||
height: 600rpx;
|
||||
}
|
||||
|
||||
.bargain-mol .icon-guanbi {
|
||||
font-size: 34rpx;
|
||||
float: right;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bargain-commont-bg {
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
.selectNumber {
|
||||
height: 34px;
|
||||
flex-direction: row;
|
||||
border: 1rpx solid #eee;
|
||||
border-radius: 10rpx;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.selectNumber .default {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
float: left;
|
||||
line-height: 32px;
|
||||
padding: 0;
|
||||
background: #fff;
|
||||
color: #444;
|
||||
font-size: 48rpx;
|
||||
}
|
||||
|
||||
.selectNumber .default-active {
|
||||
background: #f7f7f7;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.selectNumber button:after {
|
||||
content: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.selectNumber input {
|
||||
float: left;
|
||||
width: 50px;
|
||||
height: 34px;
|
||||
line-height: 34px;
|
||||
border-right: 1rpx solid #eee;
|
||||
border-left: 1rpx solid #eee;
|
||||
text-align: center;
|
||||
font-size: 28rpx;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
/* 返回顶部 */
|
||||
|
||||
.widget-goTop {
|
||||
position: fixed;
|
||||
bottom: 150rpx;
|
||||
z-index: 20;
|
||||
right: 12px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 76rpx;
|
||||
border: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.widget-goTop .icon-fanhuidingbu {
|
||||
color: #666;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 76rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.index-loading .loading {
|
||||
border-radius: 100%;
|
||||
margin: 150rpx auto 0;
|
||||
animation-fill-mode: both;
|
||||
border: 2px solid #ff495e;
|
||||
border-bottom-color: transparent;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
background: transparent !important;
|
||||
animation: rotate 0.75s 0s linear infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotate {
|
||||
0% {
|
||||
transform: rotate(0deg) scale(1);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotate {
|
||||
0% {
|
||||
transform: rotate(0deg) scale(1);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.title-header {
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
font-weight: 700;
|
||||
margin-left: -10rpx;
|
||||
}
|
||||
|
||||
.title-footer {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
overflow: hidden;
|
||||
color: #888;
|
||||
text-align: center;
|
||||
margin: 0 18rpx 0;
|
||||
}
|
||||
|
||||
.title-footer .cont {
|
||||
padding: 0 12rpx;
|
||||
font-size: 28rpx;
|
||||
z-index: 10;
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
||||
.title-footer .hr {
|
||||
background: #eee;
|
||||
height: 1rpx;
|
||||
border: 0;
|
||||
position: absolute;
|
||||
left: 10%;
|
||||
right: 10%;
|
||||
top: 50%;
|
||||
margin-top: 1px;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.slide-image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.index_sale {
|
||||
background: #fff;
|
||||
padding: 0 12px 12px 12px;
|
||||
}
|
||||
|
||||
.index_sale .nav_img, .index-list .nav_img {
|
||||
padding: 30rpx 0 0 0;
|
||||
width: 100%;
|
||||
height: 30rpx;
|
||||
}
|
||||
|
||||
.index_sale scroll-view {
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.index_sale .sale_img {
|
||||
border: 1rpx solid #f2f2f2;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 300rpx;
|
||||
}
|
||||
|
||||
.index_sale .sale_img image {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.index_sale .price {
|
||||
margin-top: 10rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.index_sale .page-column {
|
||||
padding: 0 11rpx 11rpx 0;
|
||||
}
|
||||
|
||||
.index_sale .content {
|
||||
width: 170rpx;
|
||||
}
|
||||
|
||||
.index_sale .content text {
|
||||
font-size: 26rpx;
|
||||
margin: 5rpx 10rpx;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
.flex {
|
||||
display: flex;
|
||||
} */
|
||||
|
||||
.goods-comment-box .admin {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
padding-right: 10rpx;
|
||||
}
|
||||
|
||||
.goods-comment-cont {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin: 10rpx 0;
|
||||
}
|
||||
|
||||
.footer-fixed {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
height: 46px;
|
||||
z-index: 18;
|
||||
box-shadow: 1px 5px 15px rgba(50, 50, 50, 0.3);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.order-bt {
|
||||
width: 50%;
|
||||
background-color: #ff495e;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 46px;
|
||||
}
|
||||
|
||||
.swiper-box .wx-swiper-dot {
|
||||
/* width: 0rpx;
|
||||
height: 0rpx; */
|
||||
}
|
||||
|
||||
.goods_comment_box .comment_btn {
|
||||
width: 220rpx;
|
||||
margin: 0 auto;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.goods_comment_box .comment_btn text {
|
||||
display: block;
|
||||
padding: 5rpx 0;
|
||||
color: #ff495e;
|
||||
font-size: 26rpx;
|
||||
text-align: center;
|
||||
border: 1px solid #ff495e;
|
||||
border-radius: 30rpx;
|
||||
}
|
||||
|
||||
.goods-detail-box {
|
||||
padding: 0;
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
.com_xing .icon-shoucang1 {
|
||||
padding-right: 6rpx;
|
||||
color: #ccc;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.com_xing .icon-shoucang1.active {
|
||||
color: #f4a213;
|
||||
}
|
||||
|
||||
.goods-comment-box .left {
|
||||
flex: 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.goods-comment-box .right {
|
||||
flex: 3;
|
||||
}
|
||||
|
||||
.bright789-text {
|
||||
font-size: 40rpx;
|
||||
line-height: 40px;
|
||||
color: #f00;
|
||||
}
|
||||
|
||||
.bright789_view_hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.bright789_view_show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.com_xing {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.flow-checkout-header {
|
||||
padding: 28rpx 0;
|
||||
background: #fff url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANYAAAANCAYAAADVGpDCAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA4ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo3Yjk4M2ExYy1jMDhkLTQ1OTktYTI0Ny1kZjNjYzdiYTQ5ZTgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDQwNkY3RkU5N0NGMTFFNUI3N0M4NTU4MzM2RjlFODIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDQwNkY3RkQ5N0NGMTFFNUI3N0M4NTU4MzM2RjlFODIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDowNzgwZWI1NS03OGFhLTQzOTUtODQ4OC1lOWI5YmVlYTY1ZDciIHN0UmVmOmRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDo1OTRiYzUyMy1jMzc3LTExNzgtYTdkZS04NGY3YmM1ZGIxMDMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz556PLxAAACBElEQVR42tyaSyhEYRTHP48imlKibDQeSSlkSlEWLCRFsZNH5FE2FqQ8ErIRC9lIkTwXSpMkWWChhEJCSnlkoUZGSsr78f98n43CMFPu/Z/6NZuZ2zn33/+cb869XkmLx8IDEQaGQJbgiytQDSY3MyL+LYnL/HxPXSoHDIJQQq2WQQk4Dbbb/yUB29LJ+6e3B66VB3ZITbUIEqSpCGoJBP1ghtBUD6ARpEtTGSEhXzd+awE9oJzQUPegWdf3QlBPMhgDMYRa7YNisGWkpP5qrBQtVBShUHugUE9hs4fUtwG0utlEjRivoA/Ug1sj3vjffr8FNJEK1auPFHcE9UTq5pdK2PwcoAzMG7mjuRrRYEIfK9jiDJSCBZJ6ynSTsBBqNQ0qgdPISbq6vJCFbJOaagrEk5gqWNczRGiqG1Ah1LLMafRkf5pYIUKtZnMJDXUNasAIST2ZYFioRx9ssQaKwJFZEv5uYmWDXVJTrYBEElP562PfPKGpnkAbSDOTqb6aWAGgW6iHol5kQj2CdtAJngnqkc1hHMQRNr9DPaXWzZj8Z2PZtFCxhEIdaKE2CGqRJ4060AH8CLUaALX6f5VpBZLhI9SaeZXQVHKNLt84SCIxVbhQi5YuQlNd6OVElZlN9TGxrGBUn2PZ4lyoTdIsST0FQj0UDSLUak6ot3gcBLVY3wQYAJoVXxmNERajAAAAAElFTkSuQmCC') bottom left repeat-x;
|
||||
background-size: 120rpx auto;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flow-header-left {
|
||||
flex: 14;
|
||||
}
|
||||
|
||||
.flow-header-right {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.flow-header-right image {
|
||||
width: 34rpx;
|
||||
height: 34rpx;
|
||||
margin-top: 20rpx;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.flow-checkout-header .flow-checkout-address {
|
||||
font-size: 26rpx;
|
||||
color: #777;
|
||||
margin-top: 6rpx;
|
||||
}
|
||||
|
||||
.flow-shopList {
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-left {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-left image {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
border: 1rpx solid #eee;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-right {
|
||||
flex: 4;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-right .h4 {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-right .flow-cont {
|
||||
font-size: 30rpx;
|
||||
color: #ff495e;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-right .small {
|
||||
float: right;
|
||||
font-size: 26rpx;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-right .flow-list-cont {
|
||||
padding-top: 10rpx;
|
||||
}
|
||||
|
||||
.flow-fixed-footer {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: #fff;
|
||||
border-top: 1px solid #eee;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
.flow-num-box {
|
||||
font-size: 30rpx;
|
||||
color: #777;
|
||||
padding: 15rpx 12px;
|
||||
text-align: right;
|
||||
/* border-top: 1rpx solid #f1f1f1; */
|
||||
}
|
||||
|
||||
.flow-all-money {
|
||||
padding: 8px 12px;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.flow-all-money .flow-all-list {
|
||||
font-size: 30rpx;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f1f1f1;
|
||||
}
|
||||
|
||||
.flow-all-money .flow-all-list:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.flow-all-money .flow-all-list-cont {
|
||||
font-size: 28rpx;
|
||||
padding: 6rpx 0;
|
||||
}
|
||||
|
||||
.flow-all-money .flow-arrow {
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flow-fixed-footer .chackout-left {
|
||||
font-size: 32rpx;
|
||||
line-height: 46px;
|
||||
color: #777;
|
||||
flex: 4;
|
||||
padding-left: 12px;
|
||||
}
|
||||
|
||||
.flow-fixed-footer .chackout-right {
|
||||
font-size: 34rpx;
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
.flow-btn {
|
||||
background-color: #ff495e;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
line-height: 46px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.flow-list .header .shop_name {
|
||||
padding-left: 10rpx;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.flow-list .header .icon-dianpu2 {
|
||||
color: #ff495e;
|
||||
padding-left: 20rpx;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.flow-list .header image {
|
||||
width: 34rpx;
|
||||
height: 37rpx;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
margin-top: -18rpx;
|
||||
left: 15px;
|
||||
}
|
||||
|
||||
.flow-list .header {
|
||||
background: #fdf9f9;
|
||||
padding: 24rpx 0;
|
||||
border-top: 1rpx solid #eee;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
font-size: 30rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.flow-list custom-li, .addres-list custom-li {
|
||||
margin-top: 25rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.flow-list custom-li:first-child, .addres-list custom-li:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.flow-distribution-right .icon-xiangyoujiantou {
|
||||
font-size: 26rpx;
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
margin-top: -16rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.flow-checkout-address text {
|
||||
padding-right: 5rpx;
|
||||
}
|
||||
|
||||
.flow-header-right .icon-xiangyoujiantou {
|
||||
position: absolute;
|
||||
right: 15px;
|
||||
top: 50%;
|
||||
margin-top: -13rpx;
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wxParse-em, .WxEmojiView {
|
||||
display: inline-block;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.flow-shopList .flow-list-left image {
|
||||
width: 180rpx;
|
||||
height: 180rpx;
|
||||
}
|
||||
|
||||
.profile-btn button {
|
||||
background: #ff495e;
|
||||
color: white;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.flow-checkout-header .icon-dingwei1 {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 15px;
|
||||
font-size: 40rpx;
|
||||
color: #777;
|
||||
margin-top: -20rpx;
|
||||
}
|
||||
|
||||
/*
|
||||
.index-cont-search {
|
||||
width: 85%;
|
||||
font-size: 32rpx;
|
||||
} */
|
||||
|
||||
.index-cont-search {
|
||||
width: 100%;
|
||||
font-size: 28rpx;
|
||||
position: relative;
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
.index-cont-search icon {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -70rpx;
|
||||
top: 50%;
|
||||
margin-top: -15rpx;
|
||||
}
|
||||
|
||||
.index-cont-search text {
|
||||
margin-left: 72rpx;
|
||||
}
|
||||
|
||||
@-webkit-keyframes shop {
|
||||
0% {
|
||||
transform: translateY(-80px);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(-80px);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shop {
|
||||
0% {
|
||||
transform: translateY(-80px);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: translateY(0px);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: translateY(-80px);
|
||||
}
|
||||
}
|
||||
|
||||
.user-order {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.user-orderIcon {
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
padding-left: 15rpx;
|
||||
margin-top: 15rpx;
|
||||
}
|
||||
|
||||
.user-orderName {
|
||||
font-size: 30rpx;
|
||||
color: #444;
|
||||
position: absolute;
|
||||
left: 90rpx;
|
||||
top: 50%;
|
||||
margin-top: -21rpx;
|
||||
}
|
||||
|
||||
.user-orderJtou {
|
||||
color: #777;
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.user-orderCont {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.user-orderContBox {
|
||||
float: right;
|
||||
padding: 15rpx;
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.address-box .left-name {
|
||||
width: 95px;
|
||||
}
|
||||
|
||||
.address-box .right-cont {
|
||||
padding-right: 15px;
|
||||
font-size: 30rpx;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.address-box .right-cont input {
|
||||
width: 100%;
|
||||
font-size: 30rpx;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.address-cont-box picker {
|
||||
display: inline-block;
|
||||
margin-right: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 1px solid #1aad19;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.picker {
|
||||
padding: 13px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.profile-list {
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 1px solid #f6f6f9;
|
||||
}
|
||||
|
||||
.profile-list .admin {
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.profile-btn button {
|
||||
background: #ff495e;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.profile-btn button[disabled] {
|
||||
background: #f16474;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.search-box .left {
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.search-box .left icon {
|
||||
padding: 18rpx;
|
||||
}
|
||||
|
||||
.search-box .right {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.wxParse-img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.wxParse-inline {
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wxParse-div {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wxParse-div .kd_pic {
|
||||
float: left;
|
||||
width: 50%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.xEmojiView {
|
||||
margin: 15rpx 0;
|
||||
}
|
||||
.relative {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.absolute {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.fixed {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.item-box{
|
||||
width:100%;
|
||||
height:380rpx;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
margin-bottom:20rpx;
|
||||
}
|
410
common.wxss
Normal file
@ -0,0 +1,410 @@
|
||||
/* flex */
|
||||
.i-flex {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.i-flex-wrap {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.i-flex-nowrap {
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
|
||||
.i-flex-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.i-flex-item {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.i-flex-alc {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.i-flex-spb {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.i-aic {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.jcontent-c {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.jcontent-sb {
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.jcontent-sa {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.weight {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.text-overflow1 {
|
||||
overflow: hidden;
|
||||
text-overflow:ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.text-overflow2 {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.text-right {
|
||||
text-align: right;
|
||||
}
|
||||
.text-left {
|
||||
text-align: left;
|
||||
}
|
||||
/* 字体大小 */
|
||||
.fsz-16 {
|
||||
font-size: 16rpx!important;
|
||||
}
|
||||
|
||||
.fsz-22 {
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.fsz-24 {
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.fsz-26 {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
.fsz-28 {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.fsz-30 {
|
||||
font-size: 30rpx;
|
||||
}
|
||||
|
||||
.fsz-32 {
|
||||
font-size: 32rpx;
|
||||
}
|
||||
|
||||
.fsz-34 {
|
||||
font-size: 34rpx;
|
||||
}
|
||||
|
||||
.fsz-36 {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.fsz-38 {
|
||||
font-size: 38rpx;
|
||||
}
|
||||
|
||||
.fsz-60 {
|
||||
font-size: 60rpx;
|
||||
}
|
||||
|
||||
/* 字体颜色 */
|
||||
.text-3 {
|
||||
color: #333!important;
|
||||
}
|
||||
|
||||
.text-6 {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.text-gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.text-white {
|
||||
color: #fff!important;
|
||||
}
|
||||
|
||||
.text-dark {
|
||||
color: #000!important;
|
||||
}
|
||||
|
||||
.text-sucess {
|
||||
color: #5cb85c!important;
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: #f0ad4e!important;
|
||||
}
|
||||
|
||||
.red {
|
||||
color: #ff5344;
|
||||
}
|
||||
|
||||
.bule {
|
||||
color: rgb(59,140,232);
|
||||
}
|
||||
|
||||
/* 背景 */
|
||||
.bg-f {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.bg-blue {
|
||||
background-color: rgb(59,140,232);
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: #ff5344;
|
||||
}
|
||||
|
||||
.bg-lighter {
|
||||
background-color: #f8f8f8;
|
||||
}
|
||||
|
||||
.bg-ccc {
|
||||
background: #ccc!important;
|
||||
}
|
||||
|
||||
.bg-sucess {
|
||||
background: #5cb85c!important;
|
||||
}
|
||||
|
||||
.bg-warning {
|
||||
background: #f0ad4e!important;
|
||||
}
|
||||
|
||||
/* 边距 */
|
||||
.ml5 {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.ml10 {
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.mb5 {
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.mt-auto {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.mt5 {
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
.mx5 {
|
||||
margin-left: 10rpx;
|
||||
margin-right: 10rpx;
|
||||
}
|
||||
|
||||
.m10 {
|
||||
margin: 20rpx;
|
||||
}
|
||||
|
||||
.mt10 {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.my10 {
|
||||
margin-top: 10rpx;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.mx10 {
|
||||
margin-left: 20rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.mx15 {
|
||||
margin-left: 30rpx;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.mb10 {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.mb20 {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.m15 {
|
||||
margin: 30rpx;
|
||||
}
|
||||
|
||||
.p5 {
|
||||
padding: 10rpx;
|
||||
}
|
||||
|
||||
.p10 {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.p15 {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.pt10 {
|
||||
padding-top: 20rpx;
|
||||
}
|
||||
|
||||
.pb10 {
|
||||
padding-bottom: 20rpx!important;
|
||||
}
|
||||
|
||||
.py10 {
|
||||
padding-top: 20rpx!important;
|
||||
padding-bottom: 20rpx!important;
|
||||
}
|
||||
|
||||
.pb15 {
|
||||
padding-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.px15 {
|
||||
padding-left: 30rpx;
|
||||
padding-right: 30rpx;
|
||||
}
|
||||
|
||||
.py15 {
|
||||
padding-top: 30rpx!important;
|
||||
padding-bottom: 30rpx!important;
|
||||
}
|
||||
|
||||
.pb20 {
|
||||
padding-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.p30 {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.ml30 {
|
||||
margin-left: 30rpx;
|
||||
}
|
||||
|
||||
.pb100 {
|
||||
padding-bottom: 100rpx;
|
||||
}
|
||||
|
||||
.w0 {
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.w90p {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.maxH {
|
||||
max-height: 75vh;
|
||||
}
|
||||
|
||||
.rounded-mini {
|
||||
border-radius: 5rpx;
|
||||
}
|
||||
|
||||
.rounded {
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
|
||||
.border-bottom,
|
||||
.border-top {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.border-bottom::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
transform-origin: 0 0;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
|
||||
.border-top::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
transform-origin: 0 0;
|
||||
transform: scaleY(0.5);
|
||||
}
|
||||
|
||||
.btn-hollow {
|
||||
border: 1rpx solid #e5e5e5;
|
||||
padding: 12rpx 20rpx;
|
||||
border-radius: 30rpx;
|
||||
font-size: 22rpx;
|
||||
color: #666;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.line-through {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
.line-height {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 定位 */
|
||||
.pos-r {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.pos-a {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.pos-f {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.shadow {
|
||||
box-shadow: 1px 2px 5px #ccc;
|
||||
}
|
||||
|
||||
.shadow-top {
|
||||
box-shadow: 0px -3px 5px -2px #ccc;
|
||||
}
|
||||
|
||||
.avatar-md {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
}
|
||||
.pm_index_line{border-bottom: 1px solid #DEDEDE;}
|
||||
.pm_index{width:40rpx;height:40rpx;border-radius:15rpx;color:#333;text-align:center;line-height:40rpx;}
|
||||
.pm_index1{
|
||||
background-color:#FFDC7A;
|
||||
}
|
||||
.pm_index2{
|
||||
background-color:#CBCBF6;
|
||||
}
|
||||
.pm_index3{
|
||||
background-color:#F9A470;
|
||||
}
|
472
components/calendar/calendar.js
Normal file
@ -0,0 +1,472 @@
|
||||
// components/calendar/calendar.js
|
||||
Component({
|
||||
options: {
|
||||
styleIsolation: 'apply-shared'
|
||||
},
|
||||
properties: {
|
||||
date: {
|
||||
type: null,
|
||||
value: new Date()
|
||||
},
|
||||
/**
|
||||
* 选中的日期
|
||||
*/
|
||||
selected: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer(newVal, oldVal) {
|
||||
this.getWeek(new Date())
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 锁定日期
|
||||
*/
|
||||
lockDay: {
|
||||
type: String,
|
||||
},
|
||||
/**
|
||||
* 是否默认展开, 可以调用open事件展开组件
|
||||
*/
|
||||
isOpen: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
/**
|
||||
* 是否多选日期
|
||||
*/
|
||||
multiple:{
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
/**
|
||||
* 是否展示头部
|
||||
*/
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
/**
|
||||
* 是否不能修改
|
||||
*/
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
/**
|
||||
* 使用mini样式
|
||||
*/
|
||||
mini:{
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
calShow: true, // 日历组件是否打开
|
||||
dateShow: false, // 日期是否选择
|
||||
selectDay: '', // 当前选择日期
|
||||
selectDays: [], //多选日期
|
||||
canlender: {
|
||||
"weeks": []
|
||||
},
|
||||
currentMonth: null,
|
||||
nowMonth: new Date().getMonth()+1,
|
||||
nowDate: new Date().getDate()
|
||||
},
|
||||
ready() {
|
||||
let sdays = this.data.selected;
|
||||
sdays.forEach(v=>{
|
||||
this.data.selectDays.push(v);
|
||||
})
|
||||
this.getWeek(new Date());
|
||||
if (this.data.isOpen) {
|
||||
this.setData({
|
||||
calShow: false,
|
||||
dateShow: true
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
open: function(date) {
|
||||
if(date && date!=''){
|
||||
this.data.selectDays = []; //打开时候显示一个
|
||||
this.data.selectDays.push(date);
|
||||
this.setData({
|
||||
selectDays: this.data.selectDays
|
||||
})
|
||||
this.getWeek(date);
|
||||
}
|
||||
this.dateSelection();
|
||||
},
|
||||
close: function() {
|
||||
this.packup();
|
||||
},
|
||||
clear: function(){
|
||||
this.setData({
|
||||
selectDays: []
|
||||
})
|
||||
let m;
|
||||
if(this.data.currentMonth == null){
|
||||
m = this.data.canlender.month
|
||||
}else{
|
||||
m = this.data.currentMonth
|
||||
}
|
||||
let year = this.data.canlender.year + "-" + m + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, 0);
|
||||
this.getWeek(_date);
|
||||
this.triggerEvent("clear",{})
|
||||
},
|
||||
dateSelection() {
|
||||
if (this.data.isOpen) {
|
||||
return
|
||||
}
|
||||
let self = this;
|
||||
if (self.data.calShow) {
|
||||
self.setData({
|
||||
calShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
dateShow: true
|
||||
}, () => {
|
||||
self.triggerEvent('show', {
|
||||
ischeck: !self.data.calShow
|
||||
})
|
||||
})
|
||||
}, 100)
|
||||
})
|
||||
} else {
|
||||
self.setData({
|
||||
dateShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
calShow: true
|
||||
}, () => {
|
||||
self.triggerEvent('show', {
|
||||
ischeck: !self.data.calShow
|
||||
})
|
||||
})
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
},
|
||||
//选择日期
|
||||
selectDay(e) {
|
||||
if(this.data.readonly){
|
||||
return
|
||||
}
|
||||
let index = e.currentTarget.dataset.index;
|
||||
let week = e.currentTarget.dataset.week;
|
||||
let ischeck = e.currentTarget.dataset.ischeck;
|
||||
let canlender = this.data.canlender;
|
||||
if (!ischeck) return false;
|
||||
let month = canlender.weeks[week][index].month < 10 ? "0" + canlender.weeks[week][index].month : canlender.weeks[week][index].month
|
||||
let date = canlender.weeks[week][index].date < 10 ? "0" + canlender.weeks[week][index].date : canlender.weeks[week][index].date
|
||||
let datestr = canlender.year + "-" + month + "-" + date;
|
||||
let selectDays = this.data.selectDays;
|
||||
if (selectDays.indexOf(datestr)==-1) {
|
||||
if(this.data.multiple){
|
||||
//多选
|
||||
selectDays.push(datestr);
|
||||
}else{
|
||||
selectDays = []; //只保留最后选的
|
||||
selectDays.push(datestr);
|
||||
}
|
||||
}else{
|
||||
let index = selectDays.indexOf(datestr);
|
||||
selectDays.splice(index, 1);
|
||||
}
|
||||
selectDays.sort(function(a, b){
|
||||
let ds1 = a.split("-");
|
||||
let ds2 = b.split("-");
|
||||
let d1 = new Date(ds1[0], ds1[1], ds1[2]);
|
||||
let d2 = new Date(ds2[0], ds2[1], ds2[2]);
|
||||
return d1-d2;
|
||||
});
|
||||
this.data.selectDays = selectDays;
|
||||
this.getWeek(datestr);
|
||||
this.triggerEvent('getdate', {
|
||||
datestr
|
||||
})
|
||||
},
|
||||
//点击确定
|
||||
packup() {
|
||||
let self = this;
|
||||
self.triggerEvent('select', {
|
||||
selectDays: self.data.selectDays
|
||||
})
|
||||
if (this.data.isOpen) {
|
||||
let year = self.data.canlender.year + "-" + self.data.canlender.month + "-" + self.data.canlender.date
|
||||
let _date = self.getDate(year, 0);
|
||||
self.getWeek(_date);
|
||||
return
|
||||
}
|
||||
self.setData({
|
||||
dateShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
calShow: true
|
||||
}, () => {
|
||||
let year = self.data.canlender.year + "-" + self.data.canlender.month + "-" + self.data.canlender.date
|
||||
let _date = self.getDate(year, 0);
|
||||
self.getWeek(_date);
|
||||
})
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 页面通过事件选中日期后调用refresh方法刷新日历组件
|
||||
*/
|
||||
refresh: function (num){
|
||||
this.setData({
|
||||
selectDays: num
|
||||
})
|
||||
let m;
|
||||
if(this.data.currentMonth == null){
|
||||
m = this.data.canlender.month
|
||||
}else{
|
||||
m = this.data.currentMonth
|
||||
}
|
||||
|
||||
let year = this.data.canlender.year + "-" + m + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, 0);
|
||||
this.getWeek(_date);
|
||||
},
|
||||
// 返回今天
|
||||
backtoday() {
|
||||
if(!this.data.readonly){
|
||||
let datestr = this.dateStr(new Date());
|
||||
this.data.selectDays.push(datestr);
|
||||
this.setData({
|
||||
selectDays: this.data.selectDays
|
||||
});
|
||||
this.triggerEvent('getdate', {
|
||||
datestr
|
||||
})
|
||||
}
|
||||
this.getWeek(new Date());
|
||||
},
|
||||
// 前一天|| 后一天
|
||||
dataBefor(e) {
|
||||
let num = 0;
|
||||
let types = e.currentTarget.dataset.type;
|
||||
|
||||
if (e.currentTarget.dataset.id === "0") {
|
||||
num = -1;
|
||||
} else {
|
||||
num = 1
|
||||
}
|
||||
let year = this.data.canlender.year + "-" + this.data.canlender.month + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, num, types === 'month' ? "month" : "day");
|
||||
this.getWeek(_date);
|
||||
},
|
||||
|
||||
// 获取日历内容
|
||||
getWeek(dateData) {
|
||||
|
||||
let selected = this.data.selected
|
||||
let selectDays = this.data.selectDays
|
||||
// 判断当前是 安卓还是ios ,传入不容的日期格式
|
||||
if (typeof dateData !== 'object') {
|
||||
dateData = dateData.replace(/-/g, "/")
|
||||
}
|
||||
let _date = new Date(dateData);
|
||||
let year = _date.getFullYear(); //年
|
||||
let month = _date.getMonth() + 1; //月
|
||||
let date = _date.getDate(); //日
|
||||
let day = _date.getDay(); // 天
|
||||
let canlender = [];
|
||||
|
||||
let dates = {
|
||||
firstDay: new Date(year, month - 1, 1).getDay(),
|
||||
lastMonthDays: [], // 上个月末尾几天
|
||||
currentMonthDys: [], // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
endDay: new Date(year, month, 0).getDay(),
|
||||
weeks: []
|
||||
}
|
||||
// 循环上个月末尾几天添加到数组
|
||||
for (let i = dates.firstDay; i > 0; i--) {
|
||||
let dd = new Date(year, month-1, -(i-1));
|
||||
let checked = false;
|
||||
selectDays.forEach(v => {
|
||||
let selDate = v.date.split('-');
|
||||
let ddstr = this.dateStr(dd);
|
||||
if (ddstr == v) {
|
||||
checked = true;
|
||||
}
|
||||
})
|
||||
dates.lastMonthDays.push({
|
||||
'date': '',
|
||||
'month': '',
|
||||
checked
|
||||
})
|
||||
}
|
||||
// 循环本月天数添加到数组
|
||||
for (let i = 1; i <= new Date(year, month, 0).getDate(); i++) {
|
||||
let have = false;
|
||||
let checked = false;
|
||||
let step = '';
|
||||
// for (let j = 0; j < selected.length; j++) {
|
||||
// let selDate = selected[j].split('-');
|
||||
// if (Number(year) === Number(selDate[0]) && Number(month) === Number(selDate[1]) && Number(i) === Number(selDate[2])) {
|
||||
// have = true;
|
||||
// }
|
||||
// }
|
||||
selectDays.forEach(v => {
|
||||
let selDate = v.date.split('-');
|
||||
if (Number(year) === Number(selDate[0]) && Number(month) === Number(selDate[1]) && Number(i) === Number(selDate[2])) {
|
||||
checked = true;
|
||||
step = v.step;
|
||||
}
|
||||
})
|
||||
dates.currentMonthDys.push({
|
||||
'date': i + "",
|
||||
'month': month,
|
||||
// have,
|
||||
checked,
|
||||
step
|
||||
})
|
||||
}
|
||||
// 循环下个月开始几天 添加到数组
|
||||
for (let i = 1; i < 7 - dates.endDay; i++) {
|
||||
dates.nextMonthDays.push({
|
||||
'date': '',
|
||||
'month': ''
|
||||
})
|
||||
}
|
||||
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 == 0) {
|
||||
dates.weeks[parseInt(i / 7)] = new Array(7);
|
||||
}
|
||||
dates.weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
// 渲染数据
|
||||
this.setData({
|
||||
selectDay: month + "月" + date + "日",
|
||||
"canlender.weeks": dates.weeks,
|
||||
'canlender.month': month,
|
||||
'canlender.date': date,
|
||||
"canlender.day": day,
|
||||
'canlender.year': year,
|
||||
})
|
||||
month = month < 10 ? "0" + month : month
|
||||
date = date < 10 ? "0" + date : date
|
||||
// let localstr = year+"-"+month+"-"+date;
|
||||
// this.triggerEvent('getdate', {
|
||||
// year,
|
||||
// month,
|
||||
// date,
|
||||
// localstr
|
||||
// })
|
||||
|
||||
// console.log(dates.weeks);
|
||||
|
||||
},
|
||||
checkall(){
|
||||
let date = new Date();
|
||||
let m, d, day, dayNum;
|
||||
let days = [];
|
||||
if(this.data.currentMonth == null){
|
||||
m = parseInt(this.data.nowMonth)
|
||||
}else{
|
||||
m = parseInt(this.data.currentMonth)
|
||||
}
|
||||
|
||||
switch (m) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
dayNum = 31;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
dayNum = 30;
|
||||
break;
|
||||
case 2:
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
|
||||
dayNum = 29;
|
||||
} else {
|
||||
dayNum = 28;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (d = 1; d <= dayNum; d++) {
|
||||
date.setMonth(m - 1, d);
|
||||
day = date.getDay();
|
||||
let str = this.format(date);
|
||||
if(date.getMonth() == new Date().getMonth()){
|
||||
if(date.getDate() - new Date().getDate() >= 0){
|
||||
days.push(str);
|
||||
}
|
||||
}else if(date.getMonth() > new Date().getMonth()){
|
||||
days.push(str);
|
||||
}
|
||||
}
|
||||
this.refresh(days);
|
||||
this.triggerEvent('checkall', {
|
||||
days
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 时间计算
|
||||
*/
|
||||
getDate(date, AddDayCount, str = 'day') {
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, "/")
|
||||
}
|
||||
let dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
case 'month':
|
||||
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
}
|
||||
let y = dd.getFullYear()
|
||||
let m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1) // 获取当前月份的日期,不足10补0
|
||||
let d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
this.setData({
|
||||
currentMonth: m
|
||||
})
|
||||
return y + '-' + m + '-' + d
|
||||
},
|
||||
//日期转字符串
|
||||
dateStr(calendar){
|
||||
let year = calendar.getFullYear();
|
||||
let month = calendar.getMonth()+1;
|
||||
let date = calendar.getDate();
|
||||
month = month < 10 ? "0" + month : month;
|
||||
date = date < 10 ? "0" + date : date;
|
||||
let datestr = year + "-" + month + "-" + date;
|
||||
return datestr;
|
||||
},
|
||||
format(dd){
|
||||
let y = dd.getFullYear()
|
||||
let m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1)
|
||||
let d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate()
|
||||
return y + '-' + m + '-' + d
|
||||
}
|
||||
}
|
||||
})
|
4
components/calendar/calendar.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
73
components/calendar/calendar.wxml
Normal file
@ -0,0 +1,73 @@
|
||||
<wxs module="filters">
|
||||
var strcontains = function (str,c) {
|
||||
if (str.indexOf(c) >= 0) {
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var formatNumber = function(n) {
|
||||
n = n.toString()
|
||||
return n[1] ? n : '0' + n
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatNumber: formatNumber,
|
||||
strcontains: strcontains
|
||||
}
|
||||
</wxs>
|
||||
|
||||
|
||||
<view class="header space-between" wx:if="{{showHeader}}">
|
||||
<view class="iconfont" data-type="month" data-id="0" bindtap='dataBefor'>
|
||||
<view class='left-color'></view>
|
||||
</view>
|
||||
<view class="btn flex-center" bindtap="dateSelection">
|
||||
<view class="text">{{canlender.year}}年{{canlender.month}}月</view>
|
||||
<view class=""></view>
|
||||
</view>
|
||||
<view class="iconfont" data-type="month" data-id="1" bindtap='dataBefor'>
|
||||
<view class='right-color'></view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if='{{!calShow}}' class="{{isOpen?'':'calendar-box'}} {{dateShow?'active':''}}">
|
||||
<view class="calendar-wrapper {{dateShow?'active':''}}">
|
||||
<view class="calendar-panel" wx:if="{{!showHeader}}">
|
||||
<view class="calendar-panel-box">
|
||||
<view>{{canlender.year}}年</view>
|
||||
<view>{{canlender.month}}月</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-header {{mini?'mini':''}}">
|
||||
<view>日</view>
|
||||
<view>一</view>
|
||||
<view>二</view>
|
||||
<view>三</view>
|
||||
<view>四</view>
|
||||
<view>五</view>
|
||||
<view>六</view>
|
||||
</view>
|
||||
<view class="calendar-body">
|
||||
<block wx:for="{{canlender.weeks}}" wx:for-item="weeks" wx:for-index="week" wx:key="weeks">
|
||||
<view class="calender-body-date-week">
|
||||
<block wx:for="{{weeks}}" wx:for-item="day" wx:key="day">
|
||||
|
||||
<view wx:if="{{filters.strcontains(lockDay,canlender.year+'-'+filters.formatNumber(day.month) +'-'+filters.formatNumber(day.date))}}" class="date date-lock">
|
||||
{{day.date}}
|
||||
</view>
|
||||
|
||||
<view wx:else class="date {{mini?'mini':''}} {{canlender.month==day.month && ((nowMonth === day.month && day.date-nowDate >= 0) || (day.month - nowMonth > 0))? '' : 'placeholder'}} " data-week="{{week}}" data-index="{{index}}" data-ischeck="{{canlender.month==day.month && ((nowMonth === day.month && day.date-nowDate >= 0) || (day.month - nowMonth > 0))}}"
|
||||
bindtap='selectDay'>
|
||||
<block wx:if="{{day.date}}">
|
||||
{{day.date}}
|
||||
<view wx:if="{{(readonly && day.checked) || (day.checked && canlender.month != day.month)}}" class="data-circle {{mini?'mini':''}}">{{day.step}} </view>
|
||||
<image src="/images/add_to_min_program_close.png" wx:else style="width:24rpx;height:24rpx;"></image>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
260
components/calendar/calendar.wxss
Normal file
@ -0,0 +1,260 @@
|
||||
/* pages/calendar/calendar.wxss */
|
||||
cover-view{
|
||||
line-height: initial;
|
||||
}
|
||||
.calendar-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999999;
|
||||
padding-top: 100rpx;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.calendar-box.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.calendar-wrapper {
|
||||
width: 100%;
|
||||
border-top: 1px #f5f5f5 solid;
|
||||
border-bottom: 1px #f5f5f5 solid;
|
||||
box-sizing: border-box;
|
||||
font-size: 26rpx;
|
||||
background: #fff;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.calendar-wrapper.active {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 100rpx;
|
||||
background: #fff;
|
||||
z-index: 10000;
|
||||
}
|
||||
|
||||
.top-jiantou {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.iconfont{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
color: #1AB16C;
|
||||
width: 53rpx;
|
||||
height: 53rpx;
|
||||
}
|
||||
|
||||
.left-color,
|
||||
.right-color
|
||||
{
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 20rpx solid transparent;
|
||||
border-bottom: 20rpx solid transparent;
|
||||
}
|
||||
|
||||
.left-color{
|
||||
border-right: 40rpx solid transparent;
|
||||
border-right-color: #1AB16C;
|
||||
}
|
||||
|
||||
.right-color{
|
||||
border-left: 40rpx solid transparent;
|
||||
border-left-color: #1AB16C;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0 30rpx;
|
||||
width: 240rpx;
|
||||
height: 53rpx;
|
||||
border: 1rpx solid #1AB16C;
|
||||
border-radius: 26rpx;
|
||||
color: #1AB16C;
|
||||
font-size: 26rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.calendar-panel {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 15rpx;
|
||||
padding: 0 10rpx;
|
||||
padding-left: 20rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border: 1px #1AB16C solid;
|
||||
border-right: none;
|
||||
font-size: 28rpx;
|
||||
border-top-left-radius: 50rpx;
|
||||
border-bottom-left-radius: 50rpx;
|
||||
color: #1AB16C;
|
||||
background: rgba(82, 184, 245, 0.1);
|
||||
}
|
||||
.checkalllbtn {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 15rpx;
|
||||
padding: 0 10rpx;
|
||||
padding-right: 20rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border: 1px #1AB16C solid;
|
||||
border-left: none;
|
||||
font-size: 28rpx;
|
||||
border-top-right-radius: 50rpx;
|
||||
border-bottom-right-radius: 50rpx;
|
||||
color: #1AB16C;
|
||||
background: rgba(82, 184, 245, 0.1);
|
||||
}
|
||||
|
||||
.date-befor, .date-after {
|
||||
/* border: 1px red solid; */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80rpx;
|
||||
width: 80rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
/* margin-right: 20rpx; */
|
||||
}
|
||||
|
||||
/* .date-after {
|
||||
margin-left: 20rpx;
|
||||
} */
|
||||
|
||||
.calendar-panel-box {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.calendar-header view,
|
||||
.calendar-header cover-view {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
color: #1AB16C;
|
||||
}
|
||||
.calendar-header.mini view,
|
||||
.calendar-header.mini cover-view
|
||||
{
|
||||
line-height: 50rpx;
|
||||
}
|
||||
.calendar-body {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.calender-body-date-week {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-bottom: 1px #f5f5f5 solid;
|
||||
height:100rpx;
|
||||
padding:10rpx 0;
|
||||
}
|
||||
|
||||
.date {
|
||||
|
||||
width: 100%;
|
||||
display: flex;
|
||||
color: #1c1c1c;
|
||||
background: #fff;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
.date.mini{
|
||||
line-height: 50rpx;
|
||||
|
||||
}
|
||||
.date.active {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #1c1c1c;
|
||||
}
|
||||
|
||||
.date-current {
|
||||
background: #1AB16C;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.date-lock {
|
||||
color: #ff5a5f;
|
||||
}
|
||||
.data-circle {
|
||||
color: #1AB16C;
|
||||
font-weight: bold;
|
||||
}
|
||||
.data-circle.mini{
|
||||
bottom: 2rpx;
|
||||
}
|
||||
|
||||
.packup {
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
text-align: center;
|
||||
color: #1AB16C;
|
||||
align-items: center;
|
||||
}
|
||||
.packup-button{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
height: 55px;
|
||||
line-height:55px!important;
|
||||
}
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.flex-between{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.border-left{
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
.cmf-btn{
|
||||
background-color: #39b54a;
|
||||
color: #fff;
|
||||
border: 1rpx solid #39b54a;
|
||||
}
|
475
components/calendarn/calendar.js
Normal file
@ -0,0 +1,475 @@
|
||||
// components/calendar/calendar.js
|
||||
Component({
|
||||
options: {
|
||||
styleIsolation: 'apply-shared'
|
||||
},
|
||||
properties: {
|
||||
date: {
|
||||
type: null,
|
||||
value: new Date()
|
||||
},
|
||||
/**
|
||||
* 选中的日期
|
||||
*/
|
||||
selected: {
|
||||
type: Array,
|
||||
value: [],
|
||||
observer(newVal, oldVal) {
|
||||
this.getWeek(new Date())
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 锁定日期
|
||||
*/
|
||||
lockDay: {
|
||||
type: String,
|
||||
},
|
||||
/**
|
||||
* 是否默认展开, 可以调用open事件展开组件
|
||||
*/
|
||||
isOpen: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
/**
|
||||
* 是否多选日期
|
||||
*/
|
||||
multiple:{
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
/**
|
||||
* 是否展示头部
|
||||
*/
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
},
|
||||
/**
|
||||
* 是否不能修改
|
||||
*/
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
/**
|
||||
* 使用mini样式
|
||||
*/
|
||||
mini:{
|
||||
type: Boolean,
|
||||
value: true
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
calShow: true, // 日历组件是否打开
|
||||
dateShow: false, // 日期是否选择
|
||||
selectDay: '', // 当前选择日期
|
||||
selectDays: [], //多选日期
|
||||
canlender: {
|
||||
"weeks": []
|
||||
},
|
||||
currentMonth: null,
|
||||
nowMonth: new Date().getMonth()+1,
|
||||
nowDate: new Date().getDate()
|
||||
},
|
||||
ready() {
|
||||
let sdays = this.data.selected;
|
||||
sdays.forEach(v=>{
|
||||
this.data.selectDays.push(v);
|
||||
})
|
||||
this.getWeek(new Date());
|
||||
if (this.data.isOpen) {
|
||||
this.setData({
|
||||
calShow: false,
|
||||
dateShow: true
|
||||
})
|
||||
}
|
||||
},
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
open: function(date) {
|
||||
if(date && date!=''){
|
||||
this.data.selectDays = []; //打开时候显示一个
|
||||
this.data.selectDays.push(date);
|
||||
this.setData({
|
||||
selectDays: this.data.selectDays
|
||||
})
|
||||
this.getWeek(date);
|
||||
}
|
||||
this.dateSelection();
|
||||
},
|
||||
close: function() {
|
||||
this.packup();
|
||||
},
|
||||
clear: function(){
|
||||
this.setData({
|
||||
selectDays: []
|
||||
})
|
||||
let m;
|
||||
if(this.data.currentMonth == null){
|
||||
m = this.data.canlender.month
|
||||
}else{
|
||||
m = this.data.currentMonth
|
||||
}
|
||||
let year = this.data.canlender.year + "-" + m + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, 0);
|
||||
this.getWeek(_date);
|
||||
this.triggerEvent("clear",{})
|
||||
},
|
||||
dateSelection() {
|
||||
if (this.data.isOpen) {
|
||||
return
|
||||
}
|
||||
let self = this;
|
||||
if (self.data.calShow) {
|
||||
self.setData({
|
||||
calShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
dateShow: true
|
||||
}, () => {
|
||||
self.triggerEvent('show', {
|
||||
ischeck: !self.data.calShow
|
||||
})
|
||||
})
|
||||
}, 100)
|
||||
})
|
||||
} else {
|
||||
self.setData({
|
||||
dateShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
calShow: true
|
||||
}, () => {
|
||||
self.triggerEvent('show', {
|
||||
ischeck: !self.data.calShow
|
||||
})
|
||||
})
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
},
|
||||
//选择日期
|
||||
selectDay(e) {
|
||||
if(this.data.readonly){
|
||||
return
|
||||
}
|
||||
let index = e.currentTarget.dataset.index;
|
||||
let week = e.currentTarget.dataset.week;
|
||||
let ischeck = e.currentTarget.dataset.ischeck;
|
||||
let canlender = this.data.canlender;
|
||||
if (!ischeck) return false;
|
||||
let month = canlender.weeks[week][index].month < 10 ? "0" + canlender.weeks[week][index].month : canlender.weeks[week][index].month
|
||||
let date = canlender.weeks[week][index].date < 10 ? "0" + canlender.weeks[week][index].date : canlender.weeks[week][index].date
|
||||
let datestr = canlender.year + "-" + month + "-" + date;
|
||||
let selectDays = this.data.selectDays;
|
||||
if (selectDays.indexOf(datestr)==-1) {
|
||||
if(this.data.multiple){
|
||||
//多选
|
||||
selectDays.push(datestr);
|
||||
}else{
|
||||
selectDays = []; //只保留最后选的
|
||||
selectDays.push(datestr);
|
||||
}
|
||||
}else{
|
||||
let index = selectDays.indexOf(datestr);
|
||||
selectDays.splice(index, 1);
|
||||
}
|
||||
selectDays.sort(function(a, b){
|
||||
let ds1 = a.split("-");
|
||||
let ds2 = b.split("-");
|
||||
let d1 = new Date(ds1[0], ds1[1], ds1[2]);
|
||||
let d2 = new Date(ds2[0], ds2[1], ds2[2]);
|
||||
return d1-d2;
|
||||
});
|
||||
this.data.selectDays = selectDays;
|
||||
this.getWeek(datestr);
|
||||
this.triggerEvent('getdate', {
|
||||
datestr
|
||||
})
|
||||
},
|
||||
//点击确定
|
||||
packup() {
|
||||
let self = this;
|
||||
self.triggerEvent('select', {
|
||||
selectDays: self.data.selectDays
|
||||
})
|
||||
if (this.data.isOpen) {
|
||||
let year = self.data.canlender.year + "-" + self.data.canlender.month + "-" + self.data.canlender.date
|
||||
let _date = self.getDate(year, 0);
|
||||
self.getWeek(_date);
|
||||
return
|
||||
}
|
||||
self.setData({
|
||||
dateShow: false
|
||||
}, () => {
|
||||
setTimeout(() => {
|
||||
self.setData({
|
||||
calShow: true
|
||||
}, () => {
|
||||
let year = self.data.canlender.year + "-" + self.data.canlender.month + "-" + self.data.canlender.date
|
||||
let _date = self.getDate(year, 0);
|
||||
self.getWeek(_date);
|
||||
})
|
||||
}, 300)
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 页面通过事件选中日期后调用refresh方法刷新日历组件
|
||||
*/
|
||||
refresh: function (num){
|
||||
this.setData({
|
||||
selectDays: num
|
||||
})
|
||||
let m;
|
||||
if(this.data.currentMonth == null){
|
||||
m = this.data.canlender.month
|
||||
}else{
|
||||
m = this.data.currentMonth
|
||||
}
|
||||
|
||||
let year = this.data.canlender.year + "-" + m + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, 0);
|
||||
this.getWeek(_date);
|
||||
},
|
||||
// 返回今天
|
||||
backtoday() {
|
||||
if(!this.data.readonly){
|
||||
let datestr = this.dateStr(new Date());
|
||||
this.data.selectDays.push(datestr);
|
||||
this.setData({
|
||||
selectDays: this.data.selectDays
|
||||
});
|
||||
this.triggerEvent('getdate', {
|
||||
datestr
|
||||
})
|
||||
}
|
||||
this.getWeek(new Date());
|
||||
},
|
||||
// 前一天|| 后一天
|
||||
dataBefor(e) {
|
||||
let num = 0;
|
||||
let types = e.currentTarget.dataset.type;
|
||||
|
||||
if (e.currentTarget.dataset.id === "0") {
|
||||
num = -1;
|
||||
} else {
|
||||
num = 1
|
||||
}
|
||||
let year = this.data.canlender.year + "-" + this.data.canlender.month + "-" + this.data.canlender.date
|
||||
let _date = this.getDate(year, num, types === 'month' ? "month" : "day");
|
||||
this.getWeek(_date);
|
||||
},
|
||||
|
||||
// 获取日历内容
|
||||
getWeek(dateData) {
|
||||
|
||||
let selected = this.data.selected
|
||||
let selectDays = this.data.selectDays
|
||||
// 判断当前是 安卓还是ios ,传入不容的日期格式
|
||||
if (typeof dateData !== 'object') {
|
||||
dateData = dateData.replace(/-/g, "/")
|
||||
}
|
||||
let _date = new Date(dateData);
|
||||
let year = _date.getFullYear(); //年
|
||||
let month = _date.getMonth() + 1; //月
|
||||
let date = _date.getDate(); //日
|
||||
let day = _date.getDay(); // 天
|
||||
let canlender = [];
|
||||
|
||||
let dates = {
|
||||
firstDay: new Date(year, month - 1, 1).getDay(),
|
||||
lastMonthDays: [], // 上个月末尾几天
|
||||
currentMonthDys: [], // 本月天数
|
||||
nextMonthDays: [], // 下个月开始几天
|
||||
endDay: new Date(year, month, 0).getDay(),
|
||||
weeks: []
|
||||
}
|
||||
// 循环上个月末尾几天添加到数组
|
||||
for (let i = dates.firstDay; i > 0; i--) {
|
||||
let dd = new Date(year, month-1, -(i-1));
|
||||
let checked = false;
|
||||
selectDays.forEach(v => {
|
||||
let selDate = v.date.split('-');
|
||||
let ddstr = this.dateStr(dd);
|
||||
if (ddstr == v) {
|
||||
checked = true;
|
||||
}
|
||||
})
|
||||
dates.lastMonthDays.push({
|
||||
'date': '',
|
||||
'month': '',
|
||||
checked
|
||||
})
|
||||
}
|
||||
// 循环本月天数添加到数组
|
||||
for (let i = 1; i <= new Date(year, month, 0).getDate(); i++) {
|
||||
let have = false;
|
||||
let checked = false;
|
||||
let step = '';
|
||||
let city = '';
|
||||
// for (let j = 0; j < selected.length; j++) {
|
||||
// let selDate = selected[j].split('-');
|
||||
// if (Number(year) === Number(selDate[0]) && Number(month) === Number(selDate[1]) && Number(i) === Number(selDate[2])) {
|
||||
// have = true;
|
||||
// }
|
||||
// }
|
||||
selectDays.forEach(v => {
|
||||
let selDate = v.date.split('-');
|
||||
if (Number(year) === Number(selDate[0]) && Number(month) === Number(selDate[1]) && Number(i) === Number(selDate[2])) {
|
||||
checked = true;
|
||||
step = v.step;
|
||||
city = v.city_id;
|
||||
}
|
||||
})
|
||||
dates.currentMonthDys.push({
|
||||
'date': i + "",
|
||||
'month': month,
|
||||
// have,
|
||||
checked,
|
||||
step,
|
||||
city
|
||||
})
|
||||
}
|
||||
// 循环下个月开始几天 添加到数组
|
||||
for (let i = 1; i < 7 - dates.endDay; i++) {
|
||||
dates.nextMonthDays.push({
|
||||
'date': '',
|
||||
'month': ''
|
||||
})
|
||||
}
|
||||
|
||||
canlender = canlender.concat(dates.lastMonthDays, dates.currentMonthDys, dates.nextMonthDays)
|
||||
// 拼接数组 上个月开始几天 + 本月天数+ 下个月开始几天
|
||||
for (let i = 0; i < canlender.length; i++) {
|
||||
if (i % 7 == 0) {
|
||||
dates.weeks[parseInt(i / 7)] = new Array(7);
|
||||
}
|
||||
dates.weeks[parseInt(i / 7)][i % 7] = canlender[i]
|
||||
}
|
||||
// 渲染数据
|
||||
this.setData({
|
||||
selectDay: month + "月" + date + "日",
|
||||
"canlender.weeks": dates.weeks,
|
||||
'canlender.month': month,
|
||||
'canlender.date': date,
|
||||
"canlender.day": day,
|
||||
'canlender.year': year,
|
||||
})
|
||||
month = month < 10 ? "0" + month : month
|
||||
date = date < 10 ? "0" + date : date
|
||||
// let localstr = year+"-"+month+"-"+date;
|
||||
// this.triggerEvent('getdate', {
|
||||
// year,
|
||||
// month,
|
||||
// date,
|
||||
// localstr
|
||||
// })
|
||||
|
||||
// console.log(dates.weeks);
|
||||
|
||||
},
|
||||
checkall(){
|
||||
let date = new Date();
|
||||
let m, d, day, dayNum;
|
||||
let days = [];
|
||||
if(this.data.currentMonth == null){
|
||||
m = parseInt(this.data.nowMonth)
|
||||
}else{
|
||||
m = parseInt(this.data.currentMonth)
|
||||
}
|
||||
|
||||
switch (m) {
|
||||
case 1:
|
||||
case 3:
|
||||
case 5:
|
||||
case 7:
|
||||
case 8:
|
||||
case 10:
|
||||
case 12:
|
||||
dayNum = 31;
|
||||
break;
|
||||
case 4:
|
||||
case 6:
|
||||
case 9:
|
||||
case 11:
|
||||
dayNum = 30;
|
||||
break;
|
||||
case 2:
|
||||
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
|
||||
dayNum = 29;
|
||||
} else {
|
||||
dayNum = 28;
|
||||
}
|
||||
break;
|
||||
}
|
||||
for (d = 1; d <= dayNum; d++) {
|
||||
date.setMonth(m - 1, d);
|
||||
day = date.getDay();
|
||||
let str = this.format(date);
|
||||
if(date.getMonth() == new Date().getMonth()){
|
||||
if(date.getDate() - new Date().getDate() >= 0){
|
||||
days.push(str);
|
||||
}
|
||||
}else if(date.getMonth() > new Date().getMonth()){
|
||||
days.push(str);
|
||||
}
|
||||
}
|
||||
this.refresh(days);
|
||||
this.triggerEvent('checkall', {
|
||||
days
|
||||
})
|
||||
},
|
||||
/**
|
||||
* 时间计算
|
||||
*/
|
||||
getDate(date, AddDayCount, str = 'day') {
|
||||
if (typeof date !== 'object') {
|
||||
date = date.replace(/-/g, "/")
|
||||
}
|
||||
let dd = new Date(date)
|
||||
switch (str) {
|
||||
case 'day':
|
||||
dd.setDate(dd.getDate() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
case 'month':
|
||||
dd.setMonth(dd.getMonth() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
case 'year':
|
||||
dd.setFullYear(dd.getFullYear() + AddDayCount) // 获取AddDayCount天后的日期
|
||||
break;
|
||||
}
|
||||
let y = dd.getFullYear()
|
||||
let m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1) // 获取当前月份的日期,不足10补0
|
||||
let d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate() // 获取当前几号,不足10补0
|
||||
this.setData({
|
||||
currentMonth: m
|
||||
})
|
||||
return y + '-' + m + '-' + d
|
||||
},
|
||||
//日期转字符串
|
||||
dateStr(calendar){
|
||||
let year = calendar.getFullYear();
|
||||
let month = calendar.getMonth()+1;
|
||||
let date = calendar.getDate();
|
||||
month = month < 10 ? "0" + month : month;
|
||||
date = date < 10 ? "0" + date : date;
|
||||
let datestr = year + "-" + month + "-" + date;
|
||||
return datestr;
|
||||
},
|
||||
format(dd){
|
||||
let y = dd.getFullYear()
|
||||
let m = (dd.getMonth() + 1) < 10 ? '0' + (dd.getMonth() + 1) : (dd.getMonth() + 1)
|
||||
let d = dd.getDate() < 10 ? '0' + dd.getDate() : dd.getDate()
|
||||
return y + '-' + m + '-' + d
|
||||
}
|
||||
}
|
||||
})
|
4
components/calendarn/calendar.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
73
components/calendarn/calendar.wxml
Normal file
@ -0,0 +1,73 @@
|
||||
<wxs module="filters">
|
||||
var strcontains = function (str,c) {
|
||||
if (str.indexOf(c) >= 0) {
|
||||
return true
|
||||
}else{
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var formatNumber = function(n) {
|
||||
n = n.toString()
|
||||
return n[1] ? n : '0' + n
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
formatNumber: formatNumber,
|
||||
strcontains: strcontains
|
||||
}
|
||||
</wxs>
|
||||
|
||||
|
||||
<view class="header space-between" wx:if="{{showHeader}}">
|
||||
<view class="iconfont" data-type="month" data-id="0" bindtap='dataBefor'>
|
||||
<view class='left-color'></view>
|
||||
</view>
|
||||
<view class="btn flex-center" bindtap="dateSelection">
|
||||
<view class="text">{{canlender.year}}年{{canlender.month}}月</view>
|
||||
<view class=""></view>
|
||||
</view>
|
||||
<view class="iconfont" data-type="month" data-id="1" bindtap='dataBefor'>
|
||||
<view class='right-color'></view>
|
||||
</view>
|
||||
</view>
|
||||
<view wx:if='{{!calShow}}' class="{{isOpen?'':'calendar-box'}} {{dateShow?'active':''}}">
|
||||
<view class="calendar-wrapper {{dateShow?'active':''}}">
|
||||
<view class="calendar-panel" wx:if="{{!showHeader}}">
|
||||
<view class="calendar-panel-box">
|
||||
<view>{{canlender.year}}年</view>
|
||||
<view>{{canlender.month}}月</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="calendar-header {{mini?'mini':''}}">
|
||||
<view>日</view>
|
||||
<view>一</view>
|
||||
<view>二</view>
|
||||
<view>三</view>
|
||||
<view>四</view>
|
||||
<view>五</view>
|
||||
<view>六</view>
|
||||
</view>
|
||||
<view class="calendar-body">
|
||||
<block wx:for="{{canlender.weeks}}" wx:for-item="weeks" wx:for-index="week" wx:key="weeks">
|
||||
<view class="calender-body-date-week">
|
||||
<block wx:for="{{weeks}}" wx:for-item="day" wx:key="day">
|
||||
|
||||
<view wx:if="{{filters.strcontains(lockDay,canlender.year+'-'+filters.formatNumber(day.month) +'-'+filters.formatNumber(day.date))}}" class="date date-lock">
|
||||
{{day.date}}
|
||||
</view>
|
||||
|
||||
<view wx:else class="date {{mini?'mini':''}} {{canlender.month==day.month && ((nowMonth === day.month && day.date-nowDate >= 0) || (day.month - nowMonth > 0))? '' : 'placeholder'}} " data-week="{{week}}" data-index="{{index}}" data-ischeck="{{canlender.month==day.month && ((nowMonth === day.month && day.date-nowDate >= 0) || (day.month - nowMonth > 0))}}"
|
||||
bindtap='selectDay'>
|
||||
<block wx:if="{{day.date}}">
|
||||
{{day.date}}
|
||||
<view wx:if="{{(readonly && day.checked) || (day.checked && canlender.month != day.month)}}" class="data-circle {{mini?'mini':''}}"><view>{{day.step}}</view> <view>{{day.city}}</view></view>
|
||||
<image src="/images/add_to_min_program_close.png" wx:else style="width:24rpx;height:24rpx;"></image>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
258
components/calendarn/calendar.wxss
Normal file
@ -0,0 +1,258 @@
|
||||
/* pages/calendar/calendar.wxss */
|
||||
cover-view{
|
||||
line-height: initial;
|
||||
}
|
||||
.calendar-box {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 999999;
|
||||
padding-top: 100rpx;
|
||||
box-sizing: border-box;
|
||||
transition: all 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.calendar-box.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.calendar-wrapper {
|
||||
width: 100%;
|
||||
border-top: 1px #f5f5f5 solid;
|
||||
border-bottom: 1px #f5f5f5 solid;
|
||||
box-sizing: border-box;
|
||||
font-size: 26rpx;
|
||||
background: #fff;
|
||||
transition: all 0.3s;
|
||||
transform: translateY(-100%);
|
||||
}
|
||||
|
||||
.calendar-wrapper.active {
|
||||
transform: translateY(0%);
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
height: 100rpx;
|
||||
background: #fff;
|
||||
z-index: 10000;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.top-jiantou {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
line-height: 100rpx;
|
||||
}
|
||||
|
||||
.iconfont{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
color: #890001;
|
||||
width: 53rpx;
|
||||
height: 53rpx;
|
||||
}
|
||||
|
||||
.left-color,
|
||||
.right-color
|
||||
{
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 20rpx solid transparent;
|
||||
border-bottom: 20rpx solid transparent;
|
||||
}
|
||||
|
||||
.left-color{
|
||||
border-right: 40rpx solid transparent;
|
||||
border-right-color: #890001;
|
||||
}
|
||||
|
||||
.right-color{
|
||||
border-left: 40rpx solid transparent;
|
||||
border-left-color: #890001;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 0 30rpx;
|
||||
width: 240rpx;
|
||||
height: 53rpx;
|
||||
border: 2rpx solid #890001;
|
||||
border-radius: 26rpx;
|
||||
color: #890001;
|
||||
font-size: 26rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.calendar-panel {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32rpx;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.backtoday {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 15rpx;
|
||||
padding: 0 10rpx;
|
||||
padding-left: 20rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border: 1px #890001 solid;
|
||||
border-right: none;
|
||||
font-size: 28rpx;
|
||||
border-top-left-radius: 50rpx;
|
||||
border-bottom-left-radius: 50rpx;
|
||||
color: #890001;
|
||||
background: rgba(82, 184, 245, 0.1);
|
||||
}
|
||||
.checkalllbtn {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 15rpx;
|
||||
padding: 0 10rpx;
|
||||
padding-right: 20rpx;
|
||||
height: 50rpx;
|
||||
line-height: 50rpx;
|
||||
border: 1px #890001 solid;
|
||||
border-left: none;
|
||||
font-size: 28rpx;
|
||||
border-top-right-radius: 50rpx;
|
||||
border-bottom-right-radius: 50rpx;
|
||||
color: #890001;
|
||||
background: rgba(82, 184, 245, 0.1);
|
||||
}
|
||||
|
||||
.date-befor, .date-after {
|
||||
/* border: 1px red solid; */
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 80rpx;
|
||||
width: 80rpx;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
/* margin-right: 20rpx; */
|
||||
}
|
||||
|
||||
/* .date-after {
|
||||
margin-left: 20rpx;
|
||||
} */
|
||||
|
||||
.calendar-panel-box {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.calendar-header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.calendar-header view,
|
||||
.calendar-header cover-view {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
color: #890001;
|
||||
}
|
||||
.calendar-header.mini view,
|
||||
.calendar-header.mini cover-view
|
||||
{
|
||||
line-height: 50rpx;
|
||||
}
|
||||
.calendar-body {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.calender-body-date-week {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
border-bottom: 1px #f5f5f5 solid;
|
||||
height:100rpx;
|
||||
padding:10rpx 0;
|
||||
}
|
||||
.date {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
color: #1c1c1c;
|
||||
background: #fff;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
.date.mini{
|
||||
height:120rpx;
|
||||
}
|
||||
.date.active {
|
||||
background: red;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #1c1c1c;
|
||||
}
|
||||
|
||||
.date-current {
|
||||
background: #890001;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.date-lock {
|
||||
color: #ff5a5f;
|
||||
}
|
||||
.data-circle {
|
||||
color: #890001;
|
||||
font-weight: bold;
|
||||
}
|
||||
.data-circle.mini{
|
||||
bottom: 2rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.packup {
|
||||
width: 100%;
|
||||
height: 100rpx;
|
||||
line-height: 100rpx;
|
||||
text-align: center;
|
||||
color: #890001;
|
||||
align-items: center;
|
||||
}
|
||||
.packup-button{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 50%;
|
||||
height: 55px;
|
||||
line-height:55px!important;
|
||||
}
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
.flex-between{
|
||||
justify-content: space-between;
|
||||
}
|
||||
.flex-center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.border-left{
|
||||
border-left:1px solid #eee;
|
||||
}
|
||||
.cmf-btn{
|
||||
background-color: #39b54a;
|
||||
color: #fff;
|
||||
border: 1rpx solid #39b54a;
|
||||
}
|
23
components/empty/index.js
Normal file
@ -0,0 +1,23 @@
|
||||
// lionfish_comshop/components/empty/index.js
|
||||
Component({
|
||||
/**
|
||||
* 组件的属性列表
|
||||
*/
|
||||
properties: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的初始数据
|
||||
*/
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的方法列表
|
||||
*/
|
||||
methods: {
|
||||
|
||||
}
|
||||
})
|
4
components/empty/index.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
4
components/empty/index.wxml
Normal file
@ -0,0 +1,4 @@
|
||||
<view class="none-rush-list">
|
||||
<image class="img-block" src="/images/icon-index-empty.png"></image>
|
||||
<view class="h1"><slot></slot></view>
|
||||
</view>
|
21
components/empty/index.wxss
Normal file
@ -0,0 +1,21 @@
|
||||
.none-rush-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 140rpx;
|
||||
padding-top: 140rpx;
|
||||
}
|
||||
|
||||
.none-rush-list .img-block {
|
||||
width: 240rpx;
|
||||
height: 240rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.none-rush-list .h1 {
|
||||
font-size: 32rpx;
|
||||
line-height: 32rpx;
|
||||
color: #444;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
97
components/parser/libs/CssHandler.js
Normal file
@ -0,0 +1,97 @@
|
||||
const cfg = require('./config.js'),
|
||||
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
|
||||
function CssHandler(tagStyle) {
|
||||
var styles = Object.assign(Object.create(null), cfg.userAgentStyles);
|
||||
for (var item in tagStyle)
|
||||
styles[item] = (styles[item] ? styles[item] + ';' : '') + tagStyle[item];
|
||||
this.styles = styles;
|
||||
}
|
||||
CssHandler.prototype.getStyle = function (data) {
|
||||
this.styles = new parser(data, this.styles).parse();
|
||||
}
|
||||
CssHandler.prototype.match = function (name, attrs) {
|
||||
var tmp, matched = (tmp = this.styles[name]) ? tmp + ';' : '';
|
||||
if (attrs.class) {
|
||||
var items = attrs.class.split(' ');
|
||||
for (var i = 0, item; item = items[i]; i++)
|
||||
if (tmp = this.styles['.' + item])
|
||||
matched += tmp + ';';
|
||||
}
|
||||
if (tmp = this.styles['#' + attrs.id])
|
||||
matched += tmp + ';';
|
||||
return matched;
|
||||
}
|
||||
module.exports = CssHandler;
|
||||
|
||||
function parser(data, init) {
|
||||
this.data = data;
|
||||
this.floor = 0;
|
||||
this.i = 0;
|
||||
this.list = [];
|
||||
this.res = init;
|
||||
this.state = this.Space;
|
||||
}
|
||||
parser.prototype.parse = function () {
|
||||
for (var c; c = this.data[this.i]; this.i++)
|
||||
this.state(c);
|
||||
return this.res;
|
||||
}
|
||||
parser.prototype.section = function () {
|
||||
return this.data.substring(this.start, this.i);
|
||||
}
|
||||
// 状态机
|
||||
parser.prototype.Space = function (c) {
|
||||
if (c == '.' || c == '#' || isLetter(c)) {
|
||||
this.start = this.i;
|
||||
this.state = this.Name;
|
||||
} else if (c == '/' && this.data[this.i + 1] == '*')
|
||||
this.Comment();
|
||||
else if (!cfg.blankChar[c] && c != ';')
|
||||
this.state = this.Ignore;
|
||||
}
|
||||
parser.prototype.Comment = function () {
|
||||
this.i = this.data.indexOf('*/', this.i) + 1;
|
||||
if (!this.i) this.i = this.data.length;
|
||||
this.state = this.Space;
|
||||
}
|
||||
parser.prototype.Ignore = function (c) {
|
||||
if (c == '{') this.floor++;
|
||||
else if (c == '}' && !--this.floor) this.state = this.Space;
|
||||
}
|
||||
parser.prototype.Name = function (c) {
|
||||
if (cfg.blankChar[c]) {
|
||||
this.list.push(this.section());
|
||||
this.state = this.NameSpace;
|
||||
} else if (c == '{') {
|
||||
this.list.push(this.section());
|
||||
this.Content();
|
||||
} else if (c == ',') {
|
||||
this.list.push(this.section());
|
||||
this.Comma();
|
||||
} else if (!isLetter(c) && (c < '0' || c > '9') && c != '-' && c != '_')
|
||||
this.state = this.Ignore;
|
||||
}
|
||||
parser.prototype.NameSpace = function (c) {
|
||||
if (c == '{') this.Content();
|
||||
else if (c == ',') this.Comma();
|
||||
else if (!cfg.blankChar[c]) this.state = this.Ignore;
|
||||
}
|
||||
parser.prototype.Comma = function () {
|
||||
while (cfg.blankChar[this.data[++this.i]]);
|
||||
if (this.data[this.i] == '{') this.Content();
|
||||
else {
|
||||
this.start = this.i--;
|
||||
this.state = this.Name;
|
||||
}
|
||||
}
|
||||
parser.prototype.Content = function () {
|
||||
this.start = ++this.i;
|
||||
if ((this.i = this.data.indexOf('}', this.i)) == -1) this.i = this.data.length;
|
||||
var content = this.section();
|
||||
for (var i = 0, item; item = this.list[i++];)
|
||||
if (this.res[item]) this.res[item] += ';' + content;
|
||||
else this.res[item] = content;
|
||||
this.list = [];
|
||||
this.state = this.Space;
|
||||
}
|
526
components/parser/libs/MpHtmlParser.js
Normal file
@ -0,0 +1,526 @@
|
||||
/**
|
||||
* html 解析器
|
||||
* @tutorial https://github.com/jin-yufeng/Parser
|
||||
* @version 20200630
|
||||
* @author JinYufeng
|
||||
* @listens MIT
|
||||
*/
|
||||
const cfg = require('./config.js'),
|
||||
blankChar = cfg.blankChar,
|
||||
CssHandler = require('./CssHandler.js'),
|
||||
windowWidth = wx.getSystemInfoSync().windowWidth;
|
||||
var emoji;
|
||||
|
||||
function MpHtmlParser(data, options = {}) {
|
||||
this.attrs = {};
|
||||
this.CssHandler = new CssHandler(options.tagStyle, windowWidth);
|
||||
this.data = data;
|
||||
this.domain = options.domain;
|
||||
this.DOM = [];
|
||||
this.i = this.start = this.audioNum = this.imgNum = this.videoNum = 0;
|
||||
options.prot = (this.domain || '').includes('://') ? this.domain.split('://')[0] : 'http';
|
||||
this.options = options;
|
||||
this.state = this.Text;
|
||||
this.STACK = [];
|
||||
// 工具函数
|
||||
this.bubble = () => {
|
||||
for (var i = this.STACK.length, item; item = this.STACK[--i];) {
|
||||
if (cfg.richOnlyTags[item.name]) {
|
||||
if (item.name == 'table' && !Object.hasOwnProperty.call(item, 'c')) item.c = 1;
|
||||
return false;
|
||||
}
|
||||
item.c = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
this.decode = (val, amp) => {
|
||||
var i = -1,
|
||||
j, en;
|
||||
while (1) {
|
||||
if ((i = val.indexOf('&', i + 1)) == -1) break;
|
||||
if ((j = val.indexOf(';', i + 2)) == -1) break;
|
||||
if (val[i + 1] == '#') {
|
||||
en = parseInt((val[i + 2] == 'x' ? '0' : '') + val.substring(i + 2, j));
|
||||
if (!isNaN(en)) val = val.substr(0, i) + String.fromCharCode(en) + val.substr(j + 1);
|
||||
} else {
|
||||
en = val.substring(i + 1, j);
|
||||
if (cfg.entities[en] || en == amp)
|
||||
val = val.substr(0, i) + (cfg.entities[en] || '&') + val.substr(j + 1);
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
this.getUrl = url => {
|
||||
if (url[0] == '/') {
|
||||
if (url[1] == '/') url = this.options.prot + ':' + url;
|
||||
else if (this.domain) url = this.domain + url;
|
||||
} else if (this.domain && url.indexOf('data:') != 0 && !url.includes('://'))
|
||||
url = this.domain + '/' + url;
|
||||
return url;
|
||||
}
|
||||
this.isClose = () => this.data[this.i] == '>' || (this.data[this.i] == '/' && this.data[this.i + 1] == '>');
|
||||
this.section = () => this.data.substring(this.start, this.i);
|
||||
this.parent = () => this.STACK[this.STACK.length - 1];
|
||||
this.siblings = () => this.STACK.length ? this.parent().children : this.DOM;
|
||||
}
|
||||
MpHtmlParser.prototype.parse = function () {
|
||||
if (emoji) this.data = emoji.parseEmoji(this.data);
|
||||
for (var c; c = this.data[this.i]; this.i++)
|
||||
this.state(c);
|
||||
if (this.state == this.Text) this.setText();
|
||||
while (this.STACK.length) this.popNode(this.STACK.pop());
|
||||
return this.DOM;
|
||||
}
|
||||
// 设置属性
|
||||
MpHtmlParser.prototype.setAttr = function () {
|
||||
var name = this.attrName.toLowerCase(),
|
||||
val = this.attrVal;
|
||||
if (cfg.boolAttrs[name]) this.attrs[name] = 'T';
|
||||
else if (val) {
|
||||
if (name == 'src' || (name == 'data-src' && !this.attrs.src)) this.attrs.src = this.getUrl(this.decode(val, 'amp'));
|
||||
else if (name == 'href' || name == 'style') this.attrs[name] = this.decode(val, 'amp');
|
||||
else if (name.substr(0, 5) != 'data-') this.attrs[name] = val;
|
||||
}
|
||||
this.attrVal = '';
|
||||
while (blankChar[this.data[this.i]]) this.i++;
|
||||
if (this.isClose()) this.setNode();
|
||||
else {
|
||||
this.start = this.i;
|
||||
this.state = this.AttrName;
|
||||
}
|
||||
}
|
||||
// 设置文本节点
|
||||
MpHtmlParser.prototype.setText = function () {
|
||||
var back, text = this.section();
|
||||
if (!text) return;
|
||||
text = (cfg.onText && cfg.onText(text, () => back = true)) || text;
|
||||
if (back) {
|
||||
this.data = this.data.substr(0, this.start) + text + this.data.substr(this.i);
|
||||
let j = this.start + text.length;
|
||||
for (this.i = this.start; this.i < j; this.i++) this.state(this.data[this.i]);
|
||||
return;
|
||||
}
|
||||
if (!this.pre) {
|
||||
// 合并空白符
|
||||
var tmp = [];
|
||||
for (let i = text.length, c; c = text[--i];)
|
||||
if (!blankChar[c] || (!blankChar[tmp[0]] && (c = ' '))) tmp.unshift(c);
|
||||
text = tmp.join('');
|
||||
}
|
||||
this.siblings().push({
|
||||
type: 'text',
|
||||
text: this.decode(text)
|
||||
});
|
||||
}
|
||||
// 设置元素节点
|
||||
MpHtmlParser.prototype.setNode = function () {
|
||||
var node = {
|
||||
name: this.tagName.toLowerCase(),
|
||||
attrs: this.attrs
|
||||
},
|
||||
close = cfg.selfClosingTags[node.name];
|
||||
this.attrs = {};
|
||||
if (!cfg.ignoreTags[node.name]) {
|
||||
// 处理属性
|
||||
var attrs = node.attrs,
|
||||
style = this.CssHandler.match(node.name, attrs, node) + (attrs.style || ''),
|
||||
styleObj = {};
|
||||
if (attrs.id) {
|
||||
if (this.options.compress & 1) attrs.id = void 0;
|
||||
else if (this.options.useAnchor) this.bubble();
|
||||
}
|
||||
if ((this.options.compress & 2) && attrs.class) attrs.class = void 0;
|
||||
switch (node.name) {
|
||||
case 'a':
|
||||
case 'ad':
|
||||
this.bubble();
|
||||
break;
|
||||
case 'font':
|
||||
if (attrs.color) {
|
||||
styleObj['color'] = attrs.color;
|
||||
attrs.color = void 0;
|
||||
}
|
||||
if (attrs.face) {
|
||||
styleObj['font-family'] = attrs.face;
|
||||
attrs.face = void 0;
|
||||
}
|
||||
if (attrs.size) {
|
||||
var size = parseInt(attrs.size);
|
||||
if (size < 1) size = 1;
|
||||
else if (size > 7) size = 7;
|
||||
var map = ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large'];
|
||||
styleObj['font-size'] = map[size - 1];
|
||||
attrs.size = void 0;
|
||||
}
|
||||
break;
|
||||
case 'embed':
|
||||
var src = node.attrs.src || '',
|
||||
type = node.attrs.type || '';
|
||||
if (type.includes('video') || src.includes('.mp4') || src.includes('.3gp') || src.includes('.m3u8'))
|
||||
node.name = 'video';
|
||||
else if (type.includes('audio') || src.includes('.m4a') || src.includes('.wav') || src.includes('.mp3') || src.includes('.aac'))
|
||||
node.name = 'audio';
|
||||
else break;
|
||||
if (node.attrs.autostart)
|
||||
node.attrs.autoplay = 'T';
|
||||
node.attrs.controls = 'T';
|
||||
// falls through
|
||||
case 'video':
|
||||
case 'audio':
|
||||
if (!attrs.id) attrs.id = node.name + (++this[`${node.name}Num`]);
|
||||
else this[`${node.name}Num`]++;
|
||||
if (node.name == 'video') {
|
||||
if (this.videoNum > 3)
|
||||
node.lazyLoad = 1;
|
||||
if (attrs.width) {
|
||||
styleObj.width = parseFloat(attrs.width) + (attrs.width.includes('%') ? '%' : 'px');
|
||||
attrs.width = void 0;
|
||||
}
|
||||
if (attrs.height) {
|
||||
styleObj.height = parseFloat(attrs.height) + (attrs.height.includes('%') ? '%' : 'px');
|
||||
attrs.height = void 0;
|
||||
}
|
||||
}
|
||||
attrs.source = [];
|
||||
if (attrs.src) {
|
||||
attrs.source.push(attrs.src);
|
||||
attrs.src = void 0;
|
||||
}
|
||||
this.bubble();
|
||||
break;
|
||||
case 'td':
|
||||
case 'th':
|
||||
if (attrs.colspan || attrs.rowspan)
|
||||
for (var k = this.STACK.length, item; item = this.STACK[--k];)
|
||||
if (item.name == 'table') {
|
||||
item.c = void 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (attrs.align) {
|
||||
styleObj['text-align'] = attrs.align;
|
||||
attrs.align = void 0;
|
||||
}
|
||||
// 压缩 style
|
||||
var styles = style.split(';');
|
||||
style = '';
|
||||
for (var i = 0, len = styles.length; i < len; i++) {
|
||||
var info = styles[i].split(':');
|
||||
if (info.length < 2) continue;
|
||||
let key = info[0].trim().toLowerCase(),
|
||||
value = info.slice(1).join(':').trim();
|
||||
if (value.includes('-webkit') || value.includes('-moz') || value.includes('-ms') || value.includes('-o') || value.includes('safe'))
|
||||
style += `;${key}:${value}`;
|
||||
else if (!styleObj[key] || value.includes('import') || !styleObj[key].includes('import'))
|
||||
styleObj[key] = value;
|
||||
}
|
||||
if (node.name == 'img') {
|
||||
if (attrs.src && !attrs.ignore) {
|
||||
if (this.bubble())
|
||||
attrs.i = (this.imgNum++).toString();
|
||||
else attrs.ignore = 'T';
|
||||
}
|
||||
if (attrs.ignore) {
|
||||
style += ';-webkit-touch-callout:none';
|
||||
styleObj['max-width'] = '100%';
|
||||
}
|
||||
if (!styleObj.position)
|
||||
styleObj.top = styleObj.bottom = styleObj.left = styleObj.right = styleObj['z-index'] = void 0;
|
||||
var width;
|
||||
if (styleObj.width) width = styleObj.width;
|
||||
else if (attrs.width) width = attrs.width.includes('%') ? attrs.width : attrs.width + 'px';
|
||||
if (width) {
|
||||
styleObj.width = width;
|
||||
attrs.width = '100%';
|
||||
if (parseInt(width) > windowWidth) {
|
||||
styleObj.height = '';
|
||||
if (attrs.height) attrs.height = void 0;
|
||||
}
|
||||
}
|
||||
if (styleObj.height) {
|
||||
attrs.height = styleObj.height;
|
||||
styleObj.height = '';
|
||||
} else if (attrs.height && !attrs.height.includes('%'))
|
||||
attrs.height += 'px';
|
||||
}
|
||||
for (var key in styleObj) {
|
||||
var value = styleObj[key];
|
||||
if (!value) continue;
|
||||
if (key.includes('flex') || key == 'order' || key == 'self-align') node.c = 1;
|
||||
// 填充链接
|
||||
if (value.includes('url')) {
|
||||
var j = value.indexOf('(');
|
||||
if (j++ != -1) {
|
||||
while (value[j] == '"' || value[j] == "'" || blankChar[value[j]]) j++;
|
||||
value = value.substr(0, j) + this.getUrl(value.substr(j));
|
||||
}
|
||||
}
|
||||
// 转换 rpx
|
||||
else if (value.includes('rpx'))
|
||||
value = value.replace(/[0-9.]+\s*rpx/g, $ => parseFloat($) * windowWidth / 750 + 'px');
|
||||
else if (key == 'white-space' && value.includes('pre') && !close)
|
||||
this.pre = node.pre = true;
|
||||
style += `;${key}:${value}`;
|
||||
}
|
||||
style = style.substr(1);
|
||||
if (style) attrs.style = style;
|
||||
if (!close) {
|
||||
node.children = [];
|
||||
if (node.name == 'pre' && cfg.highlight) {
|
||||
this.remove(node);
|
||||
this.pre = node.pre = true;
|
||||
}
|
||||
this.siblings().push(node);
|
||||
this.STACK.push(node);
|
||||
} else if (!cfg.filter || cfg.filter(node, this) != false)
|
||||
this.siblings().push(node);
|
||||
} else {
|
||||
if (!close) this.remove(node);
|
||||
else if (node.name == 'source') {
|
||||
var parent = this.parent();
|
||||
if (parent && (parent.name == 'video' || parent.name == 'audio') && node.attrs.src)
|
||||
parent.attrs.source.push(node.attrs.src);
|
||||
} else if (node.name == 'base' && !this.domain) this.domain = node.attrs.href;
|
||||
}
|
||||
if (this.data[this.i] == '/') this.i++;
|
||||
this.start = this.i + 1;
|
||||
this.state = this.Text;
|
||||
}
|
||||
// 移除标签
|
||||
MpHtmlParser.prototype.remove = function (node) {
|
||||
var name = node.name,
|
||||
j = this.i;
|
||||
// 处理 svg
|
||||
var handleSvg = () => {
|
||||
var src = this.data.substring(j, this.i + 1);
|
||||
if (!node.attrs.xmlns) src = ' xmlns="http://www.w3.org/2000/svg"' + src;
|
||||
var i = j;
|
||||
while (this.data[j] != '<') j--;
|
||||
src = this.data.substring(j, i) + src;
|
||||
var parent = this.parent();
|
||||
if (node.attrs.width == '100%' && parent && (parent.attrs.style || '').includes('inline'))
|
||||
parent.attrs.style = 'width:300px;max-width:100%;' + parent.attrs.style;
|
||||
this.siblings().push({
|
||||
name: 'img',
|
||||
attrs: {
|
||||
src: 'data:image/svg+xml;utf8,' + src.replace(/#/g, '%23'),
|
||||
style: (/vertical[^;]+/.exec(node.attrs.style) || []).shift(),
|
||||
ignore: 'T'
|
||||
}
|
||||
})
|
||||
}
|
||||
if (node.name == 'svg' && this.data[j] == '/') return handleSvg(this.i++);
|
||||
while (1) {
|
||||
if ((this.i = this.data.indexOf('</', this.i + 1)) == -1) {
|
||||
if (name == 'pre' || name == 'svg') this.i = j;
|
||||
else this.i = this.data.length;
|
||||
return;
|
||||
}
|
||||
this.start = (this.i += 2);
|
||||
while (!blankChar[this.data[this.i]] && !this.isClose()) this.i++;
|
||||
if (this.section().toLowerCase() == name) {
|
||||
// 代码块高亮
|
||||
if (name == 'pre') {
|
||||
this.data = this.data.substr(0, j + 1) + cfg.highlight(this.data.substring(j + 1, this.i - 5), node.attrs) + this.data.substr(this.i - 5);
|
||||
return this.i = j;
|
||||
} else if (name == 'style')
|
||||
this.CssHandler.getStyle(this.data.substring(j + 1, this.i - 7));
|
||||
else if (name == 'title')
|
||||
this.DOM.title = this.data.substring(j + 1, this.i - 7);
|
||||
if ((this.i = this.data.indexOf('>', this.i)) == -1) this.i = this.data.length;
|
||||
if (name == 'svg') handleSvg();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 节点出栈处理
|
||||
MpHtmlParser.prototype.popNode = function (node) {
|
||||
// 空白符处理
|
||||
if (node.pre) {
|
||||
node.pre = this.pre = void 0;
|
||||
for (let i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].pre)
|
||||
this.pre = true;
|
||||
}
|
||||
var siblings = this.siblings(),
|
||||
len = siblings.length,
|
||||
childs = node.children;
|
||||
if (node.name == 'head' || (cfg.filter && cfg.filter(node, this) == false))
|
||||
return siblings.pop();
|
||||
var attrs = node.attrs;
|
||||
// 替换一些标签名
|
||||
if (cfg.blockTags[node.name]) node.name = 'div';
|
||||
else if (!cfg.trustTags[node.name]) node.name = 'span';
|
||||
// 去除块标签前后空串
|
||||
if (node.name == 'div' || node.name == 'p' || node.name[0] == 't') {
|
||||
if (len > 1 && siblings[len - 2].text == ' ')
|
||||
siblings.splice(--len - 1, 1);
|
||||
if (childs.length && childs[childs.length - 1].text == ' ')
|
||||
childs.pop();
|
||||
}
|
||||
// 处理列表
|
||||
if (node.c && (node.name == 'ul' || node.name == 'ol')) {
|
||||
if ((node.attrs.style || '').includes('list-style:none')) {
|
||||
for (let i = 0, child; child = childs[i++];)
|
||||
if (child.name == 'li')
|
||||
child.name = 'div';
|
||||
} else if (node.name == 'ul') {
|
||||
var floor = 1;
|
||||
for (let i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].name == 'ul') floor++;
|
||||
if (floor != 1)
|
||||
for (let i = childs.length; i--;)
|
||||
childs[i].floor = floor;
|
||||
} else {
|
||||
for (let i = 0, num = 1, child; child = childs[i++];)
|
||||
if (child.name == 'li') {
|
||||
child.type = 'ol';
|
||||
child.num = ((num, type) => {
|
||||
if (type == 'a') return String.fromCharCode(97 + (num - 1) % 26);
|
||||
if (type == 'A') return String.fromCharCode(65 + (num - 1) % 26);
|
||||
if (type == 'i' || type == 'I') {
|
||||
num = (num - 1) % 99 + 1;
|
||||
var one = ['I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'],
|
||||
ten = ['X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'],
|
||||
res = (ten[Math.floor(num / 10) - 1] || '') + (one[num % 10 - 1] || '');
|
||||
if (type == 'i') return res.toLowerCase();
|
||||
return res;
|
||||
}
|
||||
return num;
|
||||
})(num++, attrs.type) + '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
// 处理表格的边框
|
||||
if (node.name == 'table') {
|
||||
var padding = attrs.cellpadding,
|
||||
spacing = attrs.cellspacing,
|
||||
border = attrs.border;
|
||||
if (node.c) {
|
||||
this.bubble();
|
||||
attrs.style = (attrs.style || '') + ';display:table';
|
||||
if (!padding) padding = 2;
|
||||
if (!spacing) spacing = 2;
|
||||
}
|
||||
if (border) attrs.style = `border:${border}px solid gray;${attrs.style || ''}`;
|
||||
if (spacing) attrs.style = `border-spacing:${spacing}px;${attrs.style || ''}`;
|
||||
if (border || padding || node.c)
|
||||
(function f(ns) {
|
||||
for (var i = 0, n; n = ns[i]; i++) {
|
||||
if (n.type == 'text') continue;
|
||||
var style = n.attrs.style || '';
|
||||
if (node.c && n.name[0] == 't') {
|
||||
n.c = 1;
|
||||
style += ';display:table-' + (n.name == 'th' || n.name == 'td' ? 'cell' : (n.name == 'tr' ? 'row' : 'row-group'));
|
||||
}
|
||||
if (n.name == 'th' || n.name == 'td') {
|
||||
if (border) style = `border:${border}px solid gray;${style}`;
|
||||
if (padding) style = `padding:${padding}px;${style}`;
|
||||
} else f(n.children || []);
|
||||
if (style) n.attrs.style = style;
|
||||
}
|
||||
})(childs)
|
||||
if (this.options.autoscroll) {
|
||||
var table = Object.assign({}, node);
|
||||
node.name = 'div';
|
||||
node.attrs = {
|
||||
style: 'overflow:scroll'
|
||||
}
|
||||
node.children = [table];
|
||||
}
|
||||
}
|
||||
this.CssHandler.pop && this.CssHandler.pop(node);
|
||||
// 自动压缩
|
||||
if (node.name == 'div' && !Object.keys(attrs).length && childs.length == 1 && childs[0].name == 'div')
|
||||
siblings[len - 1] = childs[0];
|
||||
}
|
||||
// 状态机
|
||||
MpHtmlParser.prototype.Text = function (c) {
|
||||
if (c == '<') {
|
||||
var next = this.data[this.i + 1],
|
||||
isLetter = c => (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
if (isLetter(next)) {
|
||||
this.setText();
|
||||
this.start = this.i + 1;
|
||||
this.state = this.TagName;
|
||||
} else if (next == '/') {
|
||||
this.setText();
|
||||
if (isLetter(this.data[++this.i + 1])) {
|
||||
this.start = this.i + 1;
|
||||
this.state = this.EndTag;
|
||||
} else this.Comment();
|
||||
} else if (next == '!') {
|
||||
this.setText();
|
||||
this.Comment();
|
||||
}
|
||||
}
|
||||
}
|
||||
MpHtmlParser.prototype.Comment = function () {
|
||||
var key;
|
||||
if (this.data.substring(this.i + 2, this.i + 4) == '--') key = '-->';
|
||||
else if (this.data.substring(this.i + 2, this.i + 9) == '[CDATA[') key = ']]>';
|
||||
else key = '>';
|
||||
if ((this.i = this.data.indexOf(key, this.i + 2)) == -1) this.i = this.data.length;
|
||||
else this.i += key.length - 1;
|
||||
this.start = this.i + 1;
|
||||
this.state = this.Text;
|
||||
}
|
||||
MpHtmlParser.prototype.TagName = function (c) {
|
||||
if (blankChar[c]) {
|
||||
this.tagName = this.section();
|
||||
while (blankChar[this.data[this.i]]) this.i++;
|
||||
if (this.isClose()) this.setNode();
|
||||
else {
|
||||
this.start = this.i;
|
||||
this.state = this.AttrName;
|
||||
}
|
||||
} else if (this.isClose()) {
|
||||
this.tagName = this.section();
|
||||
this.setNode();
|
||||
}
|
||||
}
|
||||
MpHtmlParser.prototype.AttrName = function (c) {
|
||||
if (c == '=' || blankChar[c] || this.isClose()) {
|
||||
this.attrName = this.section();
|
||||
if (blankChar[c])
|
||||
while (blankChar[this.data[++this.i]]);
|
||||
if (this.data[this.i] == '=') {
|
||||
while (blankChar[this.data[++this.i]]);
|
||||
this.start = this.i--;
|
||||
this.state = this.AttrValue;
|
||||
} else this.setAttr();
|
||||
}
|
||||
}
|
||||
MpHtmlParser.prototype.AttrValue = function (c) {
|
||||
if (c == '"' || c == "'") {
|
||||
this.start++;
|
||||
if ((this.i = this.data.indexOf(c, this.i + 1)) == -1) return this.i = this.data.length;
|
||||
this.attrVal = this.section();
|
||||
this.i++;
|
||||
} else {
|
||||
for (; !blankChar[this.data[this.i]] && !this.isClose(); this.i++);
|
||||
this.attrVal = this.section();
|
||||
}
|
||||
this.setAttr();
|
||||
}
|
||||
MpHtmlParser.prototype.EndTag = function (c) {
|
||||
if (blankChar[c] || c == '>' || c == '/') {
|
||||
var name = this.section().toLowerCase();
|
||||
for (var i = this.STACK.length; i--;)
|
||||
if (this.STACK[i].name == name) break;
|
||||
if (i != -1) {
|
||||
var node;
|
||||
while ((node = this.STACK.pop()).name != name) this.popNode(node);
|
||||
this.popNode(node);
|
||||
} else if (name == 'p' || name == 'br')
|
||||
this.siblings().push({
|
||||
name,
|
||||
attrs: {}
|
||||
});
|
||||
this.i = this.data.indexOf('>', this.i);
|
||||
this.start = this.i + 1;
|
||||
if (this.i == -1) this.i = this.data.length;
|
||||
else this.state = this.Text;
|
||||
}
|
||||
}
|
||||
module.exports = MpHtmlParser;
|
63
components/parser/libs/config.js
Normal file
@ -0,0 +1,63 @@
|
||||
/* 配置文件 */
|
||||
const canIUse = wx.canIUse('editor'); // 高基础库标识,用于兼容
|
||||
module.exports = {
|
||||
// 出错占位图
|
||||
errorImg: null,
|
||||
// 过滤器函数
|
||||
filter: null,
|
||||
// 代码高亮函数
|
||||
highlight: null,
|
||||
// 文本处理函数
|
||||
onText: null,
|
||||
// 实体编码列表
|
||||
entities: {
|
||||
quot: '"',
|
||||
apos: "'",
|
||||
semi: ';',
|
||||
nbsp: '\xA0',
|
||||
ndash: '–',
|
||||
mdash: '—',
|
||||
middot: '·',
|
||||
lsquo: '‘',
|
||||
rsquo: '’',
|
||||
ldquo: '“',
|
||||
rdquo: '”',
|
||||
bull: '•',
|
||||
hellip: '…'
|
||||
},
|
||||
blankChar: makeMap(' ,\xA0,\t,\r,\n,\f'),
|
||||
boolAttrs: makeMap('autoplay,autostart,controls,ignore,loop,muted'),
|
||||
// 块级标签,将被转为 div
|
||||
blockTags: makeMap('address,article,aside,body,caption,center,cite,footer,header,html,nav,section' + (canIUse ? '' : ',pre')),
|
||||
// 将被移除的标签
|
||||
ignoreTags: makeMap('area,base,canvas,frame,iframe,input,link,map,meta,param,script,source,style,svg,textarea,title,track,wbr' + (canIUse ? ',rp' : '')),
|
||||
// 只能被 rich-text 显示的标签
|
||||
richOnlyTags: makeMap('a,colgroup,fieldset,legend,table' + (canIUse ? ',bdi,bdo,rt,ruby' : '')),
|
||||
// 自闭合的标签
|
||||
selfClosingTags: makeMap('area,base,br,col,circle,ellipse,embed,frame,hr,img,input,line,link,meta,param,path,polygon,rect,source,track,use,wbr'),
|
||||
// 信任的标签
|
||||
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,source,span,strong,sub,sup,table,tbody,td,tfoot,th,thead,tr,title,ul,video' + (canIUse ? ',bdi,bdo,caption,pre,rt,ruby' : '')),
|
||||
// 默认的标签样式
|
||||
userAgentStyles: {
|
||||
address: 'font-style:italic',
|
||||
big: 'display:inline;font-size:1.2em',
|
||||
blockquote: 'background-color:#f6f6f6;border-left:3px solid #dbdbdb;color:#6c6c6c;padding:5px 0 5px 10px',
|
||||
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;overflow:scroll',
|
||||
s: 'text-decoration:line-through',
|
||||
small: 'display:inline;font-size:0.8em',
|
||||
u: 'text-decoration:underline'
|
||||
}
|
||||
}
|
||||
|
||||
function makeMap(str) {
|
||||
var map = Object.create(null),
|
||||
list = str.split(',');
|
||||
for (var i = list.length; i--;)
|
||||
map[list[i]] = true;
|
||||
return map;
|
||||
}
|
204
components/parser/parser.js
Normal file
@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Parser 富文本组件
|
||||
* @tutorial https://github.com/jin-yufeng/Parser
|
||||
* @version 20200630
|
||||
* @author JinYufeng
|
||||
* @listens MIT
|
||||
*/
|
||||
var cache = {},
|
||||
Parser = require('./libs/MpHtmlParser.js'),
|
||||
fs = wx.getFileSystemManager && wx.getFileSystemManager();
|
||||
var dom;
|
||||
// 计算 cache 的 key
|
||||
function hash(str) {
|
||||
for (var i = str.length, val = 5381; i--;)
|
||||
val += (val << 5) + str.charCodeAt(i);
|
||||
return val;
|
||||
}
|
||||
Component({
|
||||
options: {
|
||||
pureDataPattern: /^[acdgtu]|W/
|
||||
},
|
||||
data: {
|
||||
nodes: []
|
||||
},
|
||||
properties: {
|
||||
html: {
|
||||
type: String,
|
||||
observer(html) {
|
||||
this.setContent(html);
|
||||
}
|
||||
},
|
||||
autopause: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
autoscroll: Boolean,
|
||||
autosetTitle: {
|
||||
type: Boolean,
|
||||
value: true
|
||||
},
|
||||
compress: Number,
|
||||
domain: String,
|
||||
lazyLoad: Boolean,
|
||||
loadingImg: String,
|
||||
selectable: Boolean,
|
||||
tagStyle: Object,
|
||||
showWithAnimation: Boolean,
|
||||
useAnchor: Boolean,
|
||||
useCache: Boolean
|
||||
},
|
||||
relations: {
|
||||
'../parser-group/parser-group': {
|
||||
type: 'ancestor'
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// 图片数组
|
||||
this.imgList = [];
|
||||
this.imgList.setItem = function(i, src) {
|
||||
if (!i || !src) return;
|
||||
// 去重
|
||||
if (src.indexOf('http') == 0 && this.includes(src)) {
|
||||
var newSrc = '';
|
||||
for (var j = 0, c; c = src[j]; j++) {
|
||||
if (c == '/' && src[j - 1] != '/' && src[j + 1] != '/') break;
|
||||
newSrc += Math.random() > 0.5 ? c.toUpperCase() : c;
|
||||
}
|
||||
newSrc += src.substr(j);
|
||||
return this[i] = newSrc;
|
||||
}
|
||||
this[i] = src;
|
||||
// 暂存 data src
|
||||
if (src.includes('data:image')) {
|
||||
var info = src.match(/data:image\/(\S+?);(\S+?),(.+)/);
|
||||
if (!info) return;
|
||||
var filePath = `${wx.env.USER_DATA_PATH}/${Date.now()}.${info[1]}`;
|
||||
fs && fs.writeFile({
|
||||
filePath,
|
||||
data: info[3],
|
||||
encoding: info[2],
|
||||
success: () => this[i] = filePath
|
||||
})
|
||||
}
|
||||
}
|
||||
this.imgList.each = function(f) {
|
||||
for (var i = 0, len = this.length; i < len; i++)
|
||||
this.setItem(i, f(this[i], i, this));
|
||||
}
|
||||
if (dom) this.document = new dom(this);
|
||||
},
|
||||
detached() {
|
||||
// 删除暂存
|
||||
this.imgList.each(src => {
|
||||
if (src && src.includes(wx.env.USER_DATA_PATH) && fs)
|
||||
fs.unlink({
|
||||
filePath: src
|
||||
})
|
||||
})
|
||||
clearInterval(this._timer);
|
||||
},
|
||||
methods: {
|
||||
// 锚点跳转
|
||||
navigateTo(obj) {
|
||||
if (!this.data.useAnchor)
|
||||
return obj.fail && obj.fail({
|
||||
errMsg: 'Anchor is disabled'
|
||||
})
|
||||
this.createSelectorQuery()
|
||||
.select('.top' + (obj.id ? '>>>#' + obj.id : '')).boundingClientRect()
|
||||
.selectViewport().scrollOffset().exec(res => {
|
||||
if (!res[0])
|
||||
return this.group ? this.group.navigateTo(this.i, obj) :
|
||||
obj.fail && obj.fail({
|
||||
errMsg: 'Label not found'
|
||||
});
|
||||
obj.scrollTop = res[1].scrollTop + res[0].top + (obj.offset || 0);
|
||||
wx.pageScrollTo(obj);
|
||||
})
|
||||
},
|
||||
// 获取文本
|
||||
getText(ns = this.data.html) {
|
||||
var txt = '';
|
||||
for (var i = 0, n; n = ns[i++];) {
|
||||
if (n.type == 'text') txt += n.text.replace(/ /g, '\u00A0').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&');
|
||||
else if (n.type == 'br') txt += '\n';
|
||||
else {
|
||||
// 块级标签前后加换行
|
||||
var br = n.name == 'p' || n.name == 'div' || n.name == 'tr' || n.name == 'li' || (n.name[0] == 'h' && n.name[1] > '0' && n.name[1] < '7');
|
||||
if (br && txt && txt[txt.length - 1] != '\n') txt += '\n';
|
||||
if (n.children) txt += this.getText(n.children);
|
||||
if (br && txt[txt.length - 1] != '\n') txt += '\n';
|
||||
else if (n.name == 'td' || n.name == 'th') txt += '\t';
|
||||
}
|
||||
}
|
||||
return txt;
|
||||
},
|
||||
// 获取视频 context
|
||||
getVideoContext(id) {
|
||||
if (!id) return this.videoContexts;
|
||||
for (var i = this.videoContexts.length; i--;)
|
||||
if (this.videoContexts[i].id == id) return this.videoContexts[i];
|
||||
},
|
||||
// 渲染富文本
|
||||
setContent(html, append) {
|
||||
var nodes, parser = new Parser(html, this.data);
|
||||
// 缓存读取
|
||||
if (this.data.useCache) {
|
||||
var hashVal = hash(html);
|
||||
if (cache[hashVal]) nodes = cache[hashVal];
|
||||
else cache[hashVal] = nodes = parser.parse();
|
||||
} else nodes = parser.parse();
|
||||
this.triggerEvent('parse', nodes);
|
||||
var data = {};
|
||||
if (append)
|
||||
for (let i = this.data.nodes.length, j = nodes.length; j--;)
|
||||
data[`nodes[${i + j}]`] = nodes[j];
|
||||
else data.nodes = nodes;
|
||||
if (this.showWithAnimation) data.showAm = 'animation: show .5s';
|
||||
this.setData(data, () => {
|
||||
this.triggerEvent('load')
|
||||
});
|
||||
// 设置标题
|
||||
if (nodes.title && this.data.autosetTitle)
|
||||
wx.setNavigationBarTitle({
|
||||
title: nodes.title
|
||||
})
|
||||
this.imgList.length = 0;
|
||||
this.videoContexts = [];
|
||||
var ns = this.selectAllComponents('.top,.top>>>._node');
|
||||
for (let i = 0, n; n = ns[i++];) {
|
||||
n.top = this;
|
||||
for (let j = 0, item; item = n.data.nodes[j++];) {
|
||||
if (item.c) continue;
|
||||
// 获取图片列表
|
||||
if (item.name == 'img')
|
||||
this.imgList.setItem(item.attrs.i, item.attrs.src);
|
||||
// 音视频控制
|
||||
else if (item.name == 'video' || item.name == 'audio') {
|
||||
var ctx;
|
||||
if (item.name == 'video') ctx = wx.createVideoContext(item.attrs.id, n);
|
||||
else ctx = n.selectComponent('#' + item.attrs.id);
|
||||
if (ctx) {
|
||||
ctx.id = item.attrs.id;
|
||||
this.videoContexts.push(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var height;
|
||||
clearInterval(this._timer);
|
||||
this._timer = setInterval(() => {
|
||||
this.createSelectorQuery().select('.top').boundingClientRect(res => {
|
||||
if (!res) return;
|
||||
this.rect = res;
|
||||
if (res.height == height) {
|
||||
this.triggerEvent('ready', res)
|
||||
clearInterval(this._timer);
|
||||
}
|
||||
height = res.height;
|
||||
}).exec();
|
||||
}, 350)
|
||||
}
|
||||
}
|
||||
})
|
6
components/parser/parser.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"trees": "./trees/trees"
|
||||
}
|
||||
}
|
3
components/parser/parser.wxml
Normal file
@ -0,0 +1,3 @@
|
||||
<!--parser 主组件-->
|
||||
<slot wx:if="{{!nodes.length}}" />
|
||||
<trees class="top" style="{{selectable?'user-select:text;-webkit-user-select:text;':''}}{{showAm}}" lazy-load="{{lazyLoad}}" loading="{{loadingImg}}" nodes="{{nodes}}" />
|
19
components/parser/parser.wxss
Normal file
@ -0,0 +1,19 @@
|
||||
:host {
|
||||
display: block;
|
||||
overflow: scroll;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
|
||||
.top {
|
||||
display: inherit;
|
||||
}
|
||||
|
||||
@keyframes show {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
42
components/parser/trees/handler.wxs
Normal file
@ -0,0 +1,42 @@
|
||||
var inlineTags = {
|
||||
abbr: 1,
|
||||
b: 1,
|
||||
big: 1,
|
||||
code: 1,
|
||||
del: 1,
|
||||
em: 1,
|
||||
i: 1,
|
||||
ins: 1,
|
||||
label: 1,
|
||||
q: 1,
|
||||
small: 1,
|
||||
span: 1,
|
||||
strong: 1
|
||||
}
|
||||
module.exports = {
|
||||
// 从 rich-text 顶层标签的样式中取出一些给 rich-text
|
||||
getStyle: function(style, display) {
|
||||
if (style) {
|
||||
var i, j, res = "";
|
||||
if ((i = style.indexOf("display")) != -1)
|
||||
res = style.substring(i, (j = style.indexOf(';', i)) == -1 ? style.length : j);
|
||||
else res = "display:" + display;
|
||||
if (style.indexOf("flex") != -1) res += ';' + style.match(getRegExp("flex[:-][^;]+/g")).join(';');
|
||||
return res;
|
||||
} else return "display:" + display;
|
||||
},
|
||||
// 处理懒加载
|
||||
getNode: function(item, imgLoad) {
|
||||
if (!imgLoad) {
|
||||
delete item.attrs.src;
|
||||
item.attrs.style += ";width:20px !important;height:20px !important";
|
||||
}
|
||||
return [item];
|
||||
},
|
||||
// 是否通过 rich-text 显示
|
||||
useRichText: function(item) {
|
||||
// rich-text 不支持 inline
|
||||
if (item.c || inlineTags[item.name] || (item.attrs.style && item.attrs.style.indexOf("display:inline") != -1)) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
122
components/parser/trees/trees.js
Normal file
@ -0,0 +1,122 @@
|
||||
const errorImg = require('../libs/config.js').errorImg;
|
||||
Component({
|
||||
data: {
|
||||
canIUse: !!wx.chooseMessageFile,
|
||||
placeholder: "data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='300' height='225'/>"
|
||||
},
|
||||
properties: {
|
||||
nodes: Array,
|
||||
lazyLoad: Boolean,
|
||||
loading: String
|
||||
},
|
||||
methods: {
|
||||
// 视频播放事件
|
||||
play(e) {
|
||||
this.top.group && this.top.group.pause(this.top.i);
|
||||
if (this.top.videoContexts.length > 1 && this.top.data.autopause)
|
||||
for (var i = this.top.videoContexts.length; i--;)
|
||||
if (this.top.videoContexts[i].id != e.currentTarget.id)
|
||||
this.top.videoContexts[i].pause();
|
||||
},
|
||||
// 图片事件
|
||||
imgtap(e) {
|
||||
var attrs = e.currentTarget.dataset.attrs;
|
||||
if (!attrs.ignore) {
|
||||
var preview = true;
|
||||
this.top.triggerEvent('imgtap', {
|
||||
id: e.currentTarget.id,
|
||||
src: attrs.src,
|
||||
ignore: () => preview = false
|
||||
})
|
||||
if (preview) {
|
||||
if (this.top.group) return this.top.group.preview(this.top.i, attrs.i);
|
||||
var urls = this.top.imgList,
|
||||
current = urls[attrs.i] ? urls[attrs.i] : (urls = [attrs.src], attrs.src);
|
||||
wx.previewImage({
|
||||
current,
|
||||
urls
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
loadImg(e) {
|
||||
var i = e.target.dataset.i;
|
||||
if (this.data.lazyLoad && !this.data.nodes[i].load)
|
||||
this.setData({
|
||||
[`nodes[${i}].load`]: 1
|
||||
})
|
||||
else if (this.data.loading && this.data.nodes[i].load != 2)
|
||||
this.setData({
|
||||
[`nodes[${i}].load`]: 2
|
||||
})
|
||||
},
|
||||
// 链接点击事件
|
||||
linkpress(e) {
|
||||
var jump = true,
|
||||
attrs = e.currentTarget.dataset.attrs;
|
||||
attrs.ignore = () => jump = false;
|
||||
this.top.triggerEvent('linkpress', attrs);
|
||||
if (jump) {
|
||||
if (attrs['app-id'])
|
||||
wx.navigateToMiniProgram({
|
||||
appId: attrs['app-id'],
|
||||
path: attrs.path
|
||||
})
|
||||
else if (attrs.href) {
|
||||
if (attrs.href[0] == '#')
|
||||
this.top.navigateTo({
|
||||
id: attrs.href.substring(1)
|
||||
})
|
||||
else if (attrs.href.indexOf('http') == 0 || attrs.href.indexOf('//') == 0)
|
||||
wx.setClipboardData({
|
||||
data: attrs.href,
|
||||
success: () =>
|
||||
wx.showToast({
|
||||
title: '链接已复制'
|
||||
})
|
||||
})
|
||||
else
|
||||
wx.navigateTo({
|
||||
url: attrs.href,
|
||||
fail() {
|
||||
wx.switchTab({
|
||||
url: attrs.href,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
// 错误事件
|
||||
error(e) {
|
||||
var source = e.target.dataset.source,
|
||||
i = e.target.dataset.i,
|
||||
node = this.data.nodes[i];
|
||||
if (source == 'video' || source == 'audio') {
|
||||
// 加载其他 source
|
||||
var index = (node.i || 0) + 1;
|
||||
if (index < node.attrs.source.length)
|
||||
return this.setData({
|
||||
[`nodes[${i}].i`]: index
|
||||
})
|
||||
} else if (source == 'img' && errorImg) {
|
||||
this.top.imgList.setItem(e.target.dataset.index, errorImg);
|
||||
this.setData({
|
||||
[`nodes[${i}].attrs.src`]: errorImg
|
||||
})
|
||||
}
|
||||
this.top && this.top.triggerEvent('error', {
|
||||
source,
|
||||
target: e.target,
|
||||
errMsg: e.detail.errMsg
|
||||
})
|
||||
},
|
||||
// 加载视频
|
||||
loadVideo(e) {
|
||||
var i = e.target.dataset.i;
|
||||
this.setData({
|
||||
[`nodes[${i}].attrs.autoplay`]: true
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
6
components/parser/trees/trees.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {
|
||||
"trees": "./trees"
|
||||
}
|
||||
}
|
65
components/parser/trees/trees.wxml
Normal file
@ -0,0 +1,65 @@
|
||||
<!--trees 递归子组件-->
|
||||
<wxs module="handler">
|
||||
var inline = {
|
||||
abbr: 1,
|
||||
b: 1,
|
||||
big: 1,
|
||||
code: 1,
|
||||
del: 1,
|
||||
em: 1,
|
||||
i: 1,
|
||||
ins: 1,
|
||||
label: 1,
|
||||
q: 1,
|
||||
small: 1,
|
||||
span: 1,
|
||||
strong: 1
|
||||
}
|
||||
module.exports = {
|
||||
visited: function (e, owner) {
|
||||
if (!e.instance.hasClass('_visited'))
|
||||
e.instance.addClass('_visited')
|
||||
owner.callMethod('linkpress', e)
|
||||
},
|
||||
use: function (item) {
|
||||
return !item.c && !inline[item.name] && (item.attrs.style || '').indexOf('display:inline') == -1
|
||||
}
|
||||
}
|
||||
</wxs>
|
||||
<block wx:for="{{nodes}}" wx:key="index" wx:for-item="n">
|
||||
<!--图片-->
|
||||
<view wx:if="{{n.name=='img'}}" id="{{n.attrs.id}}" class="_img {{n.attrs.class}}" style="{{n.attrs.style}}" data-attrs="{{n.attrs}}" bindtap="imgtap">
|
||||
<rich-text nodes="{{[{attrs:{src:loading&&n.load!=2?loading:(lazyLoad&&!n.load?placeholder:n.attrs.src||''),alt:n.attrs.alt||'',width:n.attrs.width||'',style:'-webkit-touch-callout:none;max-width:100%;display:block'+(n.attrs.height?';height:'+n.attrs.height:'')},name:'img'}]}}" />
|
||||
<image class="_image" src="{{lazyLoad&&!n.load?placeholder:n.attrs.src}}" lazy-load="{{lazyLoad}}" show-menu-by-longpress="{{!n.attrs.ignore}}" data-i="{{index}}" data-index="{{n.attrs.i}}" data-source="img" bindload="loadImg" binderror="error" />
|
||||
</view>
|
||||
<!--文本-->
|
||||
<text wx:elif="{{n.type=='text'}}" decode>{{n.text}}</text>
|
||||
<text wx:elif="{{n.name=='br'}}">\n</text>
|
||||
<!--链接-->
|
||||
<view wx:elif="{{n.name=='a'}}" id="{{n.attrs.id}}" class="_a {{n.attrs.class}}" hover-class="_hover" style="{{n.attrs.style}}" data-attrs="{{n.attrs}}" bindtap="{{canIUse?handler.visited:'linkpress'}}">
|
||||
<trees class="_node" nodes="{{n.children}}" />
|
||||
</view>
|
||||
<!--视频-->
|
||||
<block wx:elif="{{n.name=='video'}}">
|
||||
<view wx:if="{{n.lazyLoad&&!n.attrs.autoplay}}" id="{{n.attrs.id}}" class="_video {{n.attrs.class}}" style="{{n.attrs.style}}" data-i="{{index}}" bindtap="loadVideo" />
|
||||
<video wx:else id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" autoplay="{{n.attrs.autoplay}}" controls="{{!n.attrs.autoplay||n.attrs.controls}}" loop="{{n.attrs.loop}}" muted="{{n.attrs.muted}}" poster="{{n.attrs.poster}}" src="{{n.attrs.source[n.i||0]}}" unit-id="{{n.attrs['unit-id']}}" data-i="{{index}}" data-source="video" binderror="error" bindplay="play" />
|
||||
</block>
|
||||
<!--音频-->
|
||||
<audio wx:elif="{{n.name=='audio'}}" id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" author="{{n.attrs.author}}" autoplay="{{n.attrs.autoplay}}" controls="{{n.attrs.controls}}" loop="{{n.attrs.loop}}" name="{{n.attrs.name}}" poster="{{n.attrs.poster}}" src="{{n.attrs.source[n.i||0]}}" data-i="{{index}}" data-source="audio" binderror="error" bindplay="play" />
|
||||
<!--广告-->
|
||||
<ad wx:elif="{{n.name=='ad'}}" class="{{n.attrs.class}}" style="{{n.attrs.style}}" unit-id="{{n.attrs['unit-id']}}" data-source="ad" binderror="error" />
|
||||
<!--列表-->
|
||||
<view wx:elif="{{n.name=='li'}}" id="{{n.attrs.id}}" class="{{n.attrs.class}}" style="{{n.attrs.style}};display:flex">
|
||||
<view wx:if="{{n.type=='ol'}}" class="_ol-bef">{{n.num}}</view>
|
||||
<view wx:else class="_ul-bef">
|
||||
<view wx:if="{{n.floor%3==0}}" class="_ul-p1">█</view>
|
||||
<view wx:elif="{{n.floor%3==2}}" class="_ul-p2" />
|
||||
<view wx:else class="_ul-p1" style="border-radius:50%">█</view>
|
||||
</view>
|
||||
<trees class="_node _li" lazyLoad="{{lazyLoad}}" loading="{{loading}}" nodes="{{n.children}}" />
|
||||
</view>
|
||||
<!--富文本-->
|
||||
<rich-text wx:elif="{{handler.use(n)}}" id="{{n.attrs.id}}" class="_p __{{n.name}}" nodes="{{[n]}}" />
|
||||
<!--继续递归-->
|
||||
<trees wx:else id="{{n.attrs.id}}" class="_node _{{n.name}} {{n.attrs.class}}" style="{{n.attrs.style}}" lazyLoad="{{lazyLoad}}" loading="{{loading}}" nodes="{{n.children}}" />
|
||||
</block>
|
184
components/parser/trees/trees.wxss
Normal file
@ -0,0 +1,184 @@
|
||||
/* 在这里引入自定义样式 */
|
||||
|
||||
/* 链接和图片效果 */
|
||||
._a {
|
||||
display: inline;
|
||||
padding: 1.5px 0 1.5px 0;
|
||||
color: #366092;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
._hover {
|
||||
text-decoration: underline;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
._visited {
|
||||
color: #551a8b;
|
||||
}
|
||||
|
||||
._img {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 内部样式 */
|
||||
:host {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
._blockquote,
|
||||
._div,
|
||||
._p,
|
||||
._ul,
|
||||
._ol,
|
||||
._li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
._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;
|
||||
}
|
||||
|
||||
._image {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
._ins {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
._li {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
._ol-bef {
|
||||
width: 36px;
|
||||
margin-right: 5px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
._ul-bef {
|
||||
margin: 0 12px 0 23px;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
._ol-bef,
|
||||
._ul_bef {
|
||||
flex: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
._ul-p1 {
|
||||
display: inline-block;
|
||||
width: 0.3em;
|
||||
height: 0.3em;
|
||||
overflow: hidden;
|
||||
line-height: 0.3em;
|
||||
}
|
||||
|
||||
._ul-p2 {
|
||||
display: inline-block;
|
||||
width: 0.23em;
|
||||
height: 0.23em;
|
||||
border: 0.05em solid black;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
._q::before {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
._q::after {
|
||||
content: '"';
|
||||
}
|
||||
|
||||
._sub {
|
||||
font-size: smaller;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
._sup {
|
||||
font-size: smaller;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.__bdi,
|
||||
.__bdo,
|
||||
.__ruby,
|
||||
.__rt {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
._video {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 300px;
|
||||
height: 225px;
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
._video::after {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -15px 0 0 -15px;
|
||||
content: '';
|
||||
border-color: transparent transparent transparent white;
|
||||
border-style: solid;
|
||||
border-width: 15px 0 15px 30px;
|
||||
}
|
||||
._img {
|
||||
vertical-align: top;
|
||||
}
|
57
components/shortcut/shortcut.js
Normal file
@ -0,0 +1,57 @@
|
||||
const App = getApp();
|
||||
|
||||
Component({
|
||||
options: {
|
||||
multipleSlots: true // 在组件定义时的选项中启用多slot支持
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的属性列表
|
||||
* 用于组件自定义设置
|
||||
*/
|
||||
properties: {
|
||||
// 弹窗标题
|
||||
title: {
|
||||
type: String,
|
||||
value: '弹窗标题'
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* 私有数据, 组件的初始数据
|
||||
* 可用于模版渲染
|
||||
*/
|
||||
data: {
|
||||
// 弹窗显示控制
|
||||
isShow: false,
|
||||
transparent: true
|
||||
},
|
||||
|
||||
/**
|
||||
* 组件的方法列表
|
||||
* 更新属性和数据的方法与更新页面数据的方法类似
|
||||
*/
|
||||
methods: {
|
||||
|
||||
/**
|
||||
* 导航菜单切换事件
|
||||
*/
|
||||
_onToggleShow(e) {
|
||||
this.setData({
|
||||
isShow: !this.data.isShow,
|
||||
transparent: false
|
||||
})
|
||||
},
|
||||
|
||||
/**
|
||||
* 导航页面跳转
|
||||
*/
|
||||
_onTargetPage(e) {
|
||||
let urls = App.getTabBarLinks();
|
||||
wx.switchTab({
|
||||
url: '/' + urls[e.detail.target.dataset.index]
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
})
|
4
components/shortcut/shortcut.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
32
components/shortcut/shortcut.wxml
Normal file
@ -0,0 +1,32 @@
|
||||
<view class="shortcut">
|
||||
|
||||
<!-- 首页 -->
|
||||
<form bindsubmit="_onTargetPage">
|
||||
<button formType="submit" data-index="0" class="nav-item btn-normal {{ isShow ? 'show_80' : (transparent ? '' : 'hide_80') }}">
|
||||
<text class="iconfont icon-home"></text>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- 全部活动 -->
|
||||
<form bindsubmit="_onTargetPage">
|
||||
<button formType="submit" data-index="1" class="nav-item btn-normal {{ isShow ? 'show_60' : (transparent ? '' : 'hide_60') }}">
|
||||
<text class="iconfont icon-cate"></text>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
|
||||
<!-- 个人中心 -->
|
||||
<form bindsubmit="_onTargetPage">
|
||||
<button formType="submit" data-index="3" class="nav-item btn-normal {{ isShow ? 'show_20' : (transparent ? '' : 'hide_20') }}">
|
||||
<text class="iconfont icon-profile"></text>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<!-- 显示隐藏开关 -->
|
||||
<form bindsubmit="_onToggleShow">
|
||||
<button formType="submit" class="nav-item nav-item__switch btn-normal {{ isShow ? 'shortcut_click_show' : '' }}">
|
||||
<text class='iconfont icon-daohang'></text>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
</view>
|
205
components/shortcut/shortcut.wxss
Normal file
@ -0,0 +1,205 @@
|
||||
@import "/utils/common.wxss";
|
||||
|
||||
/* 快捷导航 */
|
||||
|
||||
.shortcut {
|
||||
position: fixed;
|
||||
right: 12px;
|
||||
bottom: 250rpx;
|
||||
width: 76rpx;
|
||||
line-height: 1;
|
||||
z-index: 5;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* 导航菜单元素 */
|
||||
|
||||
.nav-item {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
padding: 0;
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50%;
|
||||
text-align: center;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.nav-item text {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
/* 导航开关 */
|
||||
|
||||
.nav-item__switch {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.shortcut_click_show {
|
||||
margin-bottom: 0;
|
||||
background: #ff5454;
|
||||
}
|
||||
|
||||
/* 显示动画 */
|
||||
|
||||
.show_80 {
|
||||
bottom: 384rpx;
|
||||
animation: show_80 0.3s forwards;
|
||||
}
|
||||
|
||||
.show_60 {
|
||||
bottom: 288rpx;
|
||||
animation: show_60 0.3s forwards;
|
||||
}
|
||||
|
||||
.show_40 {
|
||||
bottom: 192rpx;
|
||||
animation: show_40 0.3s forwards;
|
||||
}
|
||||
|
||||
.show_20 {
|
||||
bottom: 96rpx;
|
||||
animation: show_20 0.3s forwards;
|
||||
}
|
||||
|
||||
@keyframes show_20 {
|
||||
from {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 96rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show_40 {
|
||||
from {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 192rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show_60 {
|
||||
from {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 288rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes show_80 {
|
||||
from {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 384rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 隐藏动画 */
|
||||
|
||||
.hide_80 {
|
||||
bottom: 0;
|
||||
animation: hide_80 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hide_60 {
|
||||
bottom: 0;
|
||||
animation: hide_60 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hide_40 {
|
||||
bottom: 0;
|
||||
animation: hide_40 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.hide_20 {
|
||||
bottom: 0;
|
||||
animation: hide_20 0.3s;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
@keyframes hide_20 {
|
||||
from {
|
||||
bottom: 96rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hide_40 {
|
||||
from {
|
||||
bottom: 192rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hide_60 {
|
||||
from {
|
||||
bottom: 288rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes hide_80 {
|
||||
from {
|
||||
bottom: 384rpx;
|
||||
transform: rotate(360deg);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
bottom: 0;
|
||||
transform: rotate(0deg);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
235
ec-canvas/ec-canvas.js
Normal file
@ -0,0 +1,235 @@
|
||||
import WxCanvas from './wx-canvas';
|
||||
import * as echarts from './echarts';
|
||||
|
||||
let ctx;
|
||||
|
||||
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])
|
||||
const num2 = parseInt(v2[i])
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
Component({
|
||||
properties: {
|
||||
canvasId: {
|
||||
type: String,
|
||||
value: 'ec-canvas'
|
||||
},
|
||||
|
||||
ec: {
|
||||
type: Object
|
||||
},
|
||||
|
||||
forceUseOldCanvas: {
|
||||
type: Boolean,
|
||||
value: false
|
||||
}
|
||||
},
|
||||
|
||||
data: {
|
||||
isUseNewCanvas: false
|
||||
},
|
||||
|
||||
ready: function () {
|
||||
if (!this.data.ec) {
|
||||
console.warn('组件需绑定 ec 变量,例:<ec-canvas id="mychart-dom-bar" '
|
||||
+ 'canvas-id="mychart-bar" ec="{{ ec }}"></ec-canvas>');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.data.ec.lazyLoad) {
|
||||
this.init();
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
init: function (callback) {
|
||||
const version = wx.getSystemInfoSync().SDKVersion
|
||||
|
||||
const canUseNewCanvas = compareVersion(version, '2.9.0') >= 0;
|
||||
const forceUseOldCanvas = this.data.forceUseOldCanvas;
|
||||
const isUseNewCanvas = canUseNewCanvas && !forceUseOldCanvas;
|
||||
this.setData({ isUseNewCanvas });
|
||||
|
||||
if (forceUseOldCanvas && canUseNewCanvas) {
|
||||
console.warn('开发者强制使用旧canvas,建议关闭');
|
||||
}
|
||||
|
||||
if (isUseNewCanvas) {
|
||||
// console.log('微信基础库版本大于2.9.0,开始使用<canvas type="2d"/>');
|
||||
// 2.9.0 可以使用 <canvas type="2d"></canvas>
|
||||
this.initByNewWay(callback);
|
||||
} else {
|
||||
const isValid = compareVersion(version, '1.9.91') >= 0
|
||||
if (!isValid) {
|
||||
console.error('微信基础库版本过低,需大于等于 1.9.91。'
|
||||
+ '参见:https://github.com/ecomfe/echarts-for-weixin'
|
||||
+ '#%E5%BE%AE%E4%BF%A1%E7%89%88%E6%9C%AC%E8%A6%81%E6%B1%82');
|
||||
return;
|
||||
} else {
|
||||
console.warn('建议将微信基础库调整大于等于2.9.0版本。升级后绘图将有更好性能');
|
||||
this.initByOldWay(callback);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
initByOldWay(callback) {
|
||||
// 1.9.91 <= version < 2.9.0:原来的方式初始化
|
||||
ctx = wx.createCanvasContext(this.data.canvasId, this);
|
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, false);
|
||||
|
||||
echarts.setCanvasCreator(() => {
|
||||
return canvas;
|
||||
});
|
||||
// const canvasDpr = wx.getSystemInfoSync().pixelRatio // 微信旧的canvas不能传入dpr
|
||||
const canvasDpr = 1
|
||||
var query = wx.createSelectorQuery().in(this);
|
||||
query.select('.ec-canvas').boundingClientRect(res => {
|
||||
if (typeof callback === 'function') {
|
||||
this.chart = callback(canvas, res.width, res.height, canvasDpr);
|
||||
}
|
||||
else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
|
||||
this.chart = this.data.ec.onInit(canvas, res.width, res.height, canvasDpr);
|
||||
}
|
||||
else {
|
||||
this.triggerEvent('init', {
|
||||
canvas: canvas,
|
||||
width: res.width,
|
||||
height: res.height,
|
||||
canvasDpr: canvasDpr // 增加了dpr,可方便外面echarts.init
|
||||
});
|
||||
}
|
||||
}).exec();
|
||||
},
|
||||
|
||||
initByNewWay(callback) {
|
||||
// version >= 2.9.0:使用新的方式初始化
|
||||
const query = wx.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.ec-canvas')
|
||||
.fields({ node: true, size: true })
|
||||
.exec(res => {
|
||||
const canvasNode = res[0].node
|
||||
this.canvasNode = canvasNode
|
||||
|
||||
const canvasDpr = wx.getSystemInfoSync().pixelRatio
|
||||
const canvasWidth = res[0].width
|
||||
const canvasHeight = res[0].height
|
||||
|
||||
const ctx = canvasNode.getContext('2d')
|
||||
|
||||
const canvas = new WxCanvas(ctx, this.data.canvasId, true, canvasNode)
|
||||
echarts.setCanvasCreator(() => {
|
||||
return canvas
|
||||
})
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
this.chart = callback(canvas, canvasWidth, canvasHeight, canvasDpr)
|
||||
} else if (this.data.ec && typeof this.data.ec.onInit === 'function') {
|
||||
this.chart = this.data.ec.onInit(canvas, canvasWidth, canvasHeight, canvasDpr)
|
||||
} else {
|
||||
this.triggerEvent('init', {
|
||||
canvas: canvas,
|
||||
width: canvasWidth,
|
||||
height: canvasHeight,
|
||||
dpr: canvasDpr
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
canvasToTempFilePath(opt) {
|
||||
if (this.data.isUseNewCanvas) {
|
||||
// 新版
|
||||
const query = wx.createSelectorQuery().in(this)
|
||||
query
|
||||
.select('.ec-canvas')
|
||||
.fields({ node: true, size: true })
|
||||
.exec(res => {
|
||||
const canvasNode = res[0].node
|
||||
opt.canvas = canvasNode
|
||||
wx.canvasToTempFilePath(opt)
|
||||
})
|
||||
} else {
|
||||
// 旧的
|
||||
if (!opt.canvasId) {
|
||||
opt.canvasId = this.data.canvasId;
|
||||
}
|
||||
ctx.draw(true, () => {
|
||||
wx.canvasToTempFilePath(opt, this);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
touchStart(e) {
|
||||
if (this.chart && e.touches.length > 0) {
|
||||
var touch = e.touches[0];
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mousedown', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y
|
||||
});
|
||||
handler.dispatch('mousemove', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'start');
|
||||
}
|
||||
},
|
||||
|
||||
touchMove(e) {
|
||||
if (this.chart && e.touches.length > 0) {
|
||||
var touch = e.touches[0];
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mousemove', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'change');
|
||||
}
|
||||
},
|
||||
|
||||
touchEnd(e) {
|
||||
if (this.chart) {
|
||||
const touch = e.changedTouches ? e.changedTouches[0] : {};
|
||||
var handler = this.chart.getZr().handler;
|
||||
handler.dispatch('mouseup', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y
|
||||
});
|
||||
handler.dispatch('click', {
|
||||
zrX: touch.x,
|
||||
zrY: touch.y
|
||||
});
|
||||
handler.processGesture(wrapTouch(e), 'end');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function wrapTouch(event) {
|
||||
for (let i = 0; i < event.touches.length; ++i) {
|
||||
const touch = event.touches[i];
|
||||
touch.offsetX = touch.x;
|
||||
touch.offsetY = touch.y;
|
||||
}
|
||||
return event;
|
||||
}
|
4
ec-canvas/ec-canvas.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"component": true,
|
||||
"usingComponents": {}
|
||||
}
|
4
ec-canvas/ec-canvas.wxml
Normal file
@ -0,0 +1,4 @@
|
||||
<!-- 新的:接口对其了H5 -->
|
||||
<canvas wx:if="{{isUseNewCanvas}}" type="2d" class="ec-canvas" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
|
||||
<!-- 旧的 -->
|
||||
<canvas wx:else class="ec-canvas" type="2d" canvas-id="{{ canvasId }}" bindinit="init" bindtouchstart="{{ ec.disableTouch ? '' : 'touchStart' }}" bindtouchmove="{{ ec.disableTouch ? '' : 'touchMove' }}" bindtouchend="{{ ec.disableTouch ? '' : 'touchEnd' }}"></canvas>
|
5
ec-canvas/ec-canvas.wxss
Normal file
@ -0,0 +1,5 @@
|
||||
.ec-canvas {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
z-index:1;
|
||||
}
|
22
ec-canvas/echarts.js
Normal file
121
ec-canvas/wx-canvas.js
Normal file
@ -0,0 +1,121 @@
|
||||
export default class WxCanvas {
|
||||
constructor(ctx, canvasId, isNew, canvasNode) {
|
||||
this.ctx = ctx;
|
||||
this.canvasId = canvasId;
|
||||
this.chart = null;
|
||||
this.isNew = isNew
|
||||
if (isNew) {
|
||||
this.canvasNode = canvasNode;
|
||||
}
|
||||
else {
|
||||
this._initStyle(ctx);
|
||||
}
|
||||
|
||||
// this._initCanvas(zrender, ctx);
|
||||
|
||||
this._initEvent();
|
||||
}
|
||||
|
||||
getContext(contextType) {
|
||||
if (contextType === '2d') {
|
||||
return this.ctx;
|
||||
}
|
||||
}
|
||||
|
||||
// canvasToTempFilePath(opt) {
|
||||
// if (!opt.canvasId) {
|
||||
// opt.canvasId = this.canvasId;
|
||||
// }
|
||||
// return wx.canvasToTempFilePath(opt, this);
|
||||
// }
|
||||
|
||||
setChart(chart) {
|
||||
this.chart = chart;
|
||||
}
|
||||
|
||||
attachEvent() {
|
||||
// noop
|
||||
}
|
||||
|
||||
detachEvent() {
|
||||
// noop
|
||||
}
|
||||
|
||||
_initCanvas(zrender, ctx) {
|
||||
zrender.util.getContext = function () {
|
||||
return ctx;
|
||||
};
|
||||
|
||||
zrender.util.$override('measureText', function (text, font) {
|
||||
ctx.font = font || '12px sans-serif';
|
||||
return ctx.measureText(text);
|
||||
});
|
||||
}
|
||||
|
||||
_initStyle(ctx) {
|
||||
var styles = ['fillStyle', 'strokeStyle', 'globalAlpha',
|
||||
'textAlign', 'textBaseAlign', 'shadow', 'lineWidth',
|
||||
'lineCap', 'lineJoin', 'lineDash', 'miterLimit', 'fontSize'];
|
||||
|
||||
styles.forEach(style => {
|
||||
Object.defineProperty(ctx, style, {
|
||||
set: value => {
|
||||
if (style !== 'fillStyle' && style !== 'strokeStyle'
|
||||
|| value !== 'none' && value !== null
|
||||
) {
|
||||
ctx['set' + style.charAt(0).toUpperCase() + style.slice(1)](value);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ctx.createRadialGradient = () => {
|
||||
return ctx.createCircularGradient(arguments);
|
||||
};
|
||||
}
|
||||
|
||||
_initEvent() {
|
||||
this.event = {};
|
||||
const eventNames = [{
|
||||
wxName: 'touchStart',
|
||||
ecName: 'mousedown'
|
||||
}, {
|
||||
wxName: 'touchMove',
|
||||
ecName: 'mousemove'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'mouseup'
|
||||
}, {
|
||||
wxName: 'touchEnd',
|
||||
ecName: 'click'
|
||||
}];
|
||||
|
||||
eventNames.forEach(name => {
|
||||
this.event[name.wxName] = e => {
|
||||
const touch = e.touches[0];
|
||||
this.chart.getZr().handler.dispatch(name.ecName, {
|
||||
zrX: name.wxName === 'tap' ? touch.clientX : touch.x,
|
||||
zrY: name.wxName === 'tap' ? touch.clientY : touch.y
|
||||
});
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
set width(w) {
|
||||
if (this.canvasNode) this.canvasNode.width = w
|
||||
}
|
||||
set height(h) {
|
||||
if (this.canvasNode) this.canvasNode.height = h
|
||||
}
|
||||
|
||||
get width() {
|
||||
if (this.canvasNode)
|
||||
return this.canvasNode.width
|
||||
return 0
|
||||
}
|
||||
get height() {
|
||||
if (this.canvasNode)
|
||||
return this.canvasNode.height
|
||||
return 0
|
||||
}
|
||||
}
|
BIN
images/0181008111258.png
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
images/1.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
images/17169030f9c6767c9d17a78db1332f1.png
Normal file
After Width: | Height: | Size: 316 B |
BIN
images/2.png
Normal file
After Width: | Height: | Size: 7.0 KiB |
BIN
images/3.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
BIN
images/5-121204193R0-50.gif
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
images/add_to_min_program_arrow.png
Normal file
After Width: | Height: | Size: 427 B |
BIN
images/add_to_min_program_close.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
images/add_to_min_program_more.png
Normal file
After Width: | Height: | Size: 381 B |
BIN
images/avds.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
images/back.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
images/bk.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
images/closeLogin.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
images/default-avatar.jpg
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
images/deng.png
Normal file
After Width: | Height: | Size: 8.6 KiB |
BIN
images/dianzan.png
Normal file
After Width: | Height: | Size: 781 B |
BIN
images/ditu.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
images/fabulous.png
Normal file
After Width: | Height: | Size: 412 B |
BIN
images/fan.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
images/guan.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
BIN
images/guane.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
images/guasn.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
images/guji.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
images/gzh_btn.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
images/handle_calendar.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
images/icon-index-empty.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
images/link_more.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
images/moah.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
images/my_icon.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
images/no_content.png
Normal file
After Width: | Height: | Size: 8.3 KiB |
BIN
images/nofabulous.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
images/qi_on.png
Normal file
After Width: | Height: | Size: 930 B |
BIN
images/ren.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
images/sacsa.png
Normal file
After Width: | Height: | Size: 78 KiB |
BIN
images/saoua.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
images/sign_bg.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
images/snji.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
images/suo.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
images/t1.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
images/t2.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
images/t3.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
images/tabBar/cate.png
Normal file
After Width: | Height: | Size: 366 B |
BIN
images/tabBar/cate_on.png
Normal file
After Width: | Height: | Size: 759 B |
BIN
images/tabBar/home.png
Normal file
After Width: | Height: | Size: 928 B |
BIN
images/tabBar/home_on.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
images/tabBar/user.png
Normal file
After Width: | Height: | Size: 1005 B |
BIN
images/tabBar/user_on.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
images/tc_bg.jpg
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
images/tian.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
images/ty.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
images/user-bg.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
images/userHelp1.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
images/userPer.png
Normal file
After Width: | Height: | Size: 949 B |
BIN
images/userServer.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
images/userXun.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
images/userhelp.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
images/we.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
images/wei.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
images/wen.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
images/white.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
images/xai.png
Normal file
After Width: | Height: | Size: 4.2 KiB |