commit 3db8a7425a0a516a99a97f9497d906495947158a Author: jianglong Date: Thu Apr 27 21:53:49 2023 +0800 初始化 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c7721a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +unpackage +node_modules/ +.hbuilderx/ \ No newline at end of file diff --git a/App.vue b/App.vue new file mode 100644 index 0000000..3141762 --- /dev/null +++ b/App.vue @@ -0,0 +1,94 @@ + + diff --git a/androidPrivacy.json b/androidPrivacy.json new file mode 100644 index 0000000..ae4b97d --- /dev/null +++ b/androidPrivacy.json @@ -0,0 +1,28 @@ +{ + "version" : "1", + "prompt" : "template", + "title" : "用户协议和隐私政策", + "message" : "  请你务必审慎阅读、充分理解“用户协议”和“隐私政策”各条款,包括但不限于:为了更好的向你提供服务,我们需要收集你的设备标识、操作日志等信息用于分析、优化应用性能。
  你可阅读《用户协议》《隐私政策》了解详细信息。如果你同意,请点击下面按钮开始接受我们的服务。", + "buttonAccept" : "同意并接受", + "buttonRefuse" : "暂不同意", + "hrefLoader" : "system|default", + "second" : { + "title" : "确认提示", + "message" : "  进入应用前,你需先同意《用户协议》《隐私政策》,否则将退出应用。", + "buttonAccept" : "同意并继续", + "buttonRefuse" : "退出应用" + }, + "styles" : { + "backgroundColor" : "#ffffff", + "borderRadius" : "5px", + "title" : { + "color" : "#FF2C3C" + }, + "buttonAccept" : { + "color" : "#FF2C3C" + }, + "buttonRefuse" : { + "color" : "#545454" + } + } +} diff --git a/api/activity.js b/api/activity.js new file mode 100644 index 0000000..228e11f --- /dev/null +++ b/api/activity.js @@ -0,0 +1,183 @@ +import request from '@/utils/request' +import {client} from '@/utils/tools' + + +//领券中心 +export function getCouponList(params) { + return request.get("coupon/getCouponList", {params}); +} + +//用户领取优惠券 +export function getCoupon(id) { + return request.post('coupon/getCoupon', {coupon_id:id}) +} + + +// 下单优惠券 +export function getOrderCoupon(data) { + return request.post("coupon/getBuyCouponList", data); +} + + +//我的优惠券 +export function getMyCoupon(params) { + return request.get('coupon/myCouponList', { + params + }) +} + +// 获取活动专区商品列表 +export function getActivityGoodsLists(data) { + return request.get("activity_area/activityGoodsList", {params: data}) +} + + +// 获取秒杀时间段 +export function getSeckillTime() { + return request.get("seckill_goods/getSeckillTime"); +} + +// 获取秒杀商品 +export function getSeckillGoods(params) { + return request.get("seckill_goods/getSeckillGoods", {params}) +} + +// 拼团列表 +export function getGroupList(params) { + return request.get('team/activity', {params}); +} + +//拼团记录 +export function getUserGroup(params) { + return request.get('team/record', {params}); +} + +//拼团详情 +export function getTeamInfo(params) { + return request.get('team/teamInfo', {params}); +} + +//开团|结算 +export function teamKaiTuan(data) { + return request.post('team/kaituan', data); +} + +//参与拼团验证 +export function teamCheck(data) { + return request.post('team/check', data); +} + + //拼团下单 +export function teamBuy(data) { + return request.post("team/buy",data); +} + +// 获取砍价列表 +export function getBargainList(data) { + return request.get('bargain/lists', {params: data}) +} + +// 获取砍价详情 +export function getBargainDetail(data) { + return request.get('bargain/detail', {params: data}) +} + +// 获取砍价成功人数 +export function getBargainNumber() { + return request.get("bargain/barginNumber") +} + +// 发起砍价 +export function launchBargain(data) { + return request.post('bargain/sponsor', data) +} + +// 获取砍价活动商品列表 +export function getBargainActivityList(data) { + return request.get('bargain/orderList', {params: data}) +} + +// 砍价详情 +export function getBargainActivityDetail(data) { + return request.get("bargain/bargainDetail", {params: data}) +} + +// 砍价海报 +export function getBargainPost(data) { + return request.get("share/shareBargain", {params: data}) +} + +// 好友助力 +export function helpBargain(data) { + return request.post('bargain/knife', data) +} + +// 关闭结算订单 +export function closeBargainOrder(data) { + return request.get("bargain/closeBargain", {params: data}) +} + + +// 获取签到列表 +export function getSignLists() { + return request.get("sign/lists") +} + +// 获取签到列表 +export function getSignRule() { + return request.get("sign/rule") +} + +// 签到 +export function userSignIn() { + return request.get("sign/sign") +} + +// 积分商城 +export function getIntegralGoods(params) { + return request.get("integral_goods/lists", { params }) +} + +// 积分商品详情 +export function getIntegralGoodsDetail(params) { + return request.get("integral_goods/detail", { params }) +} + +// 积分兑换订单结算 +export function integralSettlement(params) { + return request.get("integral_order/settlement", { params }) +} + +// 积分兑换提交订单 +export function integralSubmitOrder(params) { + return request.post("integral_order/submitOrder", params) +} + +// 积分兑换订单列表 +export function getIntegralOrder(params) { + return request.get("integral_order/lists", {params}) +} + +//删除积分兑换订单 +export function delIntegralOrder(id) { + return request.post('integral_order/del', {id}) +} + +//积分兑换订单订单详情 +export function getIntegralOrderDetail(id) { + return request.get('integral_order/detail', {params: {id}}) +} + +//取消积分兑换订单 +export function cancelIntegralOrder(id) { + return request.post('integral_order/cancel', {id}) +} + +//确认收货积分兑换订单 +export function confirmIntegralOrder(id) { + return request.post("integral_order/confirm", {id}) +} +// 查看物流 +export function getIntegralOrderTraces(id) { + return request.get("integral_order/orderTraces", {params: {id}}) +} diff --git a/api/app.js b/api/app.js new file mode 100644 index 0000000..3b340ba --- /dev/null +++ b/api/app.js @@ -0,0 +1,139 @@ +import request from '@/utils/request' +import wechath5 from '@/utils/wechath5' +import {client} from '@/utils/tools' + +//小程序授权登录 +export function authLogin(data) { + return request.post('account/authLogin', data); +} +//小程序静默登录 +export function silentLogin(data) { + return request.post('account/silentLogin', data); +} +//更新小程序头像昵称 +export function updateUser(data, token) { + return request.post('account/updateUser', data, {header: {token}}); +} + +// app登录 +export function opLogin(data) { + return request.post('account/uinAppLogin', {...data, client}); +} + +//预支付接口 +export function prepay(data) { + return request.post('pay/unifiedpay', {...data,}); +} + +//小程序订阅 +export function getMnpNotice(data) { + return request.get("subscribe/lists", { + params: data + }); +} + +//账号登录 +export function accountLogin(data) { + return request.post("account/login", {...data, client}) +} + + + +// 登录 +export function wechatLogin(data) { + return request.post('account/oalogin', data) +} + +// 向微信请求code的链接 +export function getCodeUrl() { + return request.get('account/codeurl', { + params:{ + url: encodeURIComponent(location.href) + } + }); +} + + + +//微信sdk配置 +export function getJsconfig() { + return request.get('wechat/jsconfig', { + + params: { + url: encodeURIComponent(wechath5.signLink()) + } + }); +} + +// 忘记密码 +export function forgetPwd(data) { + return request.post('login_password/forget', {...data, client}) +} + +// 发送短信 +export function sendSms(data) { + return request.post('sms/send', {...data, client}) +} + +// Html5 注册账号 +export function register(data) { + return request.post('account/register', {...data, client}) +} + +// 获取服务协议 +export function getServerProto() { + return request.get("policy/service") +} + +// 获取隐私政策 +export function getPrivatePolicy() { + return request.get("policy/privacy") +} + +// 获取售后保障 +export function getAfterSaleGuar() { + return request.get("policy/afterSale") +} + +//客服 +export function getService() { + return request.get("setting/getPlatformCustomerService") +} + + +//客服配置 +export function getChatConfig(params) { + return request.get("index/chatConfig", { params }) +} + + +// 足迹气泡 +export function getBubbleLists() { + return request.get("footprint/lists") +} + + + +// 验证码登录 +export function smsCodeLogin(data) { + return request.post('account/smsLogin', {...data, client}) +} +export function getConfig() { + return request.get("index/config") +} + + +// 注册赠送优惠券 +export function getRegisterCoupon() { + return request.get('coupon/registerSendCoupon') +} + +// 获取支付配置 +export function getPayway(params) { + return request.get('order/getPayWay', { params }) +} + +// 小程序码 +export function apiMnpQrCode(params) { + return request.get('share/getMnQrcode', { params }) +} diff --git a/api/community.js b/api/community.js new file mode 100644 index 0000000..f1b68f0 --- /dev/null +++ b/api/community.js @@ -0,0 +1,131 @@ +import request from '@/utils/request' + +// 关联商品 +export function getCommunityGoods(params) { + return request.get("community/goods", {params}) +} + +// 关联店铺 +export function getCommunityShop(params) { + return request.get("community/shop", {params}) +} + +// 推荐话题 +export function getCommunityRecommendTopic() { + return request.get("community/recommendTopic") +} + +// 话题列表 +export function getCommunityTopicLists(params) { + return request.get("community/topicLists", {params}) +} + +// 发布文章 +export function apiCommunityAdd(params) { + return request.post("community/addArticle", params) +} + +// 编辑文章 +export function apiCommunityEdit(params) { + return request.post("community/editArticle", params) +} + +// 个人中心 +export function getCommunityUserCenter(params) { + return request.get("community_user/center", {params}) +} + +// 分类 +export function getCommunityCate() { + return request.get("community/cate") +} + +// 发现页文章列表 +export function getCommunityArticleLists(params) { + return request.get("community/articleLists", {params}) +} + +// 关注/取消 +export function apiCommunityFollow(params) { + return request.post("community/follow", params) +} + +// 获取设置 +export function getCommunitySetting() { + return request.get("community_user/getSetting") +} + +// 提交设置 +export function apiCommunitySetSetting(params) { + return request.post("community_user/setSetting", params) +} + +// 关注页-数据 +export function getCommunityFollow(params) { + return request.get("community/followArticle", { params }) +} + +// 个人页-作品列表 +export function getCommunityWorksLists(params) { + return request.get("community/worksLists", { params }) +} + +// 个人页-点赞列表 +export function getCommunityLikeLists(params) { + return request.get("community/likeLists", { params }) +} + +// 相关话题 +export function getCommunityTopicArticle(params) { + return request.get("community/topicArticle", { params }) +} + +// 文章详情 +export function getCommunityDetail(params) { + return request.get("community/detail", { params }) +} + +// 文章中的关联商品 +export function getCommunityGoodsLists(params) { + return request.get("community/relationGoods", { params }) +} + +// 文章中的关联店铺 +export function getCommunityShopLists(params) { + return request.get("community/relationShop", { params }) +} + +// 删除文章 +export function apiCommunityDel(params) { + return request.post("community/delArticle", params) +} + +// 添加评论 +export function apiCommunityCommentAdd(params) { + return request.post("community_comment/add", params) +} + +// 文章评论 +export function getCommunityCommentLists(params) { + return request.get("community_comment/lists", { params }) +} + +// 文章子级评论 +export function getCommunityCommentChildLists(params) { + return request.get("community_comment/commentChild", { params }) +} + +// 点赞 | 取消 | 作品点赞 | 评论点赞 +export function apiCommunityCommentLike(params) { + return request.post("community/giveLike", params) +} + +// 搜索记录 +export function getCommunitySearchHistory() { + return request.get("community_search/lists") +} + +// 清空搜索记录 +export function apiCommunityClearSearchHistory() { + return request.post("community_search/clear") +} \ No newline at end of file diff --git a/api/live.js b/api/live.js new file mode 100644 index 0000000..fd21900 --- /dev/null +++ b/api/live.js @@ -0,0 +1,10 @@ +import request from '@/utils/request' + +// 直播间列表 +export function getLiveLists(params) { + return request.get("live/lists", {params}) +} +// 店铺直播间列表 +export function getShopLive(params) { + return request.get("live/shopLive", {params}) +} diff --git a/api/order.js b/api/order.js new file mode 100644 index 0000000..c11ce1f --- /dev/null +++ b/api/order.js @@ -0,0 +1,46 @@ +import request from '@/utils/request' + +import {client} from '@/utils/tools' + +//订单结算页 +export function orderInfo(data) { + return request.post("order/settlement", data); +} +// 下单 +export function orderBuy(data) { + return request.post("order/submitOrder", data); +} +//删除订单 +export function delOrder(id) { + return request.post('order/del', {id}) +} +//订单列表 +export function getOrderList(data) { + return request.get('order/lists', {params: data}) +} +//订单详情 +export function getOrderDetail(id) { + return request.get('order/getOrderDetail', {params: {id}}) +} + +//取消订单 +export function cancelOrder(id) { + return request.post('order/cancel', {id}) +} + +//物流 +export function orderTraces(id) { + return request.get("order/orderTraces", {params: {id}}) +} + +//确认收货 +export function confirmOrder(id) { + return request.post("order/confirm", {id}) +} + + + +// 支付结果 +export function getPayResult(params) { + return request.get("order/pay_result", { params }); +} diff --git a/api/shop.js b/api/shop.js new file mode 100644 index 0000000..f8080b3 --- /dev/null +++ b/api/shop.js @@ -0,0 +1,92 @@ +import request from '@/utils/request' +import {client} from '@/utils/tools' + + + + +//获取店铺列表 +export function getShopList(params) { + return request.get('shop/getShopList', {params}) +} + +//获取附近店铺列表 +export function getNearbyShops(params) { + return request.get('shop/getNearbyShops', {params}) +} + + +//获取主营类目列表 +export function getShopCategory() { + return request.get('shop_category/getList') +} + + +//获取店铺信息 +export function getShopInfo(params) { + return request.get('shop/getShopInfo', {params}) +} + + +//获取店铺商品分类 + +export function getShopGoodsCategory(params) { + return request.get('shop_goods_category/getShopGoodsCategory', {params}) +} + +//店铺关注/取消关注 +export function changeShopFollow(data) { + return request.post('shop_follow/changeStatus', data) +} + + +// 商家入驻 +export function shopApply(data) { + return request.post('ShopApply/apply', data) +} + + +// 申请记录 +export function shopApplyRecord(params) { + return request.get('ShopApply/record', {params}) +} + +// 申请记录详情 +export function shopApplyDetail(id) { + return request.get('ShopApply/detail', {params:{id}}) +} + + +// 入住协议 +export function getTreaty() { + return request.get('ShopApply/getTreaty') +} + +//客服 +export function getShopService(id) { + return request.get("setting/getShopCustomerService", {params:{shop_id: id}}) +} + +// 商家发票设置 +export function getInvoiceSetting(params) { + return request.get("order_invoice/setting", { params }) +} + +// 发票提交 +export function apiInvoiceAdd(params) { + return request.post("order_invoice/add", params) +} + +// 发票编辑 +export function apiInvoiceEdit(params) { + return request.post("order_invoice/edit", params) +} + +// 发票详情 +export function apiInvoiceDetail(params) { + return request.get("order_invoice/detail", { params }) +} + +// 订单发票详情 +export function apiOrderInvoiceDetail(params) { + return request.get("order/invoice", { params }) +} \ No newline at end of file diff --git a/api/store.js b/api/store.js new file mode 100644 index 0000000..39378dc --- /dev/null +++ b/api/store.js @@ -0,0 +1,223 @@ +import request from '@/utils/request' +import {client} from '@/utils/tools' + + + + +//获取首页数据接口 +export function getHome(params) { + return request.get('index/index', { params }) +} + +// 通过首页分类id获取数据 +export function getIndexCategory(params) { + return request.get('index/indexCategory', {params}) +} +//获取菜单 +export function getMenu(data) { + return request.get('menu/lists', { + params: data, + }); +} + +//商品栏目 +export function getGoodsColumn() { + return request.get('goods_column/getGoodsColumnList'); +} + +//栏目商品 +export function getGoodsListColumn(params) { + return request.get('goods/getGoodsListByColumnId', {params}); +} + +//平台一级分类 +export function getLevelOneList() { + return request.get('goods_category/getLevelOneList'); +} + +// 一级分类的后代分类 +export function getListByLevelOne(params) { + return request.get('goods_category/getListByLevelOne', {params}); +} + + +//品牌列表 +export function getBrandList() { + return request.get('goods_brand/getGoodsBrandList'); +} + +//文章分类 +export function getCategoryList(data) { + let {type} = data + let url = type ? 'help/category' : 'article/category' + delete data.type + return request.get(url) +} + +//文章列表 +export function getArticleList(data) { + let {type} = data + let url = type ? 'help/lists' : 'article/lists' + delete data.type + return request.get(url, { + params: data + }) +} + +// 文章详情 +export function getArticleDetail(data) { + let {type} = data + let url = type ? 'help/detail' : 'article/detail' + delete data.type + return request.get(url, { + params: { id: data.id } + }) +} + +//购物车 +export function getCartList() { + return request.get('cart/lists') +} + +//商品详情 +export function getGoodsDetail(data) { + return request.get('goods/getGoodsDetail', { + params: data + }); +} + + +//加入购物车 + +export function addCart(data) { + return request.post('cart/add', data); +} + + //购物车数量 + +export function getCartNum(params) { + return request.get("cart/num", {params}); +} + + +// 购物车数量更改 +export function changeGoodsCount(data) { + return request.post("cart/change", data) +} + +// 单选/全选/店铺选择 +export function selectedOpt(data) { + return request.post("cart/selected", data) +} + +// 删除商品 +export function deleteGoods(data) { + return request.post("cart/del", data); +} + +//购物车选中状态 +export function changeCartSelect(data) { + return request.post('cart/selected', data) +} + +//广告位 +export function getAdList(data) { + return request.get('ad_content/lists', { + params: data + }); +} + + +// 商品分类 +export function getCatrgory() { + return request.get('goods_category/lists'); +} + + +// 商品搜索 + +export function getGoodsList(data) { + return request.get('goods/getGoodsList', { + params: data + }); +} + +//评价列表 +export function getCommentList(data) { + return request.get("goods_comment/lists", { + params: data + }) +} + +//评价分类 +export function getCommentCategory(id) { + return request.get("goods_comment/category", { + params: { + goods_id: id + } + }) +} + +//搜索页,热门搜索列表,和历史搜索列表 +export function getSearchpage() { + return request.get('search_record/lists'); +} + +// 清空历史搜索 +export function clearSearch() { + return request.post('search_record/clear'); +} + + + + +//商品海报 + +export function getPoster(data) { + return request.get("share/sharegoods", { + params: data + }); +} + +// 消息中心首页 +export function getMessageLists() { + return request.get("notice/index") +} + +// 消息通知 +export function getNoticeLists(params) { + return request.get("notice/lists", {params}) +} + +// 城市列表 +export function getCityLists() { + return request.get("index/city") +} + +// 逆解析定位地址 +export function getGeocoder(params) { + return request.get("index/geocoder", {params}) +} + + +//资料分类 +export function getResourceCategoryList() { + let url = 'resource/category' + return request.get(url) +} + +//资料列表 +export function getResourceList(data) { + let url = 'resource/lists' + return request.get(url, { + params: data + }) +} + +// 资料详情 +export function getResourceDetail(data) { + let url = 'resource/detail' + return request.get(url, { + params: { id: data.id } + }) +} diff --git a/api/user.js b/api/user.js new file mode 100644 index 0000000..8502491 --- /dev/null +++ b/api/user.js @@ -0,0 +1,332 @@ +import request from '../utils/request' +import {client} from '@/utils/tools' +//个人中心 +export function getUser() { + return request.get('user/center') +} + + +// 地址列表 +export function getAddressLists() { + return request.get('user_address/lists') +} +// 商品的增添取消收藏 +export function collectGoods(data) { + return request.post('goods_collect/changeStatus', data) +} + +// 添加编辑地址 +export function editAddress(data) { + return request.post('user_address/update', data) +} + +export function addAddress(data) { + return request.post('user_address/add', data) +} + +// 删除地址 +export function delAddress(id) { + return request.post('user_address/del', {id}) +} + +// 获取单个地址 +export function getOneAddress(id) { + return request.get('user_address/detail', {params: {id}}) +} + +// 获取默认地址 +export function getDefaultAddress(id) { + return request.get('user_address/getDefault', {params: {id}}) +} + +// 设置默认地址 +export function setDefaultAddress(id) { + return request.post('user_address/setDefault', {id}) +} + +//传省市区字符串判读是否有code +export function hasRegionCode(data) { + return request.post('user_address/handleRegion', data) +} + +// 获取评价信息 +export function getCommentInfo(params) { + return request.get("goods_comment/getCommentPage", {params}); +} + +// 未评价列表 +export function getUnComment(params) { + return request.get("goods_comment/getUnCommentOrder", {params}); +} + +// 校验商品 +export function apiCheckGoods(params) { + return request.get("goods_comment/checkGoods", {params}); +} + +// 已评价列表 +export function getComment(params) { + return request.get("goods_comment/getCommentOrder", {params}); +} + + +//商品评价 +export function goodsComment(data) { + return request.post("goods_comment/addGoodsComment", data) +} + +// 获取抽奖配置 +export function getPrize(data) { + return request.get("Luckdraw/prize", data) +} + +// 抽奖记录 +export function getUserRecord(data) { + return request.get("Luckdraw/record", data) +} + +// 获取个人详情 +export function getUserInfo() { + return request.get('user/info') +} + +// 获取资质信息 +export function getCopyright(data) { + return request.get('index/copyright', {data}) +} + +// 设置个人信息 +export function setUserInfo(data) { + return request.post('user/setInfo', data) +} + +// 获取手机号 +export function getWxMnpMobile(data) { + return request.post('user/getMobile',data); +} + + +//更新微信信息 + +export function setWechatInfo(data) { + return request.post('user/setWechatInfo', data) +} + + +// 更换手机号 +export function changeUserMobile(data) { + return request.post("user/changeMobile", {...data, client}) +} +//会员中心 +export function getLevelList() { + return request.get('user/getUserLevelInfo'); +} + +// 用户钱包 +export function getWallet() { + return request.get("user/myWallet") +} +// 账户流水 + +export function getAccountLog(params) { + return request.get("user/accountLog", {params}) +} + +// 充值模板 +export function rechargeTemplate() { + return request.get("recharge/rechargeTemplate"); +} + +//充值 +export function recharge(data) { + return request.post("recharge/recharge", data) +} + +//充值记录 +export function getRechargeRecord(params) { + return request.post("recharge/rechargeRecord", {params}) +} + + +// 填写邀请码(绑定上级) +export function bindSuperior(data) { + return request.post("distribution/code", data) +} + +// 分销会员申请 +export function applyDistribute(data) { + return request.post("distribution/apply", data) +} + +// 分销入口验证 +export function veryfiyDistribute() { + return request.post('distribution/check') +} + +// 最新分销会员申请详情 +export function applyDetail() { + return request.post("distribution/applydetail") +} + +// 邀请人信息 +export function getSuperiorInfo() { + return request.get("distribution/myLeader") +} +// 分销主页 +export function getDistribution() { + return request.get("distribution/index") +} + +// 分销订单列表 +export function getDistributionOrder(params) { + return request.get("distribution/order", {params}) +} +// 我的粉丝 +export function getUserFans(data) { + return request.get("user/fans", {params: data}) +} + +// 佣金明细 +export function getCommission(params) { + return request.get("distribution/commission", {params}) +} + +// 月度账单 +export function getMonthBill(params) { + return request.get("distribution/monthbill", {params}) +} + + +// 月度账单明细 +export function getMonthOrderDetail(params) { + return request.get("distribution/monthDetail", {params}) +} + + +// 获取商品的收藏列表 +export function getCollectGoods(params) { + return request.get('goods_collect/lists', {params}) +} + +// 获取店铺的收藏列表 +export function getCollectShop(params) { + return request.get('shop_follow/lists', {params}) +} + + + +// 获取售后列表 +export function getAfterSaleList(params) { + return request.get("after_sale/lists", {params}); +} + +// 申请售后 +export function applyAfterSale(data) { + return request.post("after_sale/add", data) +} + +// 获取商品信息 +export function getGoodsInfo(params) { + return request.get("after_sale/goodsInfo", {params}) +} + +// 填写快递信息 +export function inputExpressInfo(data) { + return request.post("after_sale/express", data) +} + +// 撤销申请 +export function cancelApply(data) { + return request.post("after_sale/cancel", data) +} + +// 售后详情 +export function afterSaleDetail(params) { + return request.get("after_sale/detail", {params}) +} + +// 重新申请 +export function applyAgain(data) { + return request.post("after_sale/again", data) +} + +// 佣金提现 +export function applyWithdraw(data) { + return request.post("withdraw/apply", data); +} + +// 提现记录列表 +export function getWithdrawRecords(params) { + return request.get("withdraw/records", {params}) +} + +// 提现详情 +export function getWithdrawDetail(params) { + return request.get("withdraw/info", {params}) +} + +// 提现页信息 +export function getWithdrawConfig() { + return request.get("withdraw/config") +} + + +// 邀请海报 +export function getUserPoster(data) { + return request.get("share/userPoster", {params: data}) +} + +// 退出登录 +export function userLogout(data) { + return request.post('account/logout', data) +} + + +// 海报背景 +export function apiDistributionPoster(data) { + return request.get("distribution/getPoster", {params: data}) +} + +// 聊天记录 +export function chatRecord(data) { + return request.get('user/chatRecord', {params: data}) +} + + +// 用户vip +export function getUserShip(data) { + return request.get('user/userShip', {params: data}) +} + +// 用户vip +export function getUserRight(data) { + return request.get('user/userRight', {params: data}) +} + +// 用户vip时间 +export function getUserVipTime(data) { + return request.get('user/userVipTime', {params: data}) +} + +//获取投诉类型列表 +export function getComplainCategory() { + return request.get('user/getComplainCategoryList') +} + + +// 投诉驻 +export function complain(data) { + return request.post('user/complain', data) +} + + +// 投诉记录 +export function complainRecord(params) { + return request.get('user/complainRecord', {params}) +} + +// 投诉记录详情 +export function complainDetail(id) { + return request.get('user/complainDetail', {params:{id}}) +} + diff --git a/apple-app-site-association b/apple-app-site-association new file mode 100644 index 0000000..3054b71 --- /dev/null +++ b/apple-app-site-association @@ -0,0 +1,11 @@ +{ + "applinks": { + "apps": [], + "details": [ + { + "appID": "8656MXP6VT.com.gzyx.likemall", + "paths": [ "/ulink/*"] + } + ] + } +} \ No newline at end of file diff --git a/autoRelease.sh b/autoRelease.sh new file mode 100644 index 0000000..fc184a7 --- /dev/null +++ b/autoRelease.sh @@ -0,0 +1,17 @@ +#!/bin/bash +# 文件原路径 +srcPath="./unpackage/dist/build/h5" +# 发布路径文件夹 +releasePath="../server/public/mobile" + +#删除发布目录下的mobile文件 +rm -r $releasePath +echo "已删除 ==> $releasePath 下的目录文件" +mkdir $releasePath +echo "已新建 ==> $releasePath 目录" + +# 复制打包目录内的文件到发布目录 +cp -r $srcPath/* $releasePath +echo "已复制 $srcPath/* ==> $releasePath" + +cp $releasePath/../favicon.ico $releasePath \ No newline at end of file diff --git a/bundle/pages/activity_detail/activity_detail.vue b/bundle/pages/activity_detail/activity_detail.vue new file mode 100644 index 0000000..fd48ca2 --- /dev/null +++ b/bundle/pages/activity_detail/activity_detail.vue @@ -0,0 +1,118 @@ + + + + + + diff --git a/bundle/pages/address_edit/address_edit.vue b/bundle/pages/address_edit/address_edit.vue new file mode 100644 index 0000000..d2540d7 --- /dev/null +++ b/bundle/pages/address_edit/address_edit.vue @@ -0,0 +1,209 @@ + + + + diff --git a/bundle/pages/after_sales/after_sales.vue b/bundle/pages/after_sales/after_sales.vue new file mode 100644 index 0000000..304f062 --- /dev/null +++ b/bundle/pages/after_sales/after_sales.vue @@ -0,0 +1,43 @@ + + + + \ No newline at end of file diff --git a/bundle/pages/after_sales_detail/after_sales_detail.vue b/bundle/pages/after_sales_detail/after_sales_detail.vue new file mode 100644 index 0000000..b998cc2 --- /dev/null +++ b/bundle/pages/after_sales_detail/after_sales_detail.vue @@ -0,0 +1,235 @@ + + + + diff --git a/bundle/pages/all_comments/all_comments.vue b/bundle/pages/all_comments/all_comments.vue new file mode 100644 index 0000000..3d0f7ee --- /dev/null +++ b/bundle/pages/all_comments/all_comments.vue @@ -0,0 +1,200 @@ + + + + diff --git a/bundle/pages/apply_refund/apply_refund.vue b/bundle/pages/apply_refund/apply_refund.vue new file mode 100644 index 0000000..9d26511 --- /dev/null +++ b/bundle/pages/apply_refund/apply_refund.vue @@ -0,0 +1,260 @@ + + + + diff --git a/bundle/pages/bargain/bargain.vue b/bundle/pages/bargain/bargain.vue new file mode 100644 index 0000000..a181a13 --- /dev/null +++ b/bundle/pages/bargain/bargain.vue @@ -0,0 +1,161 @@ + + + + + diff --git a/bundle/pages/bargain_code/bargain_code.vue b/bundle/pages/bargain_code/bargain_code.vue new file mode 100644 index 0000000..937ba7e --- /dev/null +++ b/bundle/pages/bargain_code/bargain_code.vue @@ -0,0 +1,77 @@ + + + \ No newline at end of file diff --git a/bundle/pages/bargain_process/bargain_process.vue b/bundle/pages/bargain_process/bargain_process.vue new file mode 100644 index 0000000..4a1b1aa --- /dev/null +++ b/bundle/pages/bargain_process/bargain_process.vue @@ -0,0 +1,734 @@ + + + + + \ No newline at end of file diff --git a/bundle/pages/chat/chat.vue b/bundle/pages/chat/chat.vue new file mode 100644 index 0000000..181a283 --- /dev/null +++ b/bundle/pages/chat/chat.vue @@ -0,0 +1,637 @@ + + + + + diff --git a/bundle/pages/commission_details/commission_details.vue b/bundle/pages/commission_details/commission_details.vue new file mode 100644 index 0000000..69ec3ae --- /dev/null +++ b/bundle/pages/commission_details/commission_details.vue @@ -0,0 +1,63 @@ + + + + + + + \ No newline at end of file diff --git a/bundle/pages/contact_offical/contact_offical.vue b/bundle/pages/contact_offical/contact_offical.vue new file mode 100644 index 0000000..e10b7a1 --- /dev/null +++ b/bundle/pages/contact_offical/contact_offical.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/bundle/pages/exchange_order/exchange_order.vue b/bundle/pages/exchange_order/exchange_order.vue new file mode 100644 index 0000000..353e899 --- /dev/null +++ b/bundle/pages/exchange_order/exchange_order.vue @@ -0,0 +1,61 @@ + + + + diff --git a/bundle/pages/exchange_order_details/exchange_order_details.vue b/bundle/pages/exchange_order_details/exchange_order_details.vue new file mode 100644 index 0000000..19782d5 --- /dev/null +++ b/bundle/pages/exchange_order_details/exchange_order_details.vue @@ -0,0 +1,369 @@ + + + + diff --git a/bundle/pages/goods_combination/goods_combination.vue b/bundle/pages/goods_combination/goods_combination.vue new file mode 100644 index 0000000..4d6e547 --- /dev/null +++ b/bundle/pages/goods_combination/goods_combination.vue @@ -0,0 +1,174 @@ +// +---------------------------------------------------------------------- +// | LikeShop100%开源免费商用电商系统 +// +---------------------------------------------------------------------- +// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力 +// | 开源版本可自由商用,可去除界面版权logo +// | 商业版本务必购买商业授权,以免引起法律纠纷 +// | 禁止对系统程序代码以任何目的,任何形式的再发布 +// | Gitee下载:https://gitee.com/likeshop_gitee/likeshop +// | 访问官网:https://www.likemarket.net +// | 访问社区:https://home.likemarket.net +// | 访问手册:http://doc.likemarket.net +// | 微信公众号:好象科技 +// | 好象科技开发团队 版权所有 拥有最终解释权 +// +---------------------------------------------------------------------- +// | Author: LikeShopTeam +// +---------------------------------------------------------------------- + + + + + diff --git a/bundle/pages/goods_logistics/goods_logistics.vue b/bundle/pages/goods_logistics/goods_logistics.vue new file mode 100644 index 0000000..ef8a939 --- /dev/null +++ b/bundle/pages/goods_logistics/goods_logistics.vue @@ -0,0 +1,240 @@ + + + + + + + \ No newline at end of file diff --git a/bundle/pages/goods_reviews/goods_reviews.vue b/bundle/pages/goods_reviews/goods_reviews.vue new file mode 100644 index 0000000..e57b2a9 --- /dev/null +++ b/bundle/pages/goods_reviews/goods_reviews.vue @@ -0,0 +1,193 @@ + + + + diff --git a/bundle/pages/goods_seckill/goods_seckill.vue b/bundle/pages/goods_seckill/goods_seckill.vue new file mode 100644 index 0000000..d7c7f27 --- /dev/null +++ b/bundle/pages/goods_seckill/goods_seckill.vue @@ -0,0 +1,219 @@ + + + + diff --git a/bundle/pages/input_express_info/input_express_info.vue b/bundle/pages/input_express_info/input_express_info.vue new file mode 100644 index 0000000..32be79e --- /dev/null +++ b/bundle/pages/input_express_info/input_express_info.vue @@ -0,0 +1,128 @@ + + + + diff --git a/bundle/pages/integral_details/integral_details.vue b/bundle/pages/integral_details/integral_details.vue new file mode 100644 index 0000000..30d723f --- /dev/null +++ b/bundle/pages/integral_details/integral_details.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/bundle/pages/integral_goods_details/integral_goods_details.vue b/bundle/pages/integral_goods_details/integral_goods_details.vue new file mode 100644 index 0000000..b8fe282 --- /dev/null +++ b/bundle/pages/integral_goods_details/integral_goods_details.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/bundle/pages/integral_mall/integral_mall.vue b/bundle/pages/integral_mall/integral_mall.vue new file mode 100644 index 0000000..0ba348f --- /dev/null +++ b/bundle/pages/integral_mall/integral_mall.vue @@ -0,0 +1,265 @@ + + + + + diff --git a/bundle/pages/integral_settlement/integral_settlement.vue b/bundle/pages/integral_settlement/integral_settlement.vue new file mode 100644 index 0000000..cd286ae --- /dev/null +++ b/bundle/pages/integral_settlement/integral_settlement.vue @@ -0,0 +1,266 @@ + + + + + diff --git a/bundle/pages/integral_sign/integral_sign.vue b/bundle/pages/integral_sign/integral_sign.vue new file mode 100644 index 0000000..3e36639 --- /dev/null +++ b/bundle/pages/integral_sign/integral_sign.vue @@ -0,0 +1,357 @@ + + + + diff --git a/bundle/pages/invite_fans/invite_fans.vue b/bundle/pages/invite_fans/invite_fans.vue new file mode 100644 index 0000000..beeb174 --- /dev/null +++ b/bundle/pages/invite_fans/invite_fans.vue @@ -0,0 +1,160 @@ + + + + diff --git a/bundle/pages/invoice/invoice.vue b/bundle/pages/invoice/invoice.vue new file mode 100644 index 0000000..71d9eef --- /dev/null +++ b/bundle/pages/invoice/invoice.vue @@ -0,0 +1,379 @@ + + + + + diff --git a/bundle/pages/invoice_detail/invoice_detail.vue b/bundle/pages/invoice_detail/invoice_detail.vue new file mode 100644 index 0000000..9101367 --- /dev/null +++ b/bundle/pages/invoice_detail/invoice_detail.vue @@ -0,0 +1,212 @@ + + + + + diff --git a/bundle/pages/license/license.vue b/bundle/pages/license/license.vue new file mode 100644 index 0000000..4a48765 --- /dev/null +++ b/bundle/pages/license/license.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/bundle/pages/monthly_bill/monthly_bill.vue b/bundle/pages/monthly_bill/monthly_bill.vue new file mode 100644 index 0000000..f646a25 --- /dev/null +++ b/bundle/pages/monthly_bill/monthly_bill.vue @@ -0,0 +1,102 @@ + + + + diff --git a/bundle/pages/monthly_bill_detail/monthly_bill_detail.vue b/bundle/pages/monthly_bill_detail/monthly_bill_detail.vue new file mode 100644 index 0000000..ab1dcd3 --- /dev/null +++ b/bundle/pages/monthly_bill_detail/monthly_bill_detail.vue @@ -0,0 +1,156 @@ + + + + diff --git a/bundle/pages/order_details/order_details.vue b/bundle/pages/order_details/order_details.vue new file mode 100644 index 0000000..61b678a --- /dev/null +++ b/bundle/pages/order_details/order_details.vue @@ -0,0 +1,553 @@ + + + + diff --git a/bundle/pages/recharge_record/recharge_record.vue b/bundle/pages/recharge_record/recharge_record.vue new file mode 100644 index 0000000..ca6e92e --- /dev/null +++ b/bundle/pages/recharge_record/recharge_record.vue @@ -0,0 +1,63 @@ + + + + + + + \ No newline at end of file diff --git a/bundle/pages/server_explan/server_explan.vue b/bundle/pages/server_explan/server_explan.vue new file mode 100644 index 0000000..74c785d --- /dev/null +++ b/bundle/pages/server_explan/server_explan.vue @@ -0,0 +1,72 @@ + + + + diff --git a/bundle/pages/settled_recode/settled_recode.vue b/bundle/pages/settled_recode/settled_recode.vue new file mode 100644 index 0000000..94a75d4 --- /dev/null +++ b/bundle/pages/settled_recode/settled_recode.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/bundle/pages/settled_result/settled_result.vue b/bundle/pages/settled_result/settled_result.vue new file mode 100644 index 0000000..da7daf7 --- /dev/null +++ b/bundle/pages/settled_result/settled_result.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/bundle/pages/sign_rule/sign_rule.vue b/bundle/pages/sign_rule/sign_rule.vue new file mode 100644 index 0000000..142113f --- /dev/null +++ b/bundle/pages/sign_rule/sign_rule.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/bundle/pages/store_settled/store_settled.vue b/bundle/pages/store_settled/store_settled.vue new file mode 100644 index 0000000..7f3c197 --- /dev/null +++ b/bundle/pages/store_settled/store_settled.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/bundle/pages/user_address/user_address.vue b/bundle/pages/user_address/user_address.vue new file mode 100644 index 0000000..ee2b8f4 --- /dev/null +++ b/bundle/pages/user_address/user_address.vue @@ -0,0 +1,250 @@ + + + + \ No newline at end of file diff --git a/bundle/pages/user_bill/user_bill.vue b/bundle/pages/user_bill/user_bill.vue new file mode 100644 index 0000000..971f896 --- /dev/null +++ b/bundle/pages/user_bill/user_bill.vue @@ -0,0 +1,85 @@ + + + + + + + diff --git a/bundle/pages/user_collection/user_collection.vue b/bundle/pages/user_collection/user_collection.vue new file mode 100644 index 0000000..a84e01e --- /dev/null +++ b/bundle/pages/user_collection/user_collection.vue @@ -0,0 +1,51 @@ + + + + diff --git a/bundle/pages/user_comment/user_comment.vue b/bundle/pages/user_comment/user_comment.vue new file mode 100644 index 0000000..2438225 --- /dev/null +++ b/bundle/pages/user_comment/user_comment.vue @@ -0,0 +1,35 @@ + + + + diff --git a/bundle/pages/user_coupon/user_coupon.vue b/bundle/pages/user_coupon/user_coupon.vue new file mode 100644 index 0000000..9a5493d --- /dev/null +++ b/bundle/pages/user_coupon/user_coupon.vue @@ -0,0 +1,41 @@ + + + + \ No newline at end of file diff --git a/bundle/pages/user_fans/user_fans.vue b/bundle/pages/user_fans/user_fans.vue new file mode 100644 index 0000000..62b926b --- /dev/null +++ b/bundle/pages/user_fans/user_fans.vue @@ -0,0 +1,253 @@ + + + + diff --git a/bundle/pages/user_group/user_group.vue b/bundle/pages/user_group/user_group.vue new file mode 100644 index 0000000..e91f381 --- /dev/null +++ b/bundle/pages/user_group/user_group.vue @@ -0,0 +1,59 @@ + + + + diff --git a/bundle/pages/user_growth/user_growth.vue b/bundle/pages/user_growth/user_growth.vue new file mode 100644 index 0000000..7fba529 --- /dev/null +++ b/bundle/pages/user_growth/user_growth.vue @@ -0,0 +1,64 @@ + + + + + + + \ No newline at end of file diff --git a/bundle/pages/user_order/user_order.vue b/bundle/pages/user_order/user_order.vue new file mode 100644 index 0000000..d06602e --- /dev/null +++ b/bundle/pages/user_order/user_order.vue @@ -0,0 +1,58 @@ + + + + + \ No newline at end of file diff --git a/bundle/pages/user_payment/user_payment.vue b/bundle/pages/user_payment/user_payment.vue new file mode 100644 index 0000000..cc6b509 --- /dev/null +++ b/bundle/pages/user_payment/user_payment.vue @@ -0,0 +1,336 @@ + + + + diff --git a/bundle/pages/user_profile/user_profile.vue b/bundle/pages/user_profile/user_profile.vue new file mode 100644 index 0000000..c6a44fd --- /dev/null +++ b/bundle/pages/user_profile/user_profile.vue @@ -0,0 +1,612 @@ + + + + + diff --git a/bundle/pages/user_spread/user_spread.vue b/bundle/pages/user_spread/user_spread.vue new file mode 100644 index 0000000..7710717 --- /dev/null +++ b/bundle/pages/user_spread/user_spread.vue @@ -0,0 +1,690 @@ + + + + diff --git a/bundle/pages/user_spread_order/user_spread_order.vue b/bundle/pages/user_spread_order/user_spread_order.vue new file mode 100644 index 0000000..d851a72 --- /dev/null +++ b/bundle/pages/user_spread_order/user_spread_order.vue @@ -0,0 +1,48 @@ + + + + \ No newline at end of file diff --git a/bundle/pages/user_vip/user_vip.vue b/bundle/pages/user_vip/user_vip.vue new file mode 100644 index 0000000..88ef8dc --- /dev/null +++ b/bundle/pages/user_vip/user_vip.vue @@ -0,0 +1,253 @@ + + + + diff --git a/bundle/pages/user_wallet/user_wallet.vue b/bundle/pages/user_wallet/user_wallet.vue new file mode 100644 index 0000000..69f9ff1 --- /dev/null +++ b/bundle/pages/user_wallet/user_wallet.vue @@ -0,0 +1,212 @@ + + + + diff --git a/bundle/pages/user_withdraw/user_withdraw.vue b/bundle/pages/user_withdraw/user_withdraw.vue new file mode 100644 index 0000000..b0eb01a --- /dev/null +++ b/bundle/pages/user_withdraw/user_withdraw.vue @@ -0,0 +1,250 @@ + + + + + + + + + diff --git a/bundle/pages/user_withdraw_code/user_withdraw_code.vue b/bundle/pages/user_withdraw_code/user_withdraw_code.vue new file mode 100644 index 0000000..4076e14 --- /dev/null +++ b/bundle/pages/user_withdraw_code/user_withdraw_code.vue @@ -0,0 +1,97 @@ + + + + + + + diff --git a/bundle/pages/widthdraw_result/widthdraw_result.vue b/bundle/pages/widthdraw_result/widthdraw_result.vue new file mode 100644 index 0000000..f53d8d1 --- /dev/null +++ b/bundle/pages/widthdraw_result/widthdraw_result.vue @@ -0,0 +1,127 @@ + + + + + + diff --git a/bundle/static/No.0.png b/bundle/static/No.0.png new file mode 100644 index 0000000..b985f19 Binary files /dev/null and b/bundle/static/No.0.png differ diff --git a/bundle/static/activity_detail_bg.png b/bundle/static/activity_detail_bg.png new file mode 100644 index 0000000..6737ab3 Binary files /dev/null and b/bundle/static/activity_detail_bg.png differ diff --git a/bundle/static/bg_sgin.png b/bundle/static/bg_sgin.png new file mode 100644 index 0000000..ea1b114 Binary files /dev/null and b/bundle/static/bg_sgin.png differ diff --git a/bundle/static/contact_official_bg.png b/bundle/static/contact_official_bg.png new file mode 100644 index 0000000..95cb10d Binary files /dev/null and b/bundle/static/contact_official_bg.png differ diff --git a/bundle/static/icon_camera_line.png b/bundle/static/icon_camera_line.png new file mode 100644 index 0000000..c143a23 Binary files /dev/null and b/bundle/static/icon_camera_line.png differ diff --git a/bundle/static/icon_czjl.png b/bundle/static/icon_czjl.png new file mode 100644 index 0000000..0e499b9 Binary files /dev/null and b/bundle/static/icon_czjl.png differ diff --git a/bundle/static/icon_fenxiao.png b/bundle/static/icon_fenxiao.png new file mode 100644 index 0000000..32b3dbf Binary files /dev/null and b/bundle/static/icon_fenxiao.png differ diff --git a/bundle/static/icon_integral.png b/bundle/static/icon_integral.png new file mode 100644 index 0000000..7d74f8f Binary files /dev/null and b/bundle/static/icon_integral.png differ diff --git a/bundle/static/icon_invite.png b/bundle/static/icon_invite.png new file mode 100644 index 0000000..6878002 Binary files /dev/null and b/bundle/static/icon_invite.png differ diff --git a/bundle/static/icon_jifen.png b/bundle/static/icon_jifen.png new file mode 100644 index 0000000..54a997b Binary files /dev/null and b/bundle/static/icon_jifen.png differ diff --git a/bundle/static/icon_wait.png b/bundle/static/icon_wait.png new file mode 100644 index 0000000..1e9e49a Binary files /dev/null and b/bundle/static/icon_wait.png differ diff --git a/bundle/static/icon_yezz.png b/bundle/static/icon_yezz.png new file mode 100644 index 0000000..6d3356d Binary files /dev/null and b/bundle/static/icon_yezz.png differ diff --git a/bundle/static/icon_yongjin.png b/bundle/static/icon_yongjin.png new file mode 100644 index 0000000..e5b954a Binary files /dev/null and b/bundle/static/icon_yongjin.png differ diff --git a/bundle/static/icon_zhangdan.png b/bundle/static/icon_zhangdan.png new file mode 100644 index 0000000..c257db6 Binary files /dev/null and b/bundle/static/icon_zhangdan.png differ diff --git a/bundle/static/icon_zhmx.png b/bundle/static/icon_zhmx.png new file mode 100644 index 0000000..c81b46c Binary files /dev/null and b/bundle/static/icon_zhmx.png differ diff --git a/bundle/static/icon_zzjl.png b/bundle/static/icon_zzjl.png new file mode 100644 index 0000000..c258f22 Binary files /dev/null and b/bundle/static/icon_zzjl.png differ diff --git a/bundle/static/img_activity_coupon.png b/bundle/static/img_activity_coupon.png new file mode 100644 index 0000000..1723730 Binary files /dev/null and b/bundle/static/img_activity_coupon.png differ diff --git a/bundle/static/img_activity_jifen.png b/bundle/static/img_activity_jifen.png new file mode 100644 index 0000000..f3092e5 Binary files /dev/null and b/bundle/static/img_activity_jifen.png differ diff --git a/bundle/static/img_activity_pintuan.png b/bundle/static/img_activity_pintuan.png new file mode 100644 index 0000000..7b4e4eb Binary files /dev/null and b/bundle/static/img_activity_pintuan.png differ diff --git a/bundle/static/img_activity_seckill.png b/bundle/static/img_activity_seckill.png new file mode 100644 index 0000000..3f530f1 Binary files /dev/null and b/bundle/static/img_activity_seckill.png differ diff --git a/bundle/static/invoice_success.png b/bundle/static/invoice_success.png new file mode 100644 index 0000000..4cd34b9 Binary files /dev/null and b/bundle/static/invoice_success.png differ diff --git a/bundle/static/invoice_wait.png b/bundle/static/invoice_wait.png new file mode 100644 index 0000000..68cb5fd Binary files /dev/null and b/bundle/static/invoice_wait.png differ diff --git a/bundle/static/jifen_icon_data.png b/bundle/static/jifen_icon_data.png new file mode 100644 index 0000000..a0bca72 Binary files /dev/null and b/bundle/static/jifen_icon_data.png differ diff --git a/bundle/static/jifen_icon_help.png b/bundle/static/jifen_icon_help.png new file mode 100644 index 0000000..2000e56 Binary files /dev/null and b/bundle/static/jifen_icon_help.png differ diff --git a/bundle/static/jifen_icon_select.png b/bundle/static/jifen_icon_select.png new file mode 100644 index 0000000..12d1563 Binary files /dev/null and b/bundle/static/jifen_icon_select.png differ diff --git a/bundle/static/jifen_popBg.png b/bundle/static/jifen_popBg.png new file mode 100644 index 0000000..421efb4 Binary files /dev/null and b/bundle/static/jifen_popBg.png differ diff --git a/bundle/static/logistics_address.png b/bundle/static/logistics_address.png new file mode 100644 index 0000000..18335f2 Binary files /dev/null and b/bundle/static/logistics_address.png differ diff --git a/bundle/static/logistics_address_gray.png b/bundle/static/logistics_address_gray.png new file mode 100644 index 0000000..8d841d0 Binary files /dev/null and b/bundle/static/logistics_address_gray.png differ diff --git a/bundle/static/logistics_delivered.png b/bundle/static/logistics_delivered.png new file mode 100644 index 0000000..0a47991 Binary files /dev/null and b/bundle/static/logistics_delivered.png differ diff --git a/bundle/static/logistics_pay.png b/bundle/static/logistics_pay.png new file mode 100644 index 0000000..3af7c63 Binary files /dev/null and b/bundle/static/logistics_pay.png differ diff --git a/bundle/static/logistics_success.png b/bundle/static/logistics_success.png new file mode 100644 index 0000000..7642344 Binary files /dev/null and b/bundle/static/logistics_success.png differ diff --git a/bundle/static/logistics_transit.png b/bundle/static/logistics_transit.png new file mode 100644 index 0000000..1d31580 Binary files /dev/null and b/bundle/static/logistics_transit.png differ diff --git a/bundle/static/settled_bg.png b/bundle/static/settled_bg.png new file mode 100644 index 0000000..5f5739b Binary files /dev/null and b/bundle/static/settled_bg.png differ diff --git a/bundle/static/shop_official_bg.png b/bundle/static/shop_official_bg.png new file mode 100644 index 0000000..cd230f1 Binary files /dev/null and b/bundle/static/shop_official_bg.png differ diff --git a/bundle/static/spread_top_bg.png b/bundle/static/spread_top_bg.png new file mode 100644 index 0000000..03ae1c5 Binary files /dev/null and b/bundle/static/spread_top_bg.png differ diff --git a/bundle/static/store_recruitment_bg.png b/bundle/static/store_recruitment_bg.png new file mode 100644 index 0000000..906b0db Binary files /dev/null and b/bundle/static/store_recruitment_bg.png differ diff --git a/bundle/static/vip_grade_bg.png b/bundle/static/vip_grade_bg.png new file mode 100644 index 0000000..b03f23c Binary files /dev/null and b/bundle/static/vip_grade_bg.png differ diff --git a/bundle_b/pages/city/city.vue b/bundle_b/pages/city/city.vue new file mode 100644 index 0000000..023df12 --- /dev/null +++ b/bundle_b/pages/city/city.vue @@ -0,0 +1,280 @@ + + + + + diff --git a/bundle_b/pages/community_detail/community_detail.vue b/bundle_b/pages/community_detail/community_detail.vue new file mode 100644 index 0000000..dfcd845 --- /dev/null +++ b/bundle_b/pages/community_detail/community_detail.vue @@ -0,0 +1,657 @@ + + + + + diff --git a/bundle_b/pages/community_search/community_search.vue b/bundle_b/pages/community_search/community_search.vue new file mode 100644 index 0000000..164318a --- /dev/null +++ b/bundle_b/pages/community_search/community_search.vue @@ -0,0 +1,307 @@ + + + + diff --git a/bundle_b/pages/community_topic/community_topic.vue b/bundle_b/pages/community_topic/community_topic.vue new file mode 100644 index 0000000..e50e4a2 --- /dev/null +++ b/bundle_b/pages/community_topic/community_topic.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/bundle_b/pages/community_user/community_user.vue b/bundle_b/pages/community_user/community_user.vue new file mode 100644 index 0000000..6f9e4e1 --- /dev/null +++ b/bundle_b/pages/community_user/community_user.vue @@ -0,0 +1,381 @@ + + + + + diff --git a/bundle_b/pages/community_user/components/community-like.vue b/bundle_b/pages/community_user/components/community-like.vue new file mode 100644 index 0000000..9d07408 --- /dev/null +++ b/bundle_b/pages/community_user/components/community-like.vue @@ -0,0 +1,99 @@ + + + diff --git a/bundle_b/pages/community_user/components/community-works.vue b/bundle_b/pages/community_user/components/community-works.vue new file mode 100644 index 0000000..77bdbd9 --- /dev/null +++ b/bundle_b/pages/community_user/components/community-works.vue @@ -0,0 +1,97 @@ + + + diff --git a/bundle_b/pages/community_user_profile/community_user_profile.vue b/bundle_b/pages/community_user_profile/community_user_profile.vue new file mode 100644 index 0000000..fd03609 --- /dev/null +++ b/bundle_b/pages/community_user_profile/community_user_profile.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/bundle_b/pages/live_room/live_room.vue b/bundle_b/pages/live_room/live_room.vue new file mode 100644 index 0000000..84126e8 --- /dev/null +++ b/bundle_b/pages/live_room/live_room.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/bundle_b/pages/nearby_shops/nearby_shops.vue b/bundle_b/pages/nearby_shops/nearby_shops.vue new file mode 100644 index 0000000..9aabe0e --- /dev/null +++ b/bundle_b/pages/nearby_shops/nearby_shops.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/bundle_b/pages/published_works/components/goods.vue b/bundle_b/pages/published_works/components/goods.vue new file mode 100644 index 0000000..5921d2f --- /dev/null +++ b/bundle_b/pages/published_works/components/goods.vue @@ -0,0 +1,180 @@ + + + + diff --git a/bundle_b/pages/published_works/components/recommend.vue b/bundle_b/pages/published_works/components/recommend.vue new file mode 100644 index 0000000..181eb4c --- /dev/null +++ b/bundle_b/pages/published_works/components/recommend.vue @@ -0,0 +1,130 @@ + + + + + diff --git a/bundle_b/pages/published_works/components/shop.vue b/bundle_b/pages/published_works/components/shop.vue new file mode 100644 index 0000000..ad95871 --- /dev/null +++ b/bundle_b/pages/published_works/components/shop.vue @@ -0,0 +1,173 @@ + + + + diff --git a/bundle_b/pages/published_works/components/topic.vue b/bundle_b/pages/published_works/components/topic.vue new file mode 100644 index 0000000..06ab3a6 --- /dev/null +++ b/bundle_b/pages/published_works/components/topic.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/bundle_b/pages/published_works/published_works.vue b/bundle_b/pages/published_works/published_works.vue new file mode 100644 index 0000000..24b3fe2 --- /dev/null +++ b/bundle_b/pages/published_works/published_works.vue @@ -0,0 +1,441 @@ + + + + + diff --git a/bundle_b/static/community_user_bg.png b/bundle_b/static/community_user_bg.png new file mode 100644 index 0000000..3f3cef5 Binary files /dev/null and b/bundle_b/static/community_user_bg.png differ diff --git a/bundle_b/static/icon_audit_fail.png b/bundle_b/static/icon_audit_fail.png new file mode 100644 index 0000000..59e223e Binary files /dev/null and b/bundle_b/static/icon_audit_fail.png differ diff --git a/bundle_b/static/icon_follow.png b/bundle_b/static/icon_follow.png new file mode 100644 index 0000000..8499938 Binary files /dev/null and b/bundle_b/static/icon_follow.png differ diff --git a/bundle_b/static/icon_forward.png b/bundle_b/static/icon_forward.png new file mode 100644 index 0000000..0634948 Binary files /dev/null and b/bundle_b/static/icon_forward.png differ diff --git a/bundle_b/static/icon_my_setting.png b/bundle_b/static/icon_my_setting.png new file mode 100644 index 0000000..34c0f72 Binary files /dev/null and b/bundle_b/static/icon_my_setting.png differ diff --git a/bundle_b/static/icon_publish.png b/bundle_b/static/icon_publish.png new file mode 100644 index 0000000..e1e76c5 Binary files /dev/null and b/bundle_b/static/icon_publish.png differ diff --git a/bundle_b/static/icon_recommend.png b/bundle_b/static/icon_recommend.png new file mode 100644 index 0000000..5d74095 Binary files /dev/null and b/bundle_b/static/icon_recommend.png differ diff --git a/bundle_b/static/icon_see.png b/bundle_b/static/icon_see.png new file mode 100644 index 0000000..bef5ce1 Binary files /dev/null and b/bundle_b/static/icon_see.png differ diff --git a/bundle_b/static/icon_select.png b/bundle_b/static/icon_select.png new file mode 100644 index 0000000..7ead96b Binary files /dev/null and b/bundle_b/static/icon_select.png differ diff --git a/bundle_b/static/icon_share.png b/bundle_b/static/icon_share.png new file mode 100644 index 0000000..1e292bf Binary files /dev/null and b/bundle_b/static/icon_share.png differ diff --git a/bundle_b/static/icon_tags.png b/bundle_b/static/icon_tags.png new file mode 100644 index 0000000..a251c85 Binary files /dev/null and b/bundle_b/static/icon_tags.png differ diff --git a/bundle_b/static/icon_topic.png b/bundle_b/static/icon_topic.png new file mode 100644 index 0000000..0699792 Binary files /dev/null and b/bundle_b/static/icon_topic.png differ diff --git a/bundle_b/static/icon_under_review.png b/bundle_b/static/icon_under_review.png new file mode 100644 index 0000000..6ea5c09 Binary files /dev/null and b/bundle_b/static/icon_under_review.png differ diff --git a/bundle_b/static/icon_unselect.png b/bundle_b/static/icon_unselect.png new file mode 100644 index 0000000..cf62101 Binary files /dev/null and b/bundle_b/static/icon_unselect.png differ diff --git a/bundle_b/static/icon_unselect_tags.png b/bundle_b/static/icon_unselect_tags.png new file mode 100644 index 0000000..4158225 Binary files /dev/null and b/bundle_b/static/icon_unselect_tags.png differ diff --git a/bundle_b/static/like_null.png b/bundle_b/static/like_null.png new file mode 100644 index 0000000..c154eb8 Binary files /dev/null and b/bundle_b/static/like_null.png differ diff --git a/bundle_b/static/works_null.png b/bundle_b/static/works_null.png new file mode 100644 index 0000000..4fd060f Binary files /dev/null and b/bundle_b/static/works_null.png differ diff --git a/components/active-area/active-area.vue b/components/active-area/active-area.vue new file mode 100644 index 0000000..09e45d7 --- /dev/null +++ b/components/active-area/active-area.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/components/ad-swipers/ad-swipers.vue b/components/ad-swipers/ad-swipers.vue new file mode 100644 index 0000000..1778511 --- /dev/null +++ b/components/ad-swipers/ad-swipers.vue @@ -0,0 +1,181 @@ + + + + diff --git a/components/after-sales-list/after-sales-list.vue b/components/after-sales-list/after-sales-list.vue new file mode 100644 index 0000000..4e8eca9 --- /dev/null +++ b/components/after-sales-list/after-sales-list.vue @@ -0,0 +1,287 @@ + + + + diff --git a/components/bargain-list/bargain-list.vue b/components/bargain-list/bargain-list.vue new file mode 100644 index 0000000..6fb2e4d --- /dev/null +++ b/components/bargain-list/bargain-list.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/components/bubble-tips/bubble-tips.vue b/components/bubble-tips/bubble-tips.vue new file mode 100644 index 0000000..dcffb63 --- /dev/null +++ b/components/bubble-tips/bubble-tips.vue @@ -0,0 +1,179 @@ + + + + + diff --git a/components/cate-home/cate-home.vue b/components/cate-home/cate-home.vue new file mode 100644 index 0000000..191d398 --- /dev/null +++ b/components/cate-home/cate-home.vue @@ -0,0 +1,144 @@ + + + + diff --git a/components/cate-list/cate-list.vue b/components/cate-list/cate-list.vue new file mode 100644 index 0000000..d156d68 --- /dev/null +++ b/components/cate-list/cate-list.vue @@ -0,0 +1,152 @@ + + + + diff --git a/components/cate-nav/cate-nav.vue b/components/cate-nav/cate-nav.vue new file mode 100644 index 0000000..db3ad27 --- /dev/null +++ b/components/cate-nav/cate-nav.vue @@ -0,0 +1,100 @@ + + + + + diff --git a/components/cate-one/cate-one.vue b/components/cate-one/cate-one.vue new file mode 100644 index 0000000..f4eb848 --- /dev/null +++ b/components/cate-one/cate-one.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/components/cate-two/cate-two.vue b/components/cate-two/cate-two.vue new file mode 100644 index 0000000..8941034 --- /dev/null +++ b/components/cate-two/cate-two.vue @@ -0,0 +1,286 @@ + + + + + diff --git a/components/collection-list/collection-list.vue b/components/collection-list/collection-list.vue new file mode 100644 index 0000000..6a12857 --- /dev/null +++ b/components/collection-list/collection-list.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/components/comment-list/comment-list.vue b/components/comment-list/comment-list.vue new file mode 100644 index 0000000..fdadeac --- /dev/null +++ b/components/comment-list/comment-list.vue @@ -0,0 +1,195 @@ + + + + diff --git a/components/community-comment-list/community-comment-list.vue b/components/community-comment-list/community-comment-list.vue new file mode 100644 index 0000000..d1eff39 --- /dev/null +++ b/components/community-comment-list/community-comment-list.vue @@ -0,0 +1,255 @@ + + + + + diff --git a/components/community-comment-popup/community-comment-popup.vue b/components/community-comment-popup/community-comment-popup.vue new file mode 100644 index 0000000..3e7e9b2 --- /dev/null +++ b/components/community-comment-popup/community-comment-popup.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/components/community-comment/community-comment.vue b/components/community-comment/community-comment.vue new file mode 100644 index 0000000..0508a33 --- /dev/null +++ b/components/community-comment/community-comment.vue @@ -0,0 +1,129 @@ + + + + + \ No newline at end of file diff --git a/components/community-goods/community-goods.vue b/components/community-goods/community-goods.vue new file mode 100644 index 0000000..1524964 --- /dev/null +++ b/components/community-goods/community-goods.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/components/community-list/community-list.vue b/components/community-list/community-list.vue new file mode 100644 index 0000000..cb93e69 --- /dev/null +++ b/components/community-list/community-list.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/components/community-recommend/community-recommend.vue b/components/community-recommend/community-recommend.vue new file mode 100644 index 0000000..2aab152 --- /dev/null +++ b/components/community-recommend/community-recommend.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/components/community-shop/community-shop.vue b/components/community-shop/community-shop.vue new file mode 100644 index 0000000..cf24b43 --- /dev/null +++ b/components/community-shop/community-shop.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/components/coupon-list/coupon-list.vue b/components/coupon-list/coupon-list.vue new file mode 100644 index 0000000..6f03061 --- /dev/null +++ b/components/coupon-list/coupon-list.vue @@ -0,0 +1,203 @@ + + + + + diff --git a/components/coupon-order/coupon-order.vue b/components/coupon-order/coupon-order.vue new file mode 100644 index 0000000..290d5d4 --- /dev/null +++ b/components/coupon-order/coupon-order.vue @@ -0,0 +1,115 @@ + + + + diff --git a/components/cu-progress/cu-progress.vue b/components/cu-progress/cu-progress.vue new file mode 100644 index 0000000..839113d --- /dev/null +++ b/components/cu-progress/cu-progress.vue @@ -0,0 +1,76 @@ + + + + \ No newline at end of file diff --git a/components/custom-image/custom-image.vue b/components/custom-image/custom-image.vue new file mode 100644 index 0000000..5e2792b --- /dev/null +++ b/components/custom-image/custom-image.vue @@ -0,0 +1,151 @@ + + + + + diff --git a/components/emoji/emoji.vue b/components/emoji/emoji.vue new file mode 100644 index 0000000..85eb0bb --- /dev/null +++ b/components/emoji/emoji.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/components/exchange-order-list/exchange-order-list.vue b/components/exchange-order-list/exchange-order-list.vue new file mode 100644 index 0000000..bb45917 --- /dev/null +++ b/components/exchange-order-list/exchange-order-list.vue @@ -0,0 +1,259 @@ + + + + + + + diff --git a/components/float-tab/float-tab.vue b/components/float-tab/float-tab.vue new file mode 100644 index 0000000..9e75048 --- /dev/null +++ b/components/float-tab/float-tab.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/components/get-coupon/get-coupon.vue b/components/get-coupon/get-coupon.vue new file mode 100644 index 0000000..1e6aca1 --- /dev/null +++ b/components/get-coupon/get-coupon.vue @@ -0,0 +1,137 @@ + + + + + diff --git a/components/goods-bargain/goods-bargain.vue b/components/goods-bargain/goods-bargain.vue new file mode 100644 index 0000000..67e7e54 --- /dev/null +++ b/components/goods-bargain/goods-bargain.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/components/goods-column/goods-column.vue b/components/goods-column/goods-column.vue new file mode 100644 index 0000000..e06f9ac --- /dev/null +++ b/components/goods-column/goods-column.vue @@ -0,0 +1,143 @@ + + + + diff --git a/components/goods-list/goods-list.vue b/components/goods-list/goods-list.vue new file mode 100644 index 0000000..2bca598 --- /dev/null +++ b/components/goods-list/goods-list.vue @@ -0,0 +1,303 @@ + + + + + diff --git a/components/goods-shop/goods-shop.vue b/components/goods-shop/goods-shop.vue new file mode 100644 index 0000000..dd8c709 --- /dev/null +++ b/components/goods-shop/goods-shop.vue @@ -0,0 +1,117 @@ + + + + diff --git a/components/group-list/group-list.vue b/components/group-list/group-list.vue new file mode 100644 index 0000000..946d808 --- /dev/null +++ b/components/group-list/group-list.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/components/home-seckill/home-seckill.vue b/components/home-seckill/home-seckill.vue new file mode 100644 index 0000000..3eb6aaa --- /dev/null +++ b/components/home-seckill/home-seckill.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/components/index-home/index-home.vue b/components/index-home/index-home.vue new file mode 100644 index 0000000..3f4189b --- /dev/null +++ b/components/index-home/index-home.vue @@ -0,0 +1,338 @@ + + + + + diff --git a/components/invite-poster/invite-poster.vue b/components/invite-poster/invite-poster.vue new file mode 100644 index 0000000..3461428 --- /dev/null +++ b/components/invite-poster/invite-poster.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/components/j-video/j-video.vue b/components/j-video/j-video.vue new file mode 100644 index 0000000..0c06a77 --- /dev/null +++ b/components/j-video/j-video.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/components/lime-painter/changelog.md b/components/lime-painter/changelog.md new file mode 100644 index 0000000..298c3cf --- /dev/null +++ b/components/lime-painter/changelog.md @@ -0,0 +1,54 @@ +## 1.8.5.5(2021-08-17) +- chore: 更新文档,删除 replace +- fix: 修复 text 值为 number时报错 +## 1.8.5.4(2021-08-16) +- fix: 字节小程序兼容 +## 1.8.5.3(2021-08-15) +- fix: 修复线性渐变与css现实效果不一致的问题 +- chore: 更新文档 +## 1.8.5.2(2021-08-13) +- chore: 增加`background-image`、`background-repeat` 能力,主要用于背景纹理的绘制,并不是代替`image`。例如:大面积的重复平铺的水印 +- 注意:这个功能H5暂时无法使用,因为[官方的API有BUG](https://ask.dcloud.net.cn/question/128793),待官方修复!!! +## 1.8.5.1(2021-08-10) +- fix: 修复因`margin`报错问题 +## 1.8.5(2021-08-09) +- chore: 增加margin支持`auto`,以达到居中效果 +## 1.8.4(2021-08-06) +- chore: 增加判断缓存文件条件 +- fix: 修复css 多余空格报错问题 +## 1.8.3(2021-08-04) +- tips: 1.6.x 以下的版本升级到1.8.x后要为每个元素都加上定位:position: 'absolute' +- fix: 修复只有一个view子元素时不计算高度的问题 +## 1.8.2(2021-08-03) +- fix: 修复 path-type 为 `url` 无效问题 +- fix: 修复 qrcode `text` 为空时报错问题 +- fix: 修复 image `src` 动态设置时不生效问题 +- feat: 增加 css 属性 `min-width` `max-width` +## 1.8.1(2021-08-02) +- fix: 修复无法加载本地图片 +## 1.8.0(2021-08-02) +- chore 文档更新 +- 使用旧版的同学不要升级! +## 1.8.0-beta(2021-07-30) +- ## 全新布局方式 不兼容旧版! +- chore: 布局方式变更 +- tips: 微信canvas 2d 不支持真机调试 +## 1.6.6(2021-07-09) +- chore: 统一命名规范,无须主动引入组件 +## 1.6.5(2021-06-08) +- chore: 去掉console +## 1.6.4(2021-06-07) +- fix: 修复 数字 为纯字符串时不转换的BUG +## 1.6.3(2021-06-06) +- fix: 修复 PC 端放大的BUG +## 1.6.2(2021-05-31) +- fix: 修复 报`adaptor is not a function`错误 +- fix: 修复 text 多行高度 +- fix: 优化 默认文字的基准线 +- feat: `@progress`事件,监听绘制进度 +## 1.6.1(2021-02-28) +- 删除多余节点 +## 1.6.0(2021-02-26) +- 调整为uni_modules目录规范 +- 修复:transform的rotate不能为负数问题 +- 新增:`pathType` 指定生成图片返回的路径类型,可选值有 `base64`、`url` diff --git a/components/lime-painter/components/common/relation.js b/components/lime-painter/components/common/relation.js new file mode 100644 index 0000000..895d4e1 --- /dev/null +++ b/components/lime-painter/components/common/relation.js @@ -0,0 +1,141 @@ +import {base64ToPath} from '../l-painter/utils.js' + +const styles = (v = '') => v.split(';').filter(v => v && !/^[\n\s]+$/.test(v)).map(v => { + const item = v.split(':'); + return { + [item[0] + .replace(/-([a-z])/g, function() { + return arguments[1].toUpperCase() + }) + .replace(/\s+/g, '') + ]: item?. [1]?.replace(/^\s+/, '')?.replace(/\s+$/, '') || '' + } +}) +export function parent(parent) { + return { + provide() { + return { + [parent]: this + } + }, + data() { + return { + el: { + css: {}, + views: [] + }, + } + }, + watch: { + css: { + handler(v) { + if (this.canvasId) { + this.el.css = typeof v == 'object' ? v : v && Object.assign(...styles(v)) || {} + this.canvasWidth = this.el.css?.width || this.canvasWidth + this.canvasHeight = this.el.css?.height || this.canvasHeight + } + }, + immediate: true + } + } + } +} +export function children(parent, options = {}) { + const indexKey = options.indexKey || 'index' + return { + inject: { + [parent]: { + default: null + } + }, + watch: { + el: { + handler(v, o) { + if (JSON.stringify(v) != JSON.stringify(o)) + this.bindRelation() + }, + deep: true, + immediate: true + }, + src: { + handler(v, o) { + if (v != o) + this.bindRelation() + }, + immediate: true + }, + text: { + handler(v, o) { + if (v != o) this.bindRelation() + }, + immediate: true + }, + css: { + handler(v, o) { + if (v != o) + this.el.css = typeof v == 'object' ? v : v && Object.assign(...styles(v)) || {} + }, + immediate: true + }, + replace: { + handler(v, o) { + if (JSON.stringify(v) != JSON.stringify(o)) + this.bindRelation() + }, + deep: true, + immediate: true + }, + }, + created() { + Object.defineProperty(this, 'parent', { + get: () => { + return this[parent] + }, + }) + Object.defineProperty(this, 'index', { + get: () => { + this.bindRelation(); + return this.parent?.el.views?.indexOf(this.el) + }, + }); + this.el.type = this.type + }, + beforeDestroy() { + if (this.parent) { + this.parent.el.views = this.parent.el.views.filter( + (item) => item._uid !== this._uid + ); + } + }, + methods: { + bindRelation() { + if (!this.el._uid) { + this.el._uid = this._uid + } + if (['text', 'qrcode'].includes(this.type)) { + this.el.text = this.$slots?.default?. [0]?.text || this.text?.replace(/\\n/g, '\n') + } + if (this.type == 'text' && this.replace) { + this.el.replace = this.replace + } + if (this.type == 'image') { + this.el.src = this.src + } + // || this.parent.el.views.indexOf(this.el) !== -1 + if (!this.parent) { + return; + } + + let views = this.parent.el.views || []; + if (views.indexOf(this.el) !== -1) { + this.parent.el.views = views.map(v => v._uid == this._uid ? this.el : v) + } else { + this.parent.el.views = [...views, this.el]; + } + } + }, + mounted() { + this.bindRelation() + }, + } +} diff --git a/components/lime-painter/components/l-painter-image/l-painter-image.vue b/components/lime-painter/components/l-painter-image/l-painter-image.vue new file mode 100644 index 0000000..72437da --- /dev/null +++ b/components/lime-painter/components/l-painter-image/l-painter-image.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/components/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue b/components/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue new file mode 100644 index 0000000..599f27b --- /dev/null +++ b/components/lime-painter/components/l-painter-qrcode/l-painter-qrcode.vue @@ -0,0 +1,27 @@ + + + + + diff --git a/components/lime-painter/components/l-painter-text/l-painter-text.vue b/components/lime-painter/components/l-painter-text/l-painter-text.vue new file mode 100644 index 0000000..602f64f --- /dev/null +++ b/components/lime-painter/components/l-painter-text/l-painter-text.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/components/lime-painter/components/l-painter-view/l-painter-view.vue b/components/lime-painter/components/l-painter-view/l-painter-view.vue new file mode 100644 index 0000000..01448b8 --- /dev/null +++ b/components/lime-painter/components/l-painter-view/l-painter-view.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/components/lime-painter/components/l-painter/l-painter.vue b/components/lime-painter/components/l-painter/l-painter.vue new file mode 100644 index 0000000..5e4528e --- /dev/null +++ b/components/lime-painter/components/l-painter/l-painter.vue @@ -0,0 +1,523 @@ + + + + + \ No newline at end of file diff --git a/components/lime-painter/components/l-painter/nvue.js b/components/lime-painter/components/l-painter/nvue.js new file mode 100644 index 0000000..c8a7fd4 --- /dev/null +++ b/components/lime-painter/components/l-painter/nvue.js @@ -0,0 +1,103 @@ +const painterContent = ` + var cache = []; + var painter = null; + var canvas = null; + var context = null; + var timer = null; + var pixelRatio = 1; + console.log = function(...args) { + postMessage(args); + }; + function stringify(key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + return; + } + cache.push(value); + } + return value; + }; + function emit(event, data) { + let dataStr = typeof data !== 'object' && data !== null ? data : JSON.stringify(data, stringify); + postMessage({ + event, + data: dataStr + }); + cache = []; + }; + function postMessage(data) { + uni.postMessage({ + data + }); + }; + function init() { + canvas = document.querySelector('#lime-painter'); + context = canvas.getContext('2d'); + pixelRatio = window.devicePixelRatio; + painter = new Painter({ + id: 'lime-painter', + context, + canvas, + pixelRatio, + width: canvas.offsetWidth, + height: canvas.offsetHeight + }); + emit('inited', true); + painter.listen('progressChange', (v) => { + emit('progressChange', v); + }); + }; + function save(args) { + delete args.success; + delete args.fail; + clearTimeout(timer); + timer = setTimeout(() => { + const path = painter.save(args); + if(typeof path == 'string') { + const index = Math.ceil(path.length / 8); + for (var i = 0; i < 8; i++) { + if(i == 7) { + emit('success', path.substr(i * index, index)); + } else { + emit('file', path.substr(i * index, index)); + } + }; + } else { + emit('fail', ''); + }; + }, 30); + }; + async function source(args) { + let res = await painter.source(args); + emit('layoutChange', res); + await painter.render(); + }; +` +export default ` + document.write("不支持cavnas"); + let meta = document.createElement('meta'); + meta.name = 'viewport'; + meta.content = 'width=device-width, initial-scale=1.0'; + document.head.appendChild(meta); + let styleEl = document.createElement('style'); + styleEl.setAttribute('type', 'text/css'); + styleEl.textContent='html,body,#lime-painter{padding: 0; margin: 0; width:100%;height:100%}'; + document.head.appendChild(styleEl); + + var script = document.createElement("script"); + script.language = "javascript"; + script.src = "https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.1.5.2.js"; + script.onload = function() { + var script = document.createElement("script"); + script.language = "javascript"; + script.src = "https://cdn.jsdelivr.net/gh/liangei/image@latest/lime-ui/lime-painter/painter.js"; + script.onload = function() {init()}; + document.head.appendChild(script); + }; + document.head.appendChild(script); + + var script = document.createElement("script"); + script.language = "javascript"; + script.text = "${painterContent}"; + document.body.appendChild(script); +` diff --git a/components/lime-painter/components/l-painter/painter.js b/components/lime-painter/components/l-painter/painter.js new file mode 100644 index 0000000..fdf69cd --- /dev/null +++ b/components/lime-painter/components/l-painter/painter.js @@ -0,0 +1,15 @@ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).Painter={})}(this,(function(t){"use strict"; +/*! ***************************************************************************** + Copyright (c) Microsoft Corporation. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH + REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, + INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + PERFORMANCE OF THIS SOFTWARE. + ***************************************************************************** */var e,i=function(){return(i=Object.assign||function(t){for(var e,i=1,o=arguments.length;i0&&r[r.length-1])||6!==n[0]&&2!==n[0])){s=0;continue}if(3===n[0]&&(!r||n[1]>r[0]&&n[1]0;break}}return r}("Android"===plus.os.name?"1.9.9.80627":"1.9.9.80472",plus.runtime.innerVersion))return void plus.io.resolveLocalFileSystemURL(u,(function(i){i.getDirectory(f,{create:!0,exclusive:!1},(function(i){i.getFile(c,{create:!0,exclusive:!1},(function(i){i.createWriter((function(i){var o;i.onwrite=function(){t(g)},i.onerror=e,i.seek(0),i.writeAsBinary((o=h.split(","))[o.length-1])}),e)}),e)}),e)}),e);var v=new plus.nativeObj.Bitmap(c);v.loadBase64Data(h,(function(){v.save(g,{},(function(){v.clear(),t(g)}),(function(t){v.clear(),e(t)}))}),(function(t){v.clear(),e(t)}))}})))];case 2:return e=r.sent(),[3,4];case 3:return o=r.sent(),console.log(o),[3,4];case 4:return a.getImageInfo({src:e,success:function(t){return i(t)},fail:function(t){return n(t)}}),[2]}var h}))}))}))}var u=function(t){return!(!t||!t.startsWith("linear")&&!t.startsWith("radial"))},f=function(t,e,i,o,r,n){t.startsWith("linear")?function(t,e,i,o,r,n){for(var s=function(t,e,i,o,r){void 0===o&&(o=0);void 0===r&&(r=0);var n=t.match(/([-]?\d{1,3})deg/),s=n&&n[1]?parseFloat(n[1]):0;s>=360&&(s-=360);s<0&&(s+=360);if(0===(s=Math.round(s)))return{x0:Math.round(e/2)+o,y0:i+r,x1:Math.round(e/2)+o,y1:r};if(180===s)return{x0:Math.round(e/2)+o,y0:r,x1:Math.round(e/2)+o,y1:i+r};if(90===s)return{x0:o,y0:Math.round(i/2)+r,x1:e+o,y1:Math.round(i/2)+r};if(270===s)return{x0:e+o,y0:Math.round(i/2)+r,x1:o,y1:Math.round(i/2)+r};var a=Math.round(180*Math.asin(e/Math.sqrt(Math.pow(e,2)+Math.pow(i,2)))/Math.PI);if(s===a)return{x0:o,y0:i+r,x1:e+o,y1:r};if(s===180-a)return{x0:o,y0:r,x1:e+o,y1:i+r};if(s===180+a)return{x0:e+o,y0:r,x1:o,y1:i+r};if(s===360-a)return{x0:e+o,y0:i+r,x1:o,y1:r};var h=0,d=0,l=0,c=0;if(s180-a&&s<180||s>180&&s<180+a||s>360-a){var u=s*Math.PI/180,f=s360-a?i/2:-i/2,g=Math.tan(u)*f,v=s180-a&&s<180?e/2-g:-e/2-g;h=-(l=g+(p=Math.pow(Math.sin(u),2)*v)),d=-(c=f+p/Math.tan(u))}if(s>a&&s<90||s>90&&s<90+a||s>180+a&&s<270||s>270&&s<360-a){var p;u=(90-s)*Math.PI/180,g=s>a&&s<90||s>90&&s<90+a?e/2:-e/2,f=Math.tan(u)*g,v=s>a&&s<90||s>270&&s<360-a?i/2-f:-i/2-f;h=-(l=g+(p=Math.pow(Math.sin(u),2)*v)/Math.tan(u)),d=-(c=f+p)}return h=Math.round(h+e/2)+o,d=Math.round(i/2-d)+r,l=Math.round(l+e/2)+o,c=Math.round(i/2-c)+r,{x0:h,y0:d,x1:l,y1:c}}(r,t,e,i,o),a=s.x0,h=s.y0,d=s.x1,l=s.y1,c=n.createLinearGradient(a,h,d,l),u=r.match(/linear-gradient\((.+)\)/)[1],f=g(u.substring(u.indexOf(",")+1)),v=0;vh.left+h.width+l;if(this.getBoxState(u,b)||S){var z,B,R,M;if(b.style.left+=n,(null==(z=u)?void 0:z.offsetSize.height)>=(null==(B=f)?void 0:B.offsetSize.height))b.style.top+=u.offsetSize.top+u.offsetSize.height||0;else b.style.top+=(null==(R=f)?void 0:R.offsetSize.top)+(null==(M=f)?void 0:M.offsetSize.height)||0;b.getBoxPosition(),u=b,f=b,g=!0}else b.style.left+=u.offsetSize.left+u.offsetSize.width,b.style.top+=g?u.offsetSize.top:a,b.getBoxPosition(),u=b}}this.layoutBoxUpdate(h,e)}else this.layoutBoxUpdate(h,e);return this.layoutBox},e.setMaxLineHeight=function(t,e,i){for(var o=t;o>=0&&!e[o].contentSize.maxLineHeight;)e[o].contentSize.maxLineHeight=i,o--},e.getBoxState=function(t,e){return"view"==e.name&&"inline-block"!==e.style.display||"view"==(null==t?void 0:t.name)&&"inline-block"!==(null==t?void 0:t.style.display)||"block"==e.style.display||"block"==(null==t?void 0:t.style.display)},e.getBoxHieght=function(){var t,e=this,i=this.name,o=this.computedStyle,r=this.attributes,n=this.parent,s=this.getChildren(),a=o.top,h=o.bottom,d=o.height,c=void 0===d?0:d,u=o.fontSize,f=void 0===u?14:u,g=o.position,v=o.lineHeight,b=void 0===v?"1.4em":v;o.lineClamp;var m=p({},this.contentSize);if("image"==i&&null==c){var w=r.width,x=r.height;r.mode,m.height=Math.round(m.width*x/w)||0,this.layoutBoxUpdate(m,o,"height")}else if(c)if(s.length){var y=null,S=0;s.forEach((function(t,i){var o,r,n=i==s.length-1;t.getBoxHieght();var a=(null==(o=y)?void 0:o.offsetSize.left)+(null==(r=y)?void 0:r.offsetSize.width)+t.offsetSize.width>m.left+m.width,h=e.getBoxState(y,t);if(a||h){if(a){for(var d=i-1;d>=0&&!s[d].contentSize.maxLineHeight;)S=0&&!s[l].contentSize.maxLineHeight;)Sm.width;if(a||n){var h,d,l=0;return a||M&&("view"!==(null==(h=M)?void 0:h.name)||"inline-block"==(null==(d=M)?void 0:d.style.display))?(r&&(e.setMaxLineHeight(o-1,s,R),R+=i.offsetSize.height),l=t+R,R=i.offsetSize.height,k=i.offsetSize.width,M=i,l):(k=0,R=0,t+i.offsetSize.height)}return k+=i.offsetSize.width,R=Math.max(R,i.offsetSize.height)||0,r?(e.setMaxLineHeight(o,s,R),t+R):(M=i,t)}),0),z&&(m.height=z),this.layoutBoxUpdate(m,o)}else z&&(m.height=z),this.layoutBoxUpdate(m,o,"height")}if(o.borderRadius&&null!=(t=this.borderSize)&&t.width)for(var P in o.borderRadius)Object.hasOwnProperty.call(o.borderRadius,P)&&(o.borderRadius[P]=l(o.borderRadius[P],this.borderSize.width));return this.layoutBox},e.contrastSize=function(t,e,i){var o=t;return i&&(o=Math.min(o,i)),e&&(o=Math.max(o,e)),o},e.measureText=function(t,e){var i=this.ctx.measureText(t);return{width:i.width,fontHeight:(i.actualBoundingBoxAscent||.7*e)+1}},e.getBoxWidth=function(){var t,e=this,i=this.name,o=this.computedStyle,r=this.attributes,n=this.parent,s=void 0===n?{}:n,a=this.ctx,h=this.getChildren(),d=o.left,c=void 0===d?0:d;o.top;var u=o.right,f=o.width,g=void 0===f?0:f,v=o.minWidth,p=o.maxWidth,b=o.height,m=void 0===b?0:b,w=o.fontSize,x=void 0===w?14:w,y=o.fontWeight,S=o.fontFamily,z=o.textStyle,B=o.position,R=o.display,M=o.lineClamp,k=o.padding,P=void 0===k?{}:k,O=o.margin,T=void 0===O?{}:O,L=o.border,W=(L=void 0===L?{}:L).borderWidth,I=void 0===W?0:W,j=o.borderRight,C=(j=void 0===j?{}:j).borderRightWidth,F=void 0===C?I:C,A=o.borderLeft,H=(A=void 0===A?{}:A).borderLeftWidth,$=void 0===H?I:H;if(/%$/.test(g)&&s.contentSize.width&&(g=l(g,s.contentSize.width,!0)),/%$/.test(m)&&s.contentSize.height&&(m=l(m,s.contentSize.height)),/%$/.test(v)&&s.contentSize.width&&(v=l(v,s.contentSize.width,!0)),/%$/.test(p)&&s.contentSize.width&&(p=l(p,s.contentSize.width,!0)),o.padding&&null!=(t=s.contentSize)&&t.width)for(var E in o.padding)Object.hasOwnProperty.call(o.padding,E)&&(o.padding[E]=l(o.padding[E],s.contentSize.width));var U=P.paddingRight,_=void 0===U?0:U,D=P.paddingLeft,N=void 0===D?0:D;if(o.margin&&[o.margin.marginLeft,o.margin.marginRight].includes("auto"))if(g){var V=s.contentSize.width-g-_-N-$-F||0;o.margin.marginLeft==o.margin.marginRight?o.margin.marginLeft=o.margin.marginRight=V/2:"auto"==o.margin.marginLeft?o.margin.marginLeft=V:o.margin.marginRight=V}else o.margin.marginLeft=o.margin.marginRight=0;var X=T.marginRight,q=void 0===X?0:X,G=T.marginLeft,J={width:g,height:m,left:0,top:0},Y=N+_+$+F+(void 0===G?0:G)+q;if("text"==i&&!this.attributes.widths){var Q=r.text||"";a.save(),a.setFonts({fontFamily:S,fontSize:x,fontWeight:y,textStyle:z}),Q.split("\n").map((function(t){var i=t.split("").map((function(t){return e.measureText(t,x).width}));e.attributes.fontHeight=e.measureText(t,x).fontHeight,e.attributes.widths||(e.attributes.widths=[]),e.attributes.widths.push({widths:i,total:i.reduce((function(t,e){return t+e}),0)})})),a.restore()}if("image"==i&&null==g){var Z=r.width,K=r.height;J.width=this.contrastSize(Math.round(Z*m/K)||0,v,p),this.layoutBoxUpdate(J,o,"width")}else if(g)h.length?(this.layoutBoxUpdate(J,o,"width"),h.forEach((function(t){t.getBoxWidth()}))):this.layoutBoxUpdate(J,o,"width");else{var tt=0;if((this.isAbsolute||this.isFixed)&&s.contentSize.width){var et="absolute"==B?s.contentSize.width:this.root.width;tt=et-(/%$/.test(c)?l(c,et):c)-(/%$/.test(u)?l(u,et):u)}if("text"==i){var it=this.attributes.widths,ot=Math.max.apply(Math,it.map((function(t){return t.total})));if(s&&s.contentSize.width>0&&(ot>s.contentSize.width||"block"==R)&&!this.isAbsolute&&!this.isFixed)ot=s.contentSize.width-Y;J.width=tt||this.contrastSize(ot,v,p),this.layoutBoxUpdate(J,o,"width")}else if("view"!=i||!s||"inline-block"===R||this.isAbsolute||this.isFixed)if(h.length){for(var rt=0,nt=null,st=0;h.length>st;){var at=h[st],ht=st==h.length-1,dt=this.getBoxState(nt,at);if(!at.isFixed&&!at.isAbsolute)if(!nt||dt){var lt=at.getBoxWidth();rt=Math.max(rt,lt.width)||0,nt=at}else if(nt.offsetSize.left+nt.offsetSize.width+at.offsetSize.widthJ.width?(ut++,e):t+e}),0)})),ut=M&&ut>M?M:ut,this.attributes.lines=ut}return this.layoutBox},e.layout=function(){return this.getBoxWidth(),this.getBoxHieght(),this.getBoxPosition(),this.offsetSize},t}(),x=function(){var t,e,i,o,r,n,s=[0,11,15,19,23,27,31,16,18,20,22,24,26,28,20,22,24,24,26,28,28,22,24,24,26,26,28,28,24,24,26,26,26,28,28,24,26,26,26,28,28],a=[3220,1468,2713,1235,3062,1890,2119,1549,2344,2936,1117,2583,1330,2470,1667,2249,2028,3780,481,4011,142,3098,831,3445,592,2517,1776,2234,1951,2827,1070,2660,1345,3177],h=[30660,29427,32170,30877,26159,25368,27713,26998,21522,20773,24188,23371,17913,16590,20375,19104,13663,12392,16177,14854,9396,8579,11994,11245,5769,5054,7399,6608,1890,597,3340,2107],d=[1,0,19,7,1,0,16,10,1,0,13,13,1,0,9,17,1,0,34,10,1,0,28,16,1,0,22,22,1,0,16,28,1,0,55,15,1,0,44,26,2,0,17,18,2,0,13,22,1,0,80,20,2,0,32,18,2,0,24,26,4,0,9,16,1,0,108,26,2,0,43,24,2,2,15,18,2,2,11,22,2,0,68,18,4,0,27,16,4,0,19,24,4,0,15,28,2,0,78,20,4,0,31,18,2,4,14,18,4,1,13,26,2,0,97,24,2,2,38,22,4,2,18,22,4,2,14,26,2,0,116,30,3,2,36,22,4,4,16,20,4,4,12,24,2,2,68,18,4,1,43,26,6,2,19,24,6,2,15,28,4,0,81,20,1,4,50,30,4,4,22,28,3,8,12,24,2,2,92,24,6,2,36,22,4,6,20,26,7,4,14,28,4,0,107,26,8,1,37,22,8,4,20,24,12,4,11,22,3,1,115,30,4,5,40,24,11,5,16,20,11,5,12,24,5,1,87,22,5,5,41,24,5,7,24,30,11,7,12,24,5,1,98,24,7,3,45,28,15,2,19,24,3,13,15,30,1,5,107,28,10,1,46,28,1,15,22,28,2,17,14,28,5,1,120,30,9,4,43,26,17,1,22,28,2,19,14,28,3,4,113,28,3,11,44,26,17,4,21,26,9,16,13,26,3,5,107,28,3,13,41,26,15,5,24,30,15,10,15,28,4,4,116,28,17,0,42,26,17,6,22,28,19,6,16,30,2,7,111,28,17,0,46,28,7,16,24,30,34,0,13,24,4,5,121,30,4,14,47,28,11,14,24,30,16,14,15,30,6,4,117,30,6,14,45,28,11,16,24,30,30,2,16,30,8,4,106,26,8,13,47,28,7,22,24,30,22,13,15,30,10,2,114,28,19,4,46,28,28,6,22,28,33,4,16,30,8,4,122,30,22,3,45,28,8,26,23,30,12,28,15,30,3,10,117,30,3,23,45,28,4,31,24,30,11,31,15,30,7,7,116,30,21,7,45,28,1,37,23,30,19,26,15,30,5,10,115,30,19,10,47,28,15,25,24,30,23,25,15,30,13,3,115,30,2,29,46,28,42,1,24,30,23,28,15,30,17,0,115,30,10,23,46,28,10,35,24,30,19,35,15,30,17,1,115,30,14,21,46,28,29,19,24,30,11,46,15,30,13,6,115,30,14,23,46,28,44,7,24,30,59,1,16,30,12,7,121,30,12,26,47,28,39,14,24,30,22,41,15,30,6,14,121,30,6,34,47,28,46,10,24,30,2,64,15,30,17,4,122,30,29,14,46,28,49,10,24,30,24,46,15,30,4,18,122,30,13,32,46,28,48,14,24,30,42,32,15,30,20,4,117,30,40,7,47,28,43,22,24,30,10,67,15,30,19,6,118,30,18,31,47,28,34,34,24,30,20,61,15,30],l=[255,0,1,25,2,50,26,198,3,223,51,238,27,104,199,75,4,100,224,14,52,141,239,129,28,193,105,248,200,8,76,113,5,138,101,47,225,36,15,33,53,147,142,218,240,18,130,69,29,181,194,125,106,39,249,185,201,154,9,120,77,228,114,166,6,191,139,98,102,221,48,253,226,152,37,179,16,145,34,136,54,208,148,206,143,150,219,189,241,210,19,92,131,56,70,64,30,66,182,163,195,72,126,110,107,58,40,84,250,133,186,61,202,94,155,159,10,21,121,43,78,212,229,172,115,243,167,87,7,112,192,247,140,128,99,13,103,74,222,237,49,197,254,24,227,165,153,119,38,184,180,124,17,68,146,217,35,32,137,46,55,63,209,91,149,188,207,205,144,135,151,178,220,252,190,97,242,86,211,171,20,42,93,158,132,60,57,83,71,109,65,162,31,45,67,216,183,123,164,118,196,23,73,236,127,12,111,246,108,161,59,82,41,157,85,170,251,96,134,177,187,204,62,90,203,89,95,176,156,169,160,81,11,245,22,235,122,117,44,215,79,174,213,233,230,231,173,232,116,214,244,234,168,80,88,175],c=[1,2,4,8,16,32,64,128,29,58,116,232,205,135,19,38,76,152,45,90,180,117,234,201,143,3,6,12,24,48,96,192,157,39,78,156,37,74,148,53,106,212,181,119,238,193,159,35,70,140,5,10,20,40,80,160,93,186,105,210,185,111,222,161,95,190,97,194,153,47,94,188,101,202,137,15,30,60,120,240,253,231,211,187,107,214,177,127,254,225,223,163,91,182,113,226,217,175,67,134,17,34,68,136,13,26,52,104,208,189,103,206,129,31,62,124,248,237,199,147,59,118,236,197,151,51,102,204,133,23,46,92,184,109,218,169,79,158,33,66,132,21,42,84,168,77,154,41,82,164,85,170,73,146,57,114,228,213,183,115,230,209,191,99,198,145,63,126,252,229,215,179,123,246,241,255,227,219,171,75,150,49,98,196,149,55,110,220,165,87,174,65,130,25,50,100,200,141,7,14,28,56,112,224,221,167,83,166,81,162,89,178,121,242,249,239,195,155,43,86,172,69,138,9,18,36,72,144,61,122,244,245,247,243,251,235,203,139,11,22,44,88,176,125,250,233,207,131,27,54,108,216,173,71,142,0],u=[],f=[],g=[],v=[],p=[],b=2;function m(t,e){var i;t>e&&(i=t,t=e,e=i),i=e,i*=e,i+=e,i>>=1,v[i+=t]=1}function w(t,i){var o;for(g[t+e*i]=1,o=-2;o<2;o++)g[t+o+e*(i-2)]=1,g[t-2+e*(i+o+1)]=1,g[t+2+e*(i+o)]=1,g[t+o+1+e*(i+2)]=1;for(o=0;o<2;o++)m(t-1,i+o),m(t+1,i-o),m(t-o,i-1),m(t+o,i+1)}function x(t){for(;t>=255;)t=((t-=255)>>8)+(255&t);return t}var y=[];function S(t,e,i,o){var r,n,s;for(r=0;re&&(i=t,t=e,e=i),i=e,i+=e*e,i>>=1,v[i+=t]}function B(t){var i,o,r,n;switch(t){case 0:for(o=0;o>1&1,i=0;i=5&&(i+=3+p[e]-5);for(e=3;et||3*p[e-3]>=4*p[e]||3*p[e+3]>=4*p[e])&&(i+=40);return i}function M(){var t,i,o,r,n,s=0,a=0;for(i=0;ie*e;)h-=e*e,d++;for(s+=10*d,t=0;t1)for(O=s[t],k=e-7;;){for(R=e-7;R>O-3&&(w(R,k),!(R6)for(O=a[t-7],P=17,R=0;R<6;R++)for(k=0;k<3;k++,P--)1&(P>11?t>>P-12:O>>P)?(g[5-R+e*(2-k+e-11)]=1,g[2-k+e-11+e*(5-R)]=1):(m(5-R,2-k+e-11),m(2-k+e-11,5-R));for(k=0;k=(R=r*(i+o)+o)-2&&(T=R-2,t>9&&T--),L=T,t>9){for(u[L+2]=0,u[L+3]=0;L--;)O=u[L],u[L+3]|=255&O<<4,u[L+2]=O>>4;u[2]|=255&T<<4,u[1]=T>>4,u[0]=64|T>>12}else{for(u[L+1]=0,u[L+2]=0;L--;)O=u[L],u[L+2]|=255&O<<4,u[L+1]=O>>4;u[1]|=255&T<<4,u[0]=64|T>>4}for(L=T+3-(t<10);L0;W--)y[W]=y[W]?y[W-1]^c[x(l[y[W]]+L)]:y[W-1];y[0]=c[x(l[y[0]]+L)]}for(L=0;L<=n;L++)y[L]=l[y[L]];for(P=R,k=0,L=0;L>=1)1&k&&(g[e-1-P+8*e]=1,P<6?g[8+e*P]=1:g[8+e*(P+1)]=1);for(P=0;P<7;P++,k>>=1)1&k&&(g[8+e*(e-7+P)]=1,P?g[6-P+8*e]=1:g[7+8*e]=1);return g}(p)},utf16to8:function(t){var e,i,o,r;for(e="",o=t.length,i=0;i=1&&r<=127?e+=t.charAt(i):r>2047?(e+=String.fromCharCode(224|r>>12&15),e+=String.fromCharCode(128|r>>6&63),e+=String.fromCharCode(128|r>>0&63)):(e+=String.fromCharCode(192|r>>6&31),e+=String.fromCharCode(128|r>>0&63));return e},draw:function(t,i,o,r,n){i.drawView(o,r);var s=i.ctx,a=o.contentSize,h=a.width,d=a.height;r.borderRadius,r.backgroundColor;var l=r.color,c=void 0===l?"#000000":l;r.border;var u=o.contentSize.left-o.borderSize.left,f=o.contentSize.top-o.borderSize.top;if(b=n||b,s){s.save(),i.setOpacity(r);var g=i.setTransform(o,r),v=g.x,p=g.y;v+=u,p+=f;var m=Math.min(h,d);t=this.utf16to8(t);var w=this.getFrame(t),x=m/e;s.setFillStyle(c);for(var y=0;y0?1:-1)*r.x+(B+v)/c,y:k*(f>0?1:-1)*r.y+(R+b)/f};return s.translate(T.x,T.y),w&&s.rotate(w*Math.PI/180),(y||z)&&s.transform(1,Math.tan(z*Math.PI/180),Math.tan(y*Math.PI/180),1,0,0),{x:-M*r.x,y:-k*r.y,w:M,h:k}},t.prototype.setBackground=function(t,e,i,o,r){var n=this.ctx;t&&"transparent"!=t?u(t)?f(t,e,i,o,r,n):n.setFillStyle(t):["mp-toutiao","mp-baidu"].includes(this.platform)?n.setFillStyle("transparent"):n.setFillStyle("rgba(0,0,0,0)")},t.prototype.setShadow=function(t){var e=t.boxShadow,i=void 0===e?[]:e,o=this.ctx;if(i.length){var r=i[0],n=i[1],s=i[2],a=i[3];o.setShadow(r,n,s,a)}},t.prototype.setBorder=function(t,e){var i=this,o=this.ctx,r=t.width,n=t.height,s=e.border,a=e.borderBottom,h=e.borderTop,d=e.borderRight,l=e.borderLeft,c=e.borderRadius,u=s||{},f=u.borderWidth,g=void 0===f?0:f,v=u.borderStyle,p=u.borderColor,b=a||{},m=b.borderBottomWidth,w=void 0===m?g:m,x=b.borderBottomStyle,y=void 0===x?v:x,S=b.borderBottomColor,z=void 0===S?p:S,B=h||{},R=B.borderTopWidth,M=void 0===R?g:R,k=B.borderTopStyle,P=void 0===k?v:k,O=B.borderTopColor,T=void 0===O?p:O,L=d||{},W=L.borderRightWidth,I=void 0===W?g:W,j=L.borderRightStyle,C=void 0===j?v:j,F=L.borderRightColor,A=void 0===F?p:F,H=l||{},$=H.borderLeftWidth,E=void 0===$?g:$,U=H.borderLeftStyle,_=void 0===U?v:U,D=H.borderLeftColor,N=void 0===D?p:D,V=c||{},X=V.borderTopLeftRadius,q=void 0===X?c||0:X,G=V.borderTopRightRadius,J=void 0===G?c||0:G,Y=V.borderBottomRightRadius,Q=void 0===Y?c||0:Y,Z=V.borderBottomLeftRadius,K=void 0===Z?c||0:Z;if(a||l||h||d||s){var tt=function(t,e,r){"dashed"==e?/mp/.test(i.platform)?o.setLineDash([Math.ceil(4*t/3),Math.ceil(4*t/3)]):o.setLineDash([Math.ceil(6*t),Math.ceil(6*t)]):"dotted"==e&&o.setLineDash([t,t]),o.setStrokeStyle(r)},et=function(t,e,i,r,n,s,a,h,d,l,c,u,f,g){o.save(),o.setLineWidth(u),tt(u,f,g),o.beginPath(),o.arc(t,e,a,Math.PI*d,Math.PI*l),o.lineTo(i,r),o.arc(n,s,h,Math.PI*l,Math.PI*c),o.stroke(),o.restore()};o.save(),this.setOpacity(e);var it=this.setTransform(t,e),ot=it.x,rt=it.y;s&&(o.setLineWidth(g),tt(g,v,p),this.roundRect(ot,rt,r,n,c,!1,!!p),o.restore()),a&&et(ot+r-Q,rt+n-Q,ot+K,rt+n,ot+K,rt+n-K,Q,K,.25,.5,.75,w,y,z),l&&et(ot+K,rt+n-K,ot,rt+q,ot+q,rt+q,K,q,.75,1,1.25,E,_,N),h&&et(ot+q,rt+q,ot+r-J,rt,ot+r-J,rt+J,q,J,1.25,1.5,1.75,M,P,T),d&&et(ot+r-J,rt+J,ot+r,rt+n-Q,ot+r-Q,rt+n-Q,J,Q,1.75,2,.25,I,C,A)}},t.prototype.setOpacity=function(t){var e=t.opacity,i=void 0===e?1:e;this.ctx.setGlobalAlpha(i)},t.prototype.drawPattern=function(t,e,i){return o(this,void 0,void 0,(function(){var n=this;return r(this,(function(s){return[2,new Promise((function(s,a){var h=n,d=h.ctx,l=h.canvas,c=e.width,u=e.height,f=i||{},g=f.borderRadius,v=void 0===g?0:g,p=f.backgroundColor,b=void 0===p?"transparent":p,m=f.backgroundImage,w=f.backgroundRepeat,x=void 0===w?"repeat":w;d.save(),n.setOpacity(i);var y=n.setTransform(e,i),S=y.x,z=y.y;n.setShadow(i),n.setBackground(b,c,u,S,z),n.roundRect(S,z,c,u,v,!0,!1);var B=function(t){var o=d.createPattern(t.src,x);d.setFillStyle(o),n.roundRect(S,z,c,u,v,!0,!1),n.setBorder(e,i),d.restore(),s()};if(m)if(l.createImage||"web"==n.platform){var R=null;(R=l.createImage?l.createImage():new Image).onload=function(){t.src=R,B(t)},R.onerror=function(){return o(n,void 0,void 0,(function(){return r(this,(function(e){return console.log("createImage fail: "+JSON.stringify(t)),s(),[2]}))}))},R.src=t.path}else B(t)}))]}))}))},t.prototype.drawView=function(t,e,i,o,r){void 0===i&&(i=!0),void 0===o&&(o=!0),void 0===r&&(r=!0);var n=this.ctx,s=t.width,a=t.height,h=e||{},d=h.borderRadius,l=void 0===d?0:d,c=h.backgroundColor,u=void 0===c?"transparent":c;n.save(),this.setOpacity(e);var f=this.setTransform(t,e),g=f.x,v=f.y;r&&this.setShadow(e),i&&this.setBackground(u,s,a,g,v),this.roundRect(g,v,s,a,l,i,!1),n.restore(),o&&this.setBorder(t,e)},t.prototype.drawImage=function(t,e,i,n){return void 0===e&&(e={}),void 0===i&&(i={}),void 0===n&&(n=!0),o(this,void 0,void 0,(function(){var s=this;return r(this,(function(a){switch(a.label){case 0:return[4,new Promise((function(a,h){return o(s,void 0,void 0,(function(){var s,h,d,u,f,g,v,p,b,m,w,x,y,S,z,B,R,M,k,P,O,T,L,W,I,j,C,F=this;return r(this,(function(A){switch(A.label){case 0:return i.boxShadow&&this.drawView(e,Object.assign(i,{backgroundColor:i.backgroundColor||i.boxShadow&&(i.backgroundColor||"#ffffff")}),!0,!1,!0),h=(s=this).ctx,d=s.sleep,u=s.canvas,f=i.borderRadius,g=void 0===f?0:f,v=i.backgroundColor,p=void 0===v?"transparent":v,b=i.objectFit,m=void 0===b?"fill":b,w=i.objectPosition,x=e.width,y=e.height,S=e.left,z=e.top,h.save(),B=e.contentSize.left-e.borderSize.left,R=e.contentSize.top-e.borderSize.top,n||(this.setOpacity(i),M=this.setTransform(e,i),k=M.x,P=M.y,this.setBackground(p,x,y,S,z),S=k,z=P,this.roundRect(S,z,x,y,g,!!g,!1)),S+=B,z+=R,h.clip(),O=function(t){if("fill"!==m){var i=function(t,e,i){var o=t.objectFit,r=t.objectPosition,n=e.width/e.height,s=i.width/i.height,a=1;"contain"==o&&n>=s||"cover"==o&&n=s)&&(a=e.width/i.width);var h=i.width*a,d=i.height*a,c=/^\d+px|rpx$/.test(null==r?void 0:r[0])?l(null==r?void 0:r[0],e.width):(e.width-h)*(/%$/.test(null==r?void 0:r[0])?l(null==r?void 0:r[0],1,!0):{left:0,center:.5,right:1}[(null==r?void 0:r[0])||"center"]),u=/^\d+px|rpx$/.test(null==r?void 0:r[1])?l(null==r?void 0:r[1],e.height):(e.height-d)*(/%$/.test(null==r?void 0:r[1])?l(null==r?void 0:r[1],1,!0):{top:0,center:.5,bottom:1}[(null==r?void 0:r[1])||"center"]),f=function(t,e){return[(t-c)/a,(e-u)/a]},g=f(0,0),v=g[0],p=g[1],b=f(e.width,e.height),m=b[0],w=b[1];return{sx:Math.max(v,0),sy:Math.max(p,0),sw:Math.min(m-v,i.width),sh:Math.min(w-p,i.height),dx:Math.max(c,0),dy:Math.max(u,0),dw:Math.min(h,e.width),dh:Math.min(d,e.height)}}({objectFit:m,objectPosition:w},e.contentSize,t),o=i.sx,r=i.sy,n=i.sh,s=i.sw,a=i.dx,d=i.dy,c=i.dh,u=i.dw;"mp-baidu"==F.platform?h.drawImage(t.src,a+S,d+z,u,c,o,r,s,n):h.drawImage(t.src,o,r,s,n,a+S,d+z,u,c)}else h.drawImage(t.src,S,z,x,y)},T=function(){h.restore(),F.drawView(e,i,!1,!0,!1),setTimeout(a,d)},L=function(t){if(u.createImage||"web"==F.platform){var e=null;(e=u.createImage?u.createImage():new Image).onload=function(){t.src=e,O(t),T()},e.onerror=function(){return o(F,void 0,void 0,(function(){return r(this,(function(e){return console.log("createImage fail: "+JSON.stringify(t)),a(!0),[2]}))}))},e.src=t.path}else O(t),T()},"string"!=typeof t?[3,2]:[4,c(t)];case 1:return W=A.sent(),I=W.path,j=W.width,C=W.height,L({path:I,src:I,width:j,height:C}),[3,3];case 2:L(t),A.label=3;case 3:return[2]}}))}))}))];case 1:return a.sent(),[2]}}))}))},t.prototype.drawText=function(t,e,i,o){this.drawView(e,i);var r=this.ctx,n=e.borderSize,s=e.contentSize,a=s.width,h=s.height,d=s.left-n.left,c=s.top-n.top,u=i.color,f=void 0===u?"#000000":u,g=i.lineHeight,v=void 0===g?"1.4em":g,p=i.fontSize,b=void 0===p?14:p,m=i.fontWeight,w=i.fontFamily,x=i.textStyle,y=i.textAlign,S=void 0===y?"left":y,z=i.verticalAlign,B=void 0===z?"middle":z;i.backgroundColor;var R=i.lineClamp,M=i.textDecoration;if(v=l(v,b),t){r.save(),this.setOpacity(i);var k=this.setTransform(e,i),P=k.x,O=k.y;switch(P+=d,O+=c,r.setFonts({fontFamily:w,fontSize:b,fontWeight:m,textStyle:x}),r.setTextBaseline("middle"),r.setTextAlign(S),r.setFillStyle(f),O+=b/2,S){case"left":break;case"center":P+=.5*a;break;case"right":P+=a}var T=o.lines*v,L=Math.ceil((h-T)/2);switch(L<0&&(L=0),B){case"top":break;case"middle":O+=L;break;case"bottom":O+=2*L}var W=(v-o.fontHeight)/2,I=function(t,e,i){var n=t;switch(S){case"left":t=t,n+=i;break;case"center":n=(t-=i/2)+i;break;case"right":n=t,t-=i}M&&(r.setLineWidth(b/13),r.beginPath(),e-=W,/\bunderline\b/.test(M)&&(r.moveTo(t,e-.5*o.fontHeight),r.lineTo(n,e-.5*o.fontHeight)),/\boverline\b/.test(M)&&(r.moveTo(t,e-1.5*o.fontHeight),r.lineTo(n,e-1.5*o.fontHeight)),/\bline-through\b/.test(M)&&(r.moveTo(t,e-o.fontHeight),r.lineTo(n,e-o.fontHeight)),r.closePath(),r.setStrokeStyle(f),r.stroke())};if(1==o.widths.lenght&&o.widths[0].total<=s.width)return r.fillText(t,P,O+W),I(P,O+=v,o.widths[0].total),r.restore(),void this.setBorder(e,i);for(var j=t.split(""),C=O,F=P,A="",H=0,$=0;$<=j.length;$++){var E=j[$]||"",U="\n"===E,_=""==E,D=A+(E=U?"":E),N=r.measureText(D).width;if(H>=R)break;if(F=P,(N=N)>s.width||U||_){if(H++,A=_&&N<=s.width?D:A,H===R&&N>a){for(;r.measureText(A+"...").width>s.width&&!(A.length<=1);)A=A.substring(0,A.length-1);A+="..."}if(r.fillText(A,F,O+W),I(F,O+=v,N),A=E,O+v>C+h)break}else A=D}r.restore()}},t.prototype.source=function(t){var e;return o(this,void 0,void 0,(function(){var i,o;return r(this,(function(r){switch(r.label){case 0:if("{}"==JSON.stringify(t))return[2];if(!t.type)for(i in t.type="view",t.css=t.css||{},t)["views","children","type","css"].includes(i)||(t.css[i]=t[i],delete t[i]);return(null===(e=null==t?void 0:t.css)||void 0===e?void 0:e.width)||(t.css?t.css.width=this.root.width:t.css={width:this.root.width}),[4,this.create(t)];case 1:return o=r.sent(),this.size=o.layout(),this.node=o,[2,this.size]}}))}))},t.prototype.create=function(t,e){var i,n,s,a;return o(this,void 0,void 0,(function(){var o,h,d,l,u,f,g,v,p,b,m,x;return r(this,(function(r){switch(r.label){case 0:if("image"==t.type&&!t.src&&!t.url||"qrcode"==t.type&&!t.text)return[2];if("none"==(null===(i=null==t?void 0:t.css)||void 0===i?void 0:i.display))return console.error("element display none"),[2];r.label=1;case 1:return r.trys.push([1,4,,5]),"image"==t.type||"view"==t.type&&(null===(n=t.css)||void 0===n?void 0:n.backgroundImage)?(o=null,h=/url\((.+)\)/,t.css.backgroundImage&&(null===(s=h.exec(t.css.backgroundImage))||void 0===s?void 0:s[1])&&(o=null===(a=h.exec(t.css.backgroundImage))||void 0===a?void 0:a[1]),[4,c(t.src||o)]):[3,3];case 2:d=r.sent(),l=d.width,u=d.height,f=d.path,["mp-weixin","mp-baidu","mp-qq","mp-toutiao"].includes(this.platform)&&(f=/^\.|^\/(?=[^\/])/.test(t.src||o)?"/"+f:f),t.attributes=Object.assign(t.attributes||{},{width:l,height:u,path:f,src:f,naturalSrc:t.src||o}),r.label=3;case 3:return[3,5];case 4:return g=r.sent(),console.log(g),[2];case 5:if(this.count+=1,v=new w(t,e,this.root,this.ctx),!(p=t.views||t.children))return[3,9];b=0,r.label=6;case 6:return b /^data:image\/(\w+);base64/.test(path); +export function sleep(delay) { + return new Promise(resolve => setTimeout(resolve, delay)) +} +const isDev = ['devtools'].includes(uni.getSystemInfoSync().platform) +// 缓存图片 +let cache = {} +export function isNumber(value) { + return /^-?\d+(\.\d+)?$/.test(value); +} +export function toPx(value, baseSize, isDecimal = false) { + // 如果是数字 + if (typeof value === 'number') { + return value + } + // 如果是字符串数字 + if (isNumber(value)) { + return value * 1 + } + // 如果有单位 + if (typeof value === 'string') { + const reg = /^-?([0-9]+)?([.]{1}[0-9]+){0,1}(em|rpx|px|%)$/g + const results = reg.exec(value); + if (!value || !results) { + return 0; + } + const unit = results[3]; + value = parseFloat(value); + let res = 0; + if (unit === 'rpx') { + res = uni.upx2px(value); + } else if (unit === 'px') { + res = value * 1; + } else if (unit === '%') { + res = value * toPx(baseSize) / 100; + } else if (unit === 'em') { + res =value * toPx(baseSize || 14); + } + return isDecimal ? res.toFixed(2) * 1 : Math.round(res); + } + return 0 +} + +// 计算版本 +export function compareVersion(v1, v2) { + v1 = v1.split('.') + v2 = v2.split('.') + const len = Math.max(v1.length, v2.length) + while (v1.length < len) { + v1.push('0') + } + while (v2.length < len) { + v2.push('0') + } + for (let i = 0; i < len; i++) { + const num1 = parseInt(v1[i], 10) + const num2 = parseInt(v2[i], 10) + + if (num1 > num2) { + return 1 + } else if (num1 < num2) { + return -1 + } + } + return 0 +} +// #ifdef MP +export const prefix = () => { + // #ifdef MP-TOUTIAO + return tt + // #endif + // #ifdef MP-WEIXIN + return wx + // #endif + // #ifdef MP-BAIDU + return swan + // #endif + // #ifdef MP-ALIPAY + return my + // #endif + // #ifdef MP-QQ + return qq + // #endif + // #ifdef MP-360 + return qh + // #endif +} +// #endif + +const base64ToArrayBuffer = (data) => { + // #ifndef MP-WEIXIN || APP-PLUS + /** + * Base64Binary.decode(base64_string); + * Base64Binary.decodeArrayBuffer(base64_string); + */ + const Base64Binary = { + _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", + /* will return a Uint8Array type */ + decodeArrayBuffer(input) { + const bytes = (input.length/4) * 3; + const ab = new ArrayBuffer(bytes); + this.decode(input, ab); + return ab; + }, + removePaddingChars(input) { + const lkey = this._keyStr.indexOf(input.charAt(input.length - 1)); + if(lkey == 64){ + return input.substring(0,input.length - 1); + } + return input; + }, + decode(input, arrayBuffer) { + //get last chars to see if are valid + input = this.removePaddingChars(input); + input = this.removePaddingChars(input); + + const bytes = parseInt((input.length / 4) * 3, 10); + + let uarray; + let chr1, chr2, chr3; + let enc1, enc2, enc3, enc4; + let i = 0; + let j = 0; + + if (arrayBuffer) + uarray = new Uint8Array(arrayBuffer); + else + uarray = new Uint8Array(bytes); + + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + for (i=0; i> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + uarray[i] = chr1; + if (enc3 != 64) uarray[i+1] = chr2; + if (enc4 != 64) uarray[i+2] = chr3; + } + return uarray; + } + } + return Base64Binary.decodeArrayBuffer(data) + // #endif + // #ifdef MP-WEIXIN || APP-PLUS + return uni.base64ToArrayBuffer(data) + // #endif +} + + +/** + * base64转路径 + * @param {Object} base64 + */ +export function base64ToPath(base64) { + const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || []; + + return new Promise((resolve, reject) => { + // #ifdef MP + const fs = uni.getFileSystemManager() + //自定义文件名 + if (!format) { + console.error('ERROR_BASE64SRC_PARSE') + reject(new Error('ERROR_BASE64SRC_PARSE')) + } + const time = new Date().getTime(); + let pre = prefix() + const filePath = `${pre.env.USER_DATA_PATH}/${time}.${format}` + //let buffer = base64ToArrayBuffer(bodyData) + console.log(filePath) + fs.writeFile({ + filePath, + data: base64.replace(/^data:\S+\/\S+;base64,/, ''), + encoding: 'base64', + // data: buffer, + // encoding: 'binary', + success() { + resolve(filePath) + }, + fail(err) { + + console.log(base64,'!!!!!!') + console.error('获取base64图片失败', JSON.stringify(err)) + reject(err) + } + }) + // #endif + + // #ifdef H5 + // mime类型 + let mimeString = base64.split(',')[0].split(':')[1].split(';')[0]; + //base64 解码 + let byteString = atob(base64.split(',')[1]); + //创建缓冲数组 + let arrayBuffer = new ArrayBuffer(byteString.length); + //创建视图 + let intArray = new Uint8Array(arrayBuffer); + for (let i = 0; i < byteString.length; i++) { + intArray[i] = byteString.charCodeAt(i); + } + resolve(URL.createObjectURL(new Blob([intArray], { type: mimeString }))) + // #endif + + // #ifdef APP-PLUS + const bitmap = new plus.nativeObj.Bitmap('bitmap' + Date.now()) + bitmap.loadBase64Data(base64, () => { + if (!format) { + reject(new Error('ERROR_BASE64SRC_PARSE')) + } + const time = new Date().getTime(); + const filePath = `_doc/uniapp_temp/${time}.${format}` + bitmap.save(filePath, {}, + () => { + bitmap.clear() + resolve(filePath) + }, + (error) => { + bitmap.clear() + console.error(`${JSON.stringify(error)}`) + reject(error) + }) + }, (error) => { + bitmap.clear() + console.error(`${JSON.stringify(error)}`) + reject(error) + }) + // #endif + }) +} + +/** + * 路径转base64 + * @param {Object} string + */ +export function pathToBase64(path) { + if(/^data:/.test(path)) return path + return new Promise((resolve, reject) => { + // #ifdef H5 + const _canvas = ()=> { + let image = new Image(); + image.setAttribute("crossOrigin",'Anonymous'); + image.onload = function() { + let canvas = document.createElement('canvas'); + // 获取图片原始宽高 + canvas.width = this.naturalWidth; + canvas.height = this.naturalHeight; + // 将图片插入画布并开始绘制 + canvas.getContext('2d').drawImage(image, 0, 0); + let result = canvas.toDataURL('image/png') + resolve(result); + canvas.height = canvas.width = 0 + } + image.src = path + image.onerror = (error) => { + console.error(`urlToBase64 error: ${path}`, JSON.stringify(error)) + reject(new Error('urlToBase64 error')); + }; + } + const _fileReader = (blob) => { + const fileReader = new FileReader(); + fileReader.onload = (e) => { + resolve(e.target.result); + }; + fileReader.readAsDataURL(blob); + fileReader.onerror = (error) => { + console.error('blobToBase64 error:', JSON.stringify(error)) + reject(new Error('blobToBase64 error')); + }; + } + const isFileReader = typeof FileReader === 'function' + if(networkReg.test(path) && isFileReader ) { + window.URL = window.URL || window.webkitURL; + const xhr = new XMLHttpRequest(); + xhr.open("get", path, true); + xhr.timeout = 2000; + xhr.responseType = "blob"; + xhr.onload = function() { + if(this.status == 200) { + _fileReader(this.response) + } else { + _canvas() + } + } + xhr.onreadystatechange = function() { + if(this.status === 0) { + console.error('图片跨域了,得后端处理咯') + } + } + xhr.send(); + } else if(/^blob/.test(path) && isFileReader){ + _fileReader(path) + } else { + _canvas() + } + // #endif + + // #ifdef MP + if(uni.canIUse('getFileSystemManager')) { + uni.getFileSystemManager().readFile({ + filePath: path, + encoding: 'base64', + success: (res) => { + resolve('data:image/png;base64,' + res.data) + }, + fail: (error) => { + console.error('urlToBase64 error:', JSON.stringify(error)) + reject(error) + } + }) + } + // #endif + + // #ifdef APP-PLUS + plus.io.resolveLocalFileSystemURL(getLocalFilePath(path), (entry) => { + entry.file((file) => { + const fileReader = new plus.io.FileReader() + fileReader.onload = (data) => { resolve(data.target.result)} + fileReader.onerror = (error) => { + console.error('pathToBase64 error:', JSON.stringify(error)) + reject(error) + } + fileReader.readAsDataURL(file) + }, (error) => { + console.error('pathToBase64 error:', JSON.stringify(error)) + reject(error) + }) + }, (error) => { + console.error('pathToBase64 error:', JSON.stringify(error)) + reject(error) + }) + // #endif + }) +} + +// #ifdef APP-PLUS +const getLocalFilePath = (path)=> { + if (path.indexOf('_www') === 0 || path.indexOf('_doc') === 0 || path.indexOf('_documents') === 0 || path.indexOf('_downloads') === 0) { + return path + } + if (path.indexOf('file://') === 0) { + return path + } + if (path.indexOf('/storage/emulated/0/') === 0) { + return path + } + if (path.indexOf('/') === 0) { + const localFilePath = plus.io.convertAbsoluteFileSystem(path) + if (localFilePath !== path) { + return localFilePath + } else { + path = path.substr(1) + } + } + return '_www/' + path +} +// #endif + +export function getImageInfo(img, isH5PathToBase64 = false) { + return new Promise(async (resolve, reject) => { + // const base64Reg = /^data:image\/(\w+);base64/ + const localReg = /^\.|^\/(?=[^\/])/; + // #ifdef H5 + if(networkReg.test(img) && isH5PathToBase64) { + img = await pathToBase64(img) + } + // #endif + // #ifndef MP-ALIPAY + if(isBase64(img)) { + + if(isDev || !cache[img]) { + const imgName = img + img = await base64ToPath(img) + cache[imgName] = img + } else { + img = cache[img] + } + } + // #endif + if(cache[img] && cache[img].errMsg) { + resolve(cache[img]) + } else { + uni.getImageInfo({ + src: img, + success: (image) => { + // #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO + image.path = localReg.test(img) ? `/${image.path}` : image.path; + // #endif + // #ifdef H5 + image.path = image.path.replace(/^\./, window.location.origin) + // #endif + image.naturalSrc = img + if(isDev) { + resolve(image) + } else { + cache[img] = image + resolve(cache[img]) + } + }, + fail(err) { + resolve({path: img}) + console.error(`getImageInfo:fail ${img} failed ${JSON.stringify(err)}`); + } + }) + } + }) +} \ No newline at end of file diff --git a/components/lime-painter/components/lime-painter/index.vue b/components/lime-painter/components/lime-painter/index.vue new file mode 100644 index 0000000..e69de29 diff --git a/components/lime-painter/readme.md b/components/lime-painter/readme.md new file mode 100644 index 0000000..90e0a1d --- /dev/null +++ b/components/lime-painter/readme.md @@ -0,0 +1,756 @@ +# Painter 画板 测试版 +> uniapp 海报画板,更优雅的海报生成方案 +> [查看更多 站点1](https://limeui.qcoon.cn/#/painter) +> [查看更多 站点2](http://liangei.gitee.io/limeui/#/painter) +> Q群:806744170 + +## 平台兼容 +| H5 | 微信小程序 | 支付宝小程序 | 百度小程序 | 头条小程序 | QQ 小程序 | App | +| --- | ---------- | ------------ | ---------- | ---------- | --------- | --- | +| √ | √ | √ | 未测 | √ | √ | √ | + + +## 代码演示 +### 基本用法 +- 插件提供JSON及HTML的方式绘制海报 +- 插件参考了 css 块状流布局模拟css schema方式,放弃了之前使用的绝对定位布局。 + +#### 方式一 HTML +- 插件提供了`l-painter-view`、`l-painter-text`、`l-painter-image`、`l-painter-qrcode`四种类型组件 +- 通过 `css` 属性绘制样式,与style使用方式保持一致。 因为style是保留字段,所以命名为`css`,如果有大佬知道如何破解请告之。 + + +```html + + + + + +``` + +#### 方式二 JSON schema +- 在json里四种类型组件的`type`为`view`、`text`、`image`、`qrcode` +- 通过 `board` 设置海报所需的 JSON schema 数据进行绘制 +- 所有类型的schema都具有`css`字段,css的样式属性key值使用驼峰命名如:`lineHeight` + + +```html + +``` +```js +data() { + return { + poster: { + css: { + // json 方式务必填写画板宽度 + width: '750rpx' + }, + views: [ + { + css: { + background: "#07c160", + height: "120rpx", + width: "120rpx", + display: "inline-block" + }, + type: "view" + }, + { + css: { + background: "#1989fa", + height: "120rpx", + width: "120rpx", + borderTopRightRadius: "60rpx", + borderBottomLeftRadius: "60rpx", + display: "inline-block", + margin: "0 30rpx" + }, + views: [], + type: "view" + }, + { + css: { + background: "#ff9d00", + height: "120rpx", + width: "120rpx", + borderRadius: "50%", + display: "inline-block" + }, + views: [], + type: "view" + }, + ] + } + } +} +``` + +### View 容器 +- 类似于 `div` 可以嵌套承载更多的 view、text、image,qrcode共同构建一颗完整的节点树 +- 在JSON schema里具有 `views` 的数组字段,用于嵌套承载节点。 + + +#### 方式一 HTML + + +```html + + + + + + +``` +#### 方式二 JSON schema + + +```js +{ + css: { + width: '750rpx' + }, + views: [ + { + type: 'view', + css: { + background: '#f0f0f0', + paddingTop: '100rpx' + }, + views: [ + { + type: 'view', + css: { + background: '#d9d9d9', + width: '33.33%', + height: '100rpx', + display: 'inline-block' + } + }, + { + type: 'view', + css: { + background: '#bfbfbf', + width: '66.66%', + height: '100rpx', + display: 'inline-block' + } + } + ], + + } + ] +} +``` + +### Text 文本 +- 通过 `text` 属性填写文本内容。 +- 支持`\n`换行符 +- 支持省略号,使用css的`line-clamp`设置行数,当文字内容超过会显示省略号。 +- 支持`text-decoration` + +#### 方式一 HTML +```html + + + + + + + + +``` +#### 方式二 JSON schema +```js +// 基础用法 +{ + type: 'text', + text: '登鹳雀楼\n白日依山尽,黄河入海流\n欲穷千里目,更上一层楼', +}, +{ + type: 'text', + text: '登鹳雀楼\n白日依山尽,黄河入海流\n欲穷千里目,更上一层楼', + css: { + // 设置居中对齐 + textAlign: 'center', + // 设置中划线 + textDecoration: 'line-through' + } +}, +{ + type: 'text', + text: '登鹳雀楼\n白日依山尽,黄河入海流\n欲穷千里目,更上一层楼', + css: { + // 设置右对齐 + textAlign: 'right', + } +}, +{ + type: 'text', + text: '登鹳雀楼\n白日依山尽,黄河入海流\n欲穷千里目,更上一层楼', + css: { + // 设置行数,超出显示省略号 + lineClamp: 3, + } +} +``` + +### Image 图片 +- 通过 `src` 属性填写图片路径。 +- 图片路径支持:网络图片,本地static里的图片路径,缓存路径 +- 通过 `css` 的 `object-fit`属性可以设置图片的填充方式,可选值见下方CSS表格。 +- 通过 `css` 的 `object-position`配合 `object-fit` 可以设置图片的对齐方式,类似于`background-position`,详情见下方CSS表格。 +- 使用网络图片时:小程序需要去公众平台配置 [downloadFile](https://mp.weixin.qq.com/) 域名 +- 使用网络图片时:**H5需要决跨域问题** + +#### 方式一 HTML +```html + + + + + + + + + + +``` +#### 方式二 JSON schema +```js +// 基础用法 +{ + type: 'image', + src: 'https://m.360buyimg.com/babel/jfs/t1/196317/32/13733/288158/60f4ea39E6fb378ed/d69205b1a8ed3c97.jpg', + css: { + width: '200rpx', + height: '200rpx' + } +}, +// 填充方式 +// css objectFit 设置 填充方式 见下方表格 +{ + type: 'image', + src: 'https://m.360buyimg.com/babel/jfs/t1/196317/32/13733/288158/60f4ea39E6fb378ed/d69205b1a8ed3c97.jpg', + css: { + width: '200rpx', + height: '200rpx', + objectFit: 'contain' + } +}, +// css objectPosition 设置 图片的对齐方式 +{ + type: 'image', + src: 'https://m.360buyimg.com/babel/jfs/t1/196317/32/13733/288158/60f4ea39E6fb378ed/d69205b1a8ed3c97.jpg', + css: { + width: '200rpx', + height: '200rpx', + objectFit: 'contain', + objectPosition: '50% 50%' + } +} +``` +### Qrcode 二维码 +- 通过`text`属性填写需要生成二维码的文本。 +- 通过 `css` 里的 `color` 可设置生成码点的颜色。 +- 通过 `css` 里的 `background`可设置背景色。 +- 通过 `css `里的 `width`、`height`设置尺寸。 + + +#### 方式一 HTML +```html + + + +``` +#### 方式二 JSON schema +```js +{ + type: 'qrcode', + text: 'limeui.qcoon.cn', + css: { + width: '200rpx', + height: '200rpx', + } +} +``` +### 生成图片 +- 1、通过设置`isCanvasToTempFilePath`自动生成图片并在 `@success` 事件里接收海报临时路径 +- 2、通过调用内部方法生成图片: + + +```html +...code +``` +```js +// 主动调用方式只能在绘制完成之后 +// @done 事件表示绘制完成 +this.$refs.painter.canvasToTempFilePath({ + // 在nvue里是jpeg + fileType: 'jpg', + quality: 1, + success: (res) => { + console.log(res.tempFilePath) + } +}) +``` + + +### 海报示例 +- 提供一份示例,只把插件当成生成图片的工具,弹窗之类的功能另外寻找。 +- 通过设置`isCanvasToTempFilePath`主动生成图片,再由 `@success` 事件接收海报临时路径 +- 使用`custom-style`样式把画板移到屏幕之外,因为可能canvas的层级比较高,无法覆盖。 +- **注意**:海报画板不能隐藏 否则无法生成图片。 + +#### 方式一 HTML +```html + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +```js +data() { + return { + path: '' + } +} +``` +#### 方式二 JSON schema +```html + + +``` +```js +data() { + return { + path: '', + poster: { + css: { + width: "750rpx", + paddingBottom: "40rpx", + background: "linear-gradient(,#000 0%, #ff5000 100%)" + }, + views: [ + { + src: "https://cdn.jsdelivr.net/gh/liangei/image@latest/avatar-1.jpeg", + type: "image", + css: { + background: "#fff", + objectFit: "cover", + marginLeft: "40rpx", + marginTop: "40rpx", + width: "84rpx", + border: "2rpx solid #fff", + boxSizing: "border-box", + height: "84rpx", + borderRadius: "50%" + } + }, + { + type: "view", + css: { + marginTop: "40rpx", + paddingLeft: "20rpx", + display: "inline-block" + }, + views: [ + { + text: "隔壁老王", + type: "text", + css: { + display: "block", + paddingBottom: "10rpx", + color: "#fff", + fontSize: "32rpx", + fontWeight: "bold" + } + }, + { + text: "为您挑选了一个好物", + type: "text", + css: { + color: "rgba(255,255,255,.7)", + fontSize: "24rpx" + }, + } + ], + }, + { + css: { + marginLeft: "40rpx", + marginTop: "30rpx", + padding: "32rpx", + boxSizing: "border-box", + background: "#fff", + borderRadius: "16rpx", + width: "670rpx", + boxShadow: "0 20rpx 58rpx rgba(0,0,0,.15)" + }, + views: [ + { + src: "https://m.360buyimg.com/babel/jfs/t1/196317/32/13733/288158/60f4ea39E6fb378ed/d69205b1a8ed3c97.jpg", + type: "image", + css: { + objectFit: "cover", + objectPosition: "50% 50%", + width: "606rpx", + height: "606rpx" + }, + }, { + css: { + marginTop: "32rpx", + color: "#FF0000", + fontWeight: "bold", + fontSize: "28rpx", + lineHeight: "1em" + }, + views: [{ + text: "¥", + type: "text", + css: { + verticalAlign: "bottom" + }, + }, { + text: "39", + type: "text", + css: { + verticalAlign: "bottom", + fontSize: "58rpx" + }, + }, { + text: ".39", + type: "text", + css: { + verticalAlign: "bottom" + }, + }, { + text: "¥59.99", + type: "text", + css: { + verticalAlign: "bottom", + paddingLeft: "10rpx", + fontWeight: "normal", + textDecoration: "line-through", + color: "#999999" + } + }], + + type: "view" + }, { + css: { + marginTop: "32rpx", + fontSize: "26rpx", + color: "#8c5400" + }, + views: [{ + text: "自营", + type: "text", + css: { + color: "#212121", + background: "#ffb400" + }, + }, { + text: "30天最低价", + type: "text", + css: { + marginLeft: "16rpx", + background: "#fff4d9", + textDecoration: "line-through" + }, + }, { + text: "满减优惠", + type: "text", + css: { + marginLeft: "16rpx", + background: "#fff4d9" + }, + }, { + text: "超高好评", + type: "text", + css: { + marginLeft: "16rpx", + background: "#fff4d9" + }, + + }], + + type: "view" + }, { + css: { + marginTop: "30rpx" + }, + views: [ + { + text: "360儿童电话手表9X 智能语音问答定位支付手表 4G全网通20米游泳级防水视频通话拍照手表男女孩星空蓝", + type: "text", + css: { + paddingRight: "32rpx", + boxSizing: "border-box", + lineClamp: 2, + color: "#333333", + lineHeight: "1.8em", + fontSize: "36rpx", + width: "478rpx" + }, + }, { + text: "limeui.qcoon.cn", + type: "qrcode", + css: { + width: "128rpx", + height: "128rpx", + }, + + }], + type: "view" + }], + type: "view" + } + ] + } + } +} +``` + +### 原生小程序 +- 插件里的`painter.js`支持在原生小程序中使用 +- new Painter之后在`source`里传入JSON schema +- 再调用`render`绘制海报 +- 如需生成图片,请查看微信小程序cavnas的[canvasToTempFilePath](https://developers.weixin.qq.com/miniprogram/dev/api/canvas/wx.canvasToTempFilePath.html) + +```html + +``` +```js +import {Painter} from './painter' +page({ + data: { + poster: { + css: { + width: '750rpx' + }, + views: [ + { + type: 'view', + css: { + background: '#d2d4c8', + paddingTop: '100rpx' + }, + views: [ + { + type: 'view', + css: { + background: '#5f7470', + width: '33.33%', + height: '100rpx', + display: 'inline-block' + } + }, + { + type: 'view', + css: { + background: '#889696', + width: '33.33%', + height: '100rpx', + display: 'inline-block' + } + }, + { + type: 'view', + css: { + background: '#b8bdb5', + width: '33.33%', + height: '100rpx', + display: 'inline-block' + } + } + ], + + } + ] + } + }, + async onLoad() { + const res = await this.getCentext() + const painter = new Painter(res) + // 返回计算布局后的整个内容尺寸 + const {width, height} = await painter.source(this.data.poster) + // 得到计算后的尺寸后 可给canvas尺寸赋值,达到动态响应效果 + // 渲染 + await painter.render() + }, + // 获取canvas 2d + // 非2d也可以使用这里只是举个例子 + getCentext() { + return new Promise(resolve => { + wx.createSelectorQuery() + .select(`#painter`) + .node() + .exec(res => { + let { node: canvas } = res[0]; + resolve({ + canvas, + context: canvas.getContext('2d'), + width: canvas.width, + height: canvas.height, + pixelRatio: 2 + }) + }) + }) + }, +}) +``` +### Nvue +- 插件是通过 `web-view` 支持 `app-nvue` +- 默认是远端的文件,如果需要本地化,请按下方步骤: +- 1、去码云把[hybrid](https://gitee.com/liangei/lime-painter/tree/master/examples/uni/hybrid)目录的文件,放到自己项目的根目录。 +- 2、给插件文件`l-painter.vue`里`web-view`的`src`加上根目录的`hybrid路径`并注释`this.webViewInit()` + + +```html +// 只加上路径 其它参数不要改 + +``` +```js +// 153行 注释该方法 +// this.webViewInit() +``` + +### 旧版更新(1.6.x) +- 由于1.8.x版放弃了以定位的方式,所以1.6.x版更新之后要每个样式都加上`position: absolute` +- 旧版的 `image` mode 模式被放弃,使用`object-fit` +- 旧版的 `isRenderImage` 改成 `is-canvas-to-temp-filePath` +- 旧版的 `maxLines` 改成 `line-clamp` + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| ------------- | ------------ | ---------------- | ------------ | +| board | JSON schema方式的海报元素对象集 | object | - | +| css | 海报最外层的样式,可以理解为`body` | object | 参数请向下看 | +| custom-style | canvas自定义样式 | string | | +| is-canvas-to-temp-filePath | 是否生成图片,在`@success`事件接收图片地址 | boolean | `false` | +| after-delay | 生成图片错乱,可延时生成图片 | number | `100` | +| type | canvas 类型,对微信头条支付宝小程序可有效,可选值:`2d`、`` | string | `2d` | +| file-type | 生成图片的后缀类型, 可选值:`png`、`jpg`,在nvue里是`jpeg` | string | `png` | +| path-type | 生成图片路径类型,可选值`url`、`base64` | string | `-` | +| pixel-ratio | 生成图片的像素密度,默认为对应手机的像素密度 | number | `-` | + + + +### css +| 属性名 | 支持的值或类型 | 默认值 | +| ------------- | ------------ | ---------------- | +| (min\max)width | 支持`%`、`rpx`、`px` | - | +| height | 同上 | - | +| color | `string` | - | +| position | 定位,可选值:`absolute`、`fixed` | - | +| ↳ left、top、right、bottom | 配合`position`才生效,支持`%`、`rpx`、`px` | - | +| margin | 可简写或各方向分别写,如:`margin-top`,支持`auto`、`rpx`、`px` | - | +| padding | 可简写或各方向分别写,支持`rpx`、`px` | - | +| border | 可简写或各个值分开写:`border-width`、`border-style` 、`border-color`,简写请按顺序写| - | +| line-clamp | `number`,超过行数显示省略号 | - | +| background | 支持渐变,但必须写百分比!如:`linear-gradient(,#ff971b 0%, #ff5000 100%)`、`radial-gradient(#0ff 15%, #f0f 60%)`,目前radial-gradient 渐变的圆心为元素中点,半径为最长边,不支持设置 | - | +| vertical-align | 文字垂直对齐,可选值:`bottom`、`top`、`middle` | `middle` | +| line-height | 文字行高,支持`rpx`、`px`、`em`| `1.4em` | +| font-weight | 文字粗细,可选值:`normal`、`bold`| `normal` | +| font-size | 文字大小,`string`,支持`rpx`、`px` | `14px` | +| text-decoration | 文本修饰,可选值:`underline` 、`line-through`、`overline`| - | +| text-align | 文本水平对齐,可选值:`right` 、`center`| - | +| display | 框类型,可选值:`block`、`inline-block`、`none`,当为`none`时是不渲染该段 | - | +| border-radius | 圆角边框,支持`%`、`rpx`、`px` | - | +| box-sizing | 可选值:`border-box` | - | +| box-shadow | 投影 | - | +| background-image | view元素设置背景纹理,注意这里的背景纹理一般是用于纹理平铺,无法代替`image`元素。如:水印 | - | +| background-repeat | 设置是否及如何重复背景纹理,可选值:`repeat`、`repeat-x`、`repeat-y`、`no-repeat` | `repeat` | +| [object-fit](https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-fit/) | 图片元素适应容器方式,类似于`mode`,可选值:`cover`、 `contain`、 `fill`、 `none` | - | +| [object-position](https://developer.mozilla.org/zh-CN/docs/Web/CSS/object-position) | 图片的对齐方式,配合`object-fit`使用 | - | + +### 图片填充模式 object-fit +| 名称 | 含义 | +| ------- | ------------ | +| contain | 保持宽高缩放图片,使图片的长边能完全显示出来 | +| cover | 保持宽高缩放图片,使图片的短边能完全显示出来,裁剪长边 | +| fill | 拉伸图片,使图片填满元素 | +| none | 保持图片原有尺寸 | + +### 事件 Events + +| 事件名 | 说明 | 回调 | +| ------- | ------------ | -------------- | +| success | 生成图片成功,若使用了`is-canvas-to-temp-filePath` 可以接收图片地址 | path | +| fail | 生成图片失败 | {error: error} | +| done | 绘制成功 | | +| progress | 绘制进度 | number | + +## 常见问题 +- 1、H5端使用网络图片需要解决跨域问题。 +- 2、小程序使用网络图片需要去公众平台增加下载白名单!二级域名也需要配! +- 3、H5端生成图片是base64,有时显示只有一半可以使用原生标签`` +- 4、发生保存图片倾斜变形或提示native buffer exceed size limit时,使用pixel-ratio="2"参数,降分辨率。 +- 5、h5保存图片不需要调接口,提示用户长按图片保存。 +- 6、IOS APP 请勿使用HBX2.9.3.20201014的版本!这个版本无法生成图片。 +- 7、组件不能隐藏,包含`v-if`,`v-show`、`display:none`、`opacity:0` +- 8、微信小程序 canvas 2d不支持真机调试,请使用真机预览方式。 +- 9、华为手机APP上无法生成图片,请使用HBX2.9.11++ +- 10、苹果微信7.0.20存在闪退和图片无法onload为微信bug,请到码云上升级本插件 + +## 打赏 +如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。 + +![输入图片说明](https://cdn.jsdelivr.net/gh/liangei/image@latest/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg") \ No newline at end of file diff --git a/components/live-item/live-item.vue b/components/live-item/live-item.vue new file mode 100644 index 0000000..a2dc489 --- /dev/null +++ b/components/live-item/live-item.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/components/loading-footer/loading-footer.vue b/components/loading-footer/loading-footer.vue new file mode 100644 index 0000000..dc2015c --- /dev/null +++ b/components/loading-footer/loading-footer.vue @@ -0,0 +1,63 @@ + + + + \ No newline at end of file diff --git a/components/loading-view/loading-view.vue b/components/loading-view/loading-view.vue new file mode 100644 index 0000000..e6ebad0 --- /dev/null +++ b/components/loading-view/loading-view.vue @@ -0,0 +1,51 @@ + + + + \ No newline at end of file diff --git a/components/lyg-popup/lyg-popup.vue b/components/lyg-popup/lyg-popup.vue new file mode 100644 index 0000000..dde0dd1 --- /dev/null +++ b/components/lyg-popup/lyg-popup.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/components/mescroll-uni/components/mescroll-down.css b/components/mescroll-uni/components/mescroll-down.css new file mode 100644 index 0000000..72bf106 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-down.css @@ -0,0 +1,55 @@ +/* 下拉刷新区域 */ +.mescroll-downwarp { + position: absolute; + top: -100%; + left: 0; + width: 100%; + height: 100%; + text-align: center; +} + +/* 下拉刷新--内容区,定位于区域底部 */ +.mescroll-downwarp .downwarp-content { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + min-height: 60rpx; + padding: 20rpx 0; + text-align: center; +} + +/* 下拉刷新--提示文本 */ +.mescroll-downwarp .downwarp-tip { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + margin-left: 16rpx; + /* color: gray; 已在style设置color,此处删去*/ +} + +/* 下拉刷新--旋转进度条 */ +.mescroll-downwarp .downwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-downwarp .mescroll-rotate { + animation: mescrollDownRotate 0.6s linear infinite; +} + +@keyframes mescrollDownRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/components/mescroll-down.vue b/components/mescroll-uni/components/mescroll-down.vue new file mode 100644 index 0000000..9fd1567 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-down.vue @@ -0,0 +1,47 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-empty.vue b/components/mescroll-uni/components/mescroll-empty.vue new file mode 100644 index 0000000..e7ea8e9 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-empty.vue @@ -0,0 +1,90 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-top.vue b/components/mescroll-uni/components/mescroll-top.vue new file mode 100644 index 0000000..bf5ae29 --- /dev/null +++ b/components/mescroll-uni/components/mescroll-top.vue @@ -0,0 +1,83 @@ + + + + + + diff --git a/components/mescroll-uni/components/mescroll-up.css b/components/mescroll-uni/components/mescroll-up.css new file mode 100644 index 0000000..cbf48cd --- /dev/null +++ b/components/mescroll-uni/components/mescroll-up.css @@ -0,0 +1,47 @@ +/* 上拉加载区域 */ +.mescroll-upwarp { + box-sizing: border-box; + min-height: 110rpx; + padding: 30rpx 0; + text-align: center; + clear: both; +} + +/*提示文本 */ +.mescroll-upwarp .upwarp-tip, +.mescroll-upwarp .upwarp-nodata { + display: inline-block; + font-size: 28rpx; + vertical-align: middle; + /* color: gray; 已在style设置color,此处删去*/ +} + +.mescroll-upwarp .upwarp-tip { + margin-left: 16rpx; +} + +/*旋转进度条 */ +.mescroll-upwarp .upwarp-progress { + display: inline-block; + width: 32rpx; + height: 32rpx; + border-radius: 50%; + border: 2rpx solid gray; + border-bottom-color: transparent !important; /*已在style设置border-color,此处需加 !important*/ + vertical-align: middle; +} + +/* 旋转动画 */ +.mescroll-upwarp .mescroll-rotate { + animation: mescrollUpRotate 0.6s linear infinite; +} + +@keyframes mescrollUpRotate { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/components/mescroll-up.vue b/components/mescroll-uni/components/mescroll-up.vue new file mode 100644 index 0000000..11c2e1f --- /dev/null +++ b/components/mescroll-uni/components/mescroll-up.vue @@ -0,0 +1,39 @@ + + + + + + diff --git a/components/mescroll-uni/mescroll-body.css b/components/mescroll-uni/mescroll-body.css new file mode 100644 index 0000000..35a2343 --- /dev/null +++ b/components/mescroll-uni/mescroll-body.css @@ -0,0 +1,23 @@ +.mescroll-body { + position: relative; /* 下拉刷新区域相对自身定位 */ + height: auto; /* 不可固定高度,否则overflow:hidden导致无法滑动; 同时使设置的最小高生效,实现列表不满屏仍可下拉*/ + overflow: hidden; /* 当有元素写在mescroll-body标签前面时,可遮住下拉刷新区域 */ + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} +.mescroll-body .downwarp-content { + display: flex; + justify-content: center; + align-items: center; +} +/* 使sticky生效: 父元素不能overflow:hidden或者overflow:auto属性 */ +.mescroll-body.mescorll-sticky{ + overflow: unset !important +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} \ No newline at end of file diff --git a/components/mescroll-uni/mescroll-body.vue b/components/mescroll-uni/mescroll-body.vue new file mode 100644 index 0000000..34e0e6b --- /dev/null +++ b/components/mescroll-uni/mescroll-body.vue @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + diff --git a/components/mescroll-uni/mescroll-mixins.js b/components/mescroll-uni/mescroll-mixins.js new file mode 100644 index 0000000..050f9b7 --- /dev/null +++ b/components/mescroll-uni/mescroll-mixins.js @@ -0,0 +1,66 @@ +// mescroll-body 和 mescroll-uni 通用 + +// import MescrollUni from "./mescroll-uni.vue"; +// import MescrollBody from "./mescroll-body.vue"; + +const MescrollMixin = { + // components: { // 非H5端无法通过mixin注册组件, 只能在main.js中注册全局组件或具体界面中注册 + // MescrollUni, + // MescrollBody + // }, + data() { + return { + mescroll: null //mescroll实例对象 + } + }, + // 注册系统自带的下拉刷新 (配置down.native为true时生效, 还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + onPullDownRefresh(){ + this.mescroll && this.mescroll.onPullDownRefresh(); + }, + // 注册列表滚动事件,用于判定在顶部可下拉刷新,在指定位置可显示隐藏回到顶部按钮 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onPageScroll(e) { + this.mescroll && this.mescroll.onPageScroll(e); + }, + // 注册滚动到底部的事件,用于上拉加载 (此方法为页面生命周期,无法在子组件中触发, 仅在mescroll-body生效) + onReachBottom() { + this.mescroll && this.mescroll.onReachBottom(); + }, + methods: { + // mescroll组件初始化的回调,可获取到mescroll对象 + mescrollInit(mescroll) { + console.log(mescroll) + this.mescroll = mescroll; + this.mescrollInitByRef(); // 兼容字节跳动小程序 + }, + // 以ref的方式初始化mescroll对象 (兼容字节跳动小程序) + mescrollInitByRef() { + if(!this.mescroll || !this.mescroll.resetUpScroll){ + let mescrollRef = this.$refs.mescrollRef; + if(mescrollRef) this.mescroll = mescrollRef.mescroll + } + }, + // 下拉刷新的回调 (mixin默认resetUpScroll) + downCallback() { + if(this.mescroll.optUp.use){ + this.mescroll.resetUpScroll() + }else{ + setTimeout(()=>{ + this.mescroll.endSuccess(); + }, 500) + } + }, + // 上拉加载的回调 + upCallback() { + // mixin默认延时500自动结束加载 + setTimeout(()=>{ + this.mescroll.endErr(); + }, 500) + } + }, + mounted() { + this.mescrollInitByRef(); // 兼容字节跳动小程序, 避免未设置@init或@init此时未能取到ref的情况 + } + +} + +export default MescrollMixin; diff --git a/components/mescroll-uni/mescroll-uni-option.js b/components/mescroll-uni/mescroll-uni-option.js new file mode 100644 index 0000000..51967c5 --- /dev/null +++ b/components/mescroll-uni/mescroll-uni-option.js @@ -0,0 +1,36 @@ +// 全局配置 +// mescroll-body 和 mescroll-uni 通用 +const GlobalOption = { + down: { + // 其他down的配置参数也可以写,这里只展示了常用的配置: + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + textSuccess: '加载成功', // 加载成功的文本 + textErr: '加载失败', // 加载失败的文本 + beforeEndDelay: 100, // 延时结束的时长 (显示加载成功/失败的时长) + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + native: false // 是否使用系统自带的下拉刷新; 默认false; 仅在mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + }, + up: { + // 其他up的配置参数也可以写,这里只展示了常用的配置: + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '没有更多了~', // 没有更多数据的提示文本 + offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) + toTop: { + // 回到顶部按钮,需配置src才显示 + src: "https://www.mescroll.com/img/mescroll-totop.png", // 图片路径 (建议放入static目录, 如 /static/img/mescroll-totop.png ) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000px + right: 20, // 到右边的距离, 默认20 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + bottom: 100, // 到底部的距离, 默认120 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + width: 84 // 回到顶部图标的宽度, 默认72 (支持"20rpx", "20px", "20%"格式的值, 纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: "https://www.mescroll.com/img/mescroll-empty.png", // 图标路径 (建议放入static目录, 如 /static/img/mescroll-empty.png ) + tip: '空空如也' // 提示 + } + } +} + +export default GlobalOption diff --git a/components/mescroll-uni/mescroll-uni.css b/components/mescroll-uni/mescroll-uni.css new file mode 100644 index 0000000..c320360 --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.css @@ -0,0 +1,38 @@ +.mescroll-uni-warp{ + height: 100%; +} + +.mescroll-uni-content{ + height: 100%; + position: relative; +} + +.mescroll-uni { + /* border-radius: 20rpx 20rpx 0 0; */ + position: relative; + width: 100%; + height: 100%; + min-height: 200rpx; + overflow-y: auto; + box-sizing: border-box; /* 避免设置padding出现双滚动条的问题 */ +} + +/* 定位的方式固定高度 */ +.mescroll-uni-fixed{ + z-index: 1; + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: auto; /* 使right生效 */ + height: auto; /* 使bottom生效 */ +} + +/* 适配 iPhoneX */ +@supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) { + .mescroll-safearea { + padding-bottom: constant(safe-area-inset-bottom); + padding-bottom: env(safe-area-inset-bottom); + } +} diff --git a/components/mescroll-uni/mescroll-uni.js b/components/mescroll-uni/mescroll-uni.js new file mode 100644 index 0000000..571918b --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.js @@ -0,0 +1,799 @@ +/* mescroll + * version 1.3.3 + * 2020-09-15 wenju + * https://www.mescroll.com + */ + +export default function MeScroll(options, isScrollBody) { + let me = this; + me.version = '1.3.3'; // mescroll版本号 + me.options = options || {}; // 配置 + me.isScrollBody = isScrollBody || false; // 滚动区域是否为原生页面滚动; 默认为scroll-view + + me.isDownScrolling = false; // 是否在执行下拉刷新的回调 + me.isUpScrolling = false; // 是否在执行上拉加载的回调 + let hasDownCallback = me.options.down && me.options.down.callback; // 是否配置了down的callback + + // 初始化下拉刷新 + me.initDownScroll(); + // 初始化上拉加载,则初始化 + me.initUpScroll(); + + // 自动加载 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + // 自动触发下拉刷新 (只有配置了down的callback才自动触发下拉刷新) + if ((me.optDown.use || me.optDown.native) && me.optDown.auto && hasDownCallback) { + if (me.optDown.autoShowLoading) { + me.triggerDownScroll(); // 显示下拉进度,执行下拉回调 + } else { + me.optDown.callback && me.optDown.callback(me); // 不显示下拉进度,直接执行下拉回调 + } + } + // 自动触发上拉加载 + if(!me.isUpAutoLoad){ // 部分小程序(头条小程序)emit是异步, 会导致isUpAutoLoad判断有误, 先延时确保先执行down的callback,再执行up的callback + setTimeout(function(){ + me.optUp.use && me.optUp.auto && !me.isUpAutoLoad && me.triggerUpScroll(); + },100) + } + }, 30); // 需让me.optDown.inited和me.optUp.inited先执行 +} + +/* 配置参数:下拉刷新 */ +MeScroll.prototype.extendDownScroll = function(optDown) { + // 下拉刷新的配置 + MeScroll.extend(optDown, { + use: true, // 是否启用下拉刷新; 默认true + auto: true, // 是否在初始化完毕之后自动执行下拉刷新的回调; 默认true + native: false, // 是否使用系统自带的下拉刷新; 默认false; 仅mescroll-body生效 (值为true时,还需在pages配置enablePullDownRefresh:true;详请参考mescroll-native的案例) + autoShowLoading: false, // 如果设置auto=true(在初始化完毕之后自动执行下拉刷新的回调),那么是否显示下拉刷新的进度; 默认false + isLock: false, // 是否锁定下拉刷新,默认false; + offset: 80, // 在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调 + startTop: 100, // scroll-view快速滚动到顶部时,此时的scroll-top可能大于0, 此值用于控制最大的误差 + inOffsetRate: 1, // 在列表顶部,下拉的距离小于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + outOffsetRate: 0.2, // 在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值小于1且越接近0,高度变化越小,表现为越往下越难拉 + bottomOffset: 20, // 当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行 + minAngle: 45, // 向下滑动最少偏移的角度,取值区间 [0,90];默认45度,即向下滑动的角度大于45度则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突; + textInOffset: '下拉刷新', // 下拉的距离在offset范围内的提示文本 + textOutOffset: '释放更新', // 下拉的距离大于offset范围的提示文本 + textLoading: '加载中 ...', // 加载中的提示文本 + textSuccess: '加载成功', // 加载成功的文本 + textErr: '加载失败', // 加载失败的文本 + beforeEndDelay: 100, // 延时结束的时长 (显示加载成功/失败的时长) + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorTop) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 下拉刷新初始化完毕的回调 + inOffset: null, // 下拉的距离进入offset范围内那一刻的回调 + outOffset: null, // 下拉的距离大于offset那一刻的回调 + onMoving: null, // 下拉过程中的回调,滑动过程一直在执行; rate下拉区域当前高度与指定距离的比值(inOffset: rate<1; outOffset: rate>=1); downHight当前下拉区域的高度 + beforeLoading: null, // 准备触发下拉刷新的回调: 如果return true,将不触发showLoading和callback回调; 常用来完全自定义下拉刷新, 参考案例【淘宝 v6.8.0】 + showLoading: null, // 显示下拉刷新进度的回调 + afterLoading: null, // 显示下拉刷新进度的回调之后,马上要执行的代码 (如: 在wxs中使用) + beforeEndDownScroll: null, // 准备结束下拉的回调. 返回结束下拉的延时执行时间,默认0ms; 常用于结束下拉之前再显示另外一小段动画,才去隐藏下拉刷新的场景, 参考案例【dotJump】 + endDownScroll: null, // 结束下拉刷新的回调 + afterEndDownScroll: null, // 结束下拉刷新的回调,马上要执行的代码 (如: 在wxs中使用) + callback: function(mescroll) { + // 下拉刷新的回调;默认重置上拉加载列表为第一页 + mescroll.resetUpScroll(); + } + }) +} + +/* 配置参数:上拉加载 */ +MeScroll.prototype.extendUpScroll = function(optUp) { + // 上拉加载的配置 + MeScroll.extend(optUp, { + use: true, // 是否启用上拉加载; 默认true + auto: true, // 是否在初始化完毕之后自动执行上拉加载的回调; 默认true + isLock: false, // 是否锁定上拉加载,默认false; + isBoth: true, // 上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新;默认true,两者可同时触发; + callback: null, // 上拉加载的回调;function(page,mescroll){ } + page: { + num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始 + size: 10, // 每页数据的数量 + time: null // 加载第一页数据服务器返回的时间; 防止用户翻页时,后台新增了数据从而导致下一页数据重复; + }, + noMoreSize: 4, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看 + offset: 150, // 距底部多远时,触发upCallback,仅mescroll-uni生效 ( mescroll-body配置的是pages.json的 onReachBottomDistance ) + textLoading: '加载中 ...', // 加载中的提示文本 + textNoMore: '-- END --', // 没有更多数据的提示文本 + bgColor: "transparent", // 背景颜色 (建议在pages.json中再设置一下backgroundColorBottom) + textColor: "gray", // 文本颜色 (当bgColor配置了颜色,而textColor未配置时,则textColor会默认为白色) + inited: null, // 初始化完毕的回调 + showLoading: null, // 显示加载中的回调 + showNoMore: null, // 显示无更多数据的回调 + hideUpScroll: null, // 隐藏上拉加载的回调 + errDistance: 60, // endErr的时候需往上滑动一段距离,使其往下滑动时再次触发onReachBottom,仅mescroll-body生效 + toTop: { + // 回到顶部按钮,需配置src才显示 + src: null, // 图片路径,默认null (绝对路径或网络图) + offset: 1000, // 列表滚动多少距离才显示回到顶部按钮,默认1000 + duration: 300, // 回到顶部的动画时长,默认300ms (当值为0或300则使用系统自带回到顶部,更流畅; 其他值则通过step模拟,部分机型可能不够流畅,所以非特殊情况不建议修改此项) + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + zIndex: 9990, // fixed定位z-index值 + left: null, // 到左边的距离, 默认null. 此项有值时,right不生效. (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + right: 20, // 到右边的距离, 默认20 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + bottom: 120, // 到底部的距离, 默认120 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + safearea: false, // bottom的偏移量是否加上底部安全区的距离, 默认false, 需要适配iPhoneX时使用 (具体的界面如果不配置此项,则取本vue的safearea值) + width: 72, // 回到顶部图标的宽度, 默认72 (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + radius: "50%" // 圆角, 默认"50%" (支持20, "20rpx", "20px", "20%"格式的值, 其中纯数字则默认单位rpx) + }, + empty: { + use: true, // 是否显示空布局 + icon: null, // 图标路径 + tip: '~ 暂无相关数据 ~', // 提示 + btnText: '', // 按钮 + btnClick: null, // 点击按钮的回调 + onShow: null, // 是否显示的回调 + fixed: false, // 是否使用fixed定位,默认false; 配置fixed为true,以下的top和zIndex才生效 (transform会使fixed失效,最终会降级为absolute) + top: "100rpx", // fixed定位的top值 (完整的单位值,如 "10%"; "100rpx") + zIndex: 99 // fixed定位z-index值 + }, + onScroll: false // 是否监听滚动事件 + }) +} + +/* 配置参数 */ +MeScroll.extend = function(userOption, defaultOption) { + if (!userOption) return defaultOption; + for (let key in defaultOption) { + if (userOption[key] == null) { + let def = defaultOption[key]; + if (def != null && typeof def === 'object') { + userOption[key] = MeScroll.extend({}, def); // 深度匹配 + } else { + userOption[key] = def; + } + } else if (typeof userOption[key] === 'object') { + MeScroll.extend(userOption[key], defaultOption[key]); // 深度匹配 + } + } + return userOption; +} + +/* 简单判断是否配置了颜色 (非透明,非白色) */ +MeScroll.prototype.hasColor = function(color) { + if(!color) return false; + let c = color.toLowerCase(); + return c != "#fff" && c != "#ffffff" && c != "transparent" && c != "white" +} + +/* -------初始化下拉刷新------- */ +MeScroll.prototype.initDownScroll = function() { + let me = this; + // 配置参数 + me.optDown = me.options.down || {}; + if(!me.optDown.textColor && me.hasColor(me.optDown.bgColor)) me.optDown.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendDownScroll(me.optDown); + + // 如果是mescroll-body且配置了native,则禁止自定义的下拉刷新 + if(me.isScrollBody && me.optDown.native){ + me.optDown.use = false + }else{ + me.optDown.native = false // 仅mescroll-body支持,mescroll-uni不支持 + } + + me.downHight = 0; // 下拉区域的高度 + + // 在页面中加入下拉布局 + if (me.optDown.use && me.optDown.inited) { + // 初始化完毕的回调 + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optDown.inited(me); + }, 0) + } +} + +/* 列表touchstart事件 */ +MeScroll.prototype.touchstartEvent = function(e) { + if (!this.optDown.use) return; + + this.startPoint = this.getPoint(e); // 记录起点 + this.startTop = this.getScrollTop(); // 记录此时的滚动条位置 + this.startAngle = 0; // 初始角度 + this.lastPoint = this.startPoint; // 重置上次move的点 + this.maxTouchmoveY = this.getBodyHeight() - this.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + this.inTouchend = false; // 标记不是touchend +} + +/* 列表touchmove事件 */ +MeScroll.prototype.touchmoveEvent = function(e) { + if (!this.optDown.use) return; + let me = this; + + let scrollTop = me.getScrollTop(); // 当前滚动条的距离 + let curPoint = me.getPoint(e); // 当前点 + + let moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.optUp.isBoth))) { + + // 下拉的初始角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + me.touchendEvent(); // 提前触发touchend + return; + } + + me.preventDefault(e); // 阻止默认事件 + + let diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + me.isDownEndSuccess = null; // 重置是否加载成功的状态 (wxs执行的是wxs.wxs) + me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + let rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 +} + +/* 列表touchend事件 */ +MeScroll.prototype.touchendEvent = function(e) { + if (!this.optDown.use) return; + // 如果下拉区域高度已改变,则需重置回来 + if (this.isMoveDown) { + if (this.downHight >= this.optDown.offset) { + // 符合触发刷新的条件 + this.triggerDownScroll(); + } else { + // 不符合的话 则重置 + this.downHight = 0; + this.endDownScrollCall(this); + } + this.movetype = 0; + this.isMoveDown = false; + } else if (!this.isScrollBody && this.getScrollTop() === this.startTop) { // scroll-view到顶/左/右/底的滑动事件 + let isScrollUp = this.getPoint(e).y - this.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + let angle = this.getAngle(this.getPoint(e), this.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + this.triggerUpScroll(true); + } + } + } +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +MeScroll.prototype.getPoint = function(e) { + if (!e) { + return { + x: 0, + y: 0 + } + } + if (e.touches && e.touches[0]) { + return { + x: e.touches[0].pageX, + y: e.touches[0].pageY + } + } else if (e.changedTouches && e.changedTouches[0]) { + return { + x: e.changedTouches[0].pageX, + y: e.changedTouches[0].pageY + } + } else { + return { + x: e.clientX, + y: e.clientY + } + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +MeScroll.prototype.getAngle = function(p1, p2) { + let x = Math.abs(p1.x - p2.x); + let y = Math.abs(p1.y - p2.y); + let z = Math.sqrt(x * x + y * y); + let angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 触发下拉刷新 */ +MeScroll.prototype.triggerDownScroll = function() { + if (this.optDown.beforeLoading && this.optDown.beforeLoading(this)) { + //return true则处于完全自定义状态 + } else { + this.showDownScroll(); // 下拉刷新中... + !this.optDown.native && this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示下拉进度布局 */ +MeScroll.prototype.showDownScroll = function() { + this.isDownScrolling = true; // 标记下拉中 + if (this.optDown.native) { + uni.startPullDownRefresh(); // 系统自带的下拉刷新 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + } else{ + this.downHight = this.optDown.offset; // 更新下拉区域高度 + this.showDownLoadingCall(this.downHight); // 下拉刷新中... + } +} + +MeScroll.prototype.showDownLoadingCall = function(downHight) { + this.optDown.showLoading && this.optDown.showLoading(this, downHight); // 下拉刷新中... + this.optDown.afterLoading && this.optDown.afterLoading(this, downHight); // 下拉刷新中...触发之后马上要执行的代码 +} + +/* 显示系统自带的下拉刷新时需要处理的业务 */ +MeScroll.prototype.onPullDownRefresh = function() { + this.isDownScrolling = true; // 标记下拉中 + this.showDownLoadingCall(0); // 仍触发showLoading,因为上拉加载用到 + this.optDown.callback && this.optDown.callback(this); // 执行回调,联网加载数据 +} + +/* 结束下拉刷新 */ +MeScroll.prototype.endDownScroll = function() { + if (this.optDown.native) { // 结束原生下拉刷新 + this.isDownScrolling = false; + this.endDownScrollCall(this); + uni.stopPullDownRefresh(); + return + } + let me = this; + // 结束下拉刷新的方法 + let endScroll = function() { + me.downHight = 0; + me.isDownScrolling = false; + me.endDownScrollCall(me); + if(!me.isScrollBody){ + me.setScrollHeight(0) // scroll-view重置滚动区域,使数据不满屏时仍可检查触发翻页 + me.scrollTo(0,0) // scroll-view需重置滚动条到顶部,避免startTop大于0时,对下拉刷新的影响 + } + } + // 结束下拉刷新时的回调 + let delay = 0; + if (me.optDown.beforeEndDownScroll) { + delay = me.optDown.beforeEndDownScroll(me); // 结束下拉刷新的延时,单位ms + if(me.isDownEndSuccess == null) delay = 0; // 没有执行加载中,则不延时 + } + if (typeof delay === 'number' && delay > 0) { + setTimeout(endScroll, delay); + } else { + endScroll(); + } +} + +MeScroll.prototype.endDownScrollCall = function() { + this.optDown.endDownScroll && this.optDown.endDownScroll(this); + this.optDown.afterEndDownScroll && this.optDown.afterEndDownScroll(this); +} + +/* 锁定下拉刷新:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockDownScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optDown.isLock = isLock; +} + +/* 锁定上拉加载:isLock=ture,null锁定;isLock=false解锁 */ +MeScroll.prototype.lockUpScroll = function(isLock) { + if (isLock == null) isLock = true; + this.optUp.isLock = isLock; +} + +/* -------初始化上拉加载------- */ +MeScroll.prototype.initUpScroll = function() { + let me = this; + // 配置参数 + me.optUp = me.options.up || {use: false} + if(!me.optUp.textColor && me.hasColor(me.optUp.bgColor)) me.optUp.textColor = "#fff"; // 当bgColor有值且textColor未设置,则textColor默认白色 + me.extendUpScroll(me.optUp); + + if (me.optUp.use === false) return; // 配置不使用上拉加载时,则不初始化上拉布局 + me.optUp.hasNext = true; // 如果使用上拉,则默认有下一页 + me.startNum = me.optUp.page.num + 1; // 记录page开始的页码 + + // 初始化完毕的回调 + if (me.optUp.inited) { + setTimeout(function() { // 待主线程执行完毕再执行,避免new MeScroll未初始化,在回调获取不到mescroll的实例 + me.optUp.inited(me); + }, 0) + } +} + +/*滚动到底部的事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onReachBottom = function() { + if (this.isScrollBody && !this.isUpScrolling) { // 只能支持下拉刷新的时候同时可以触发上拉加载,否则滚动到底部就需要上滑一点才能触发onReachBottom + if (!this.optUp.isLock && this.optUp.hasNext) { + this.triggerUpScroll(); + } + } +} + +/*列表滚动事件 (仅mescroll-body生效)*/ +MeScroll.prototype.onPageScroll = function(e) { + if (!this.isScrollBody) return; + + // 更新滚动条的位置 (主要用于判断下拉刷新时,滚动条是否在顶部) + this.setScrollTop(e.scrollTop); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } +} + +/*列表滚动事件*/ +MeScroll.prototype.scroll = function(e, onScroll) { + // 更新滚动条的位置 + this.setScrollTop(e.scrollTop); + // 更新滚动内容高度 + this.setScrollHeight(e.scrollHeight); + + // 向上滑还是向下滑动 + if (this.preScrollY == null) this.preScrollY = 0; + this.isScrollUp = e.scrollTop - this.preScrollY > 0; + this.preScrollY = e.scrollTop; + + // 上滑 && 检查并触发上拉 + this.isScrollUp && this.triggerUpScroll(true); + + // 顶部按钮的显示隐藏 + if (e.scrollTop >= this.optUp.toTop.offset) { + this.showTopBtn(); + } else { + this.hideTopBtn(); + } + + // 滑动监听 + this.optUp.onScroll && onScroll && onScroll() +} + +/* 触发上拉加载 */ +MeScroll.prototype.triggerUpScroll = function(isCheck) { + if (!this.isUpScrolling && this.optUp.use && this.optUp.callback) { + // 是否校验在底部; 默认不校验 + if (isCheck === true) { + let canUp = false; + // 还有下一页 && 没有锁定 && 不在下拉中 + if (this.optUp.hasNext && !this.optUp.isLock && !this.isDownScrolling) { + if (this.getScrollBottom() <= this.optUp.offset) { // 到底部 + canUp = true; // 标记可上拉 + } + } + if (canUp === false) return; + } + this.showUpScroll(); // 上拉加载中... + this.optUp.page.num++; // 预先加一页,如果失败则减回 + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = this.optUp.page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = this.optUp.page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = this.optUp.page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback(this); // 执行回调,联网加载数据 + } +} + +/* 显示上拉加载中 */ +MeScroll.prototype.showUpScroll = function() { + this.isUpScrolling = true; // 标记上拉加载中 + this.optUp.showLoading && this.optUp.showLoading(this); // 回调 +} + +/* 显示上拉无更多数据 */ +MeScroll.prototype.showNoMore = function() { + this.optUp.hasNext = false; // 标记无更多数据 + this.optUp.showNoMore && this.optUp.showNoMore(this); // 回调 +} + +/* 隐藏上拉区域**/ +MeScroll.prototype.hideUpScroll = function() { + this.optUp.hideUpScroll && this.optUp.hideUpScroll(this); // 回调 +} + +/* 结束上拉加载 */ +MeScroll.prototype.endUpScroll = function(isShowNoMore) { + if (isShowNoMore != null) { // isShowNoMore=null,不处理下拉状态,下拉刷新的时候调用 + if (isShowNoMore) { + this.showNoMore(); // isShowNoMore=true,显示无更多数据 + } else { + this.hideUpScroll(); // isShowNoMore=false,隐藏上拉加载 + } + } + this.isUpScrolling = false; // 标记结束上拉加载 +} + +/* 重置上拉加载列表为第一页 + *isShowLoading 是否显示进度布局; + * 1.默认null,不传参,则显示上拉加载的进度布局 + * 2.传参true, 则显示下拉刷新的进度布局 + * 3.传参false,则不显示上拉和下拉的进度 (常用于静默更新列表数据) + */ +MeScroll.prototype.resetUpScroll = function(isShowLoading) { + if (this.optUp && this.optUp.use) { + let page = this.optUp.page; + this.prePageNum = page.num; // 缓存重置前的页码,加载失败可退回 + this.prePageTime = page.time; // 缓存重置前的时间,加载失败可退回 + page.num = this.startNum; // 重置为第一页 + page.time = null; // 重置时间为空 + if (!this.isDownScrolling && isShowLoading !== false) { // 如果不是下拉刷新触发的resetUpScroll并且不配置列表静默更新,则显示进度; + if (isShowLoading == null) { + this.removeEmpty(); // 移除空布局 + this.showUpScroll(); // 不传参,默认显示上拉加载的进度布局 + } else { + this.showDownScroll(); // 传true,显示下拉刷新的进度布局,不清空列表 + } + } + this.isUpAutoLoad = true; // 标记上拉已经自动执行过,避免初始化时多次触发上拉回调 + this.num = page.num; // 把最新的页数赋值在mescroll上,避免对page的影响 + this.size = page.size; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.time = page.time; // 把最新的页码赋值在mescroll上,避免对page的影响 + this.optUp.callback && this.optUp.callback(this); // 执行上拉回调 + } +} + +/* 设置page.num的值 */ +MeScroll.prototype.setPageNum = function(num) { + this.optUp.page.num = num - 1; +} + +/* 设置page.size的值 */ +MeScroll.prototype.setPageSize = function(size) { + this.optUp.page.size = size; +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalPage: 总页数(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endByPage = function(dataSize, totalPage, systime) { + let hasNext; + if (this.optUp.use && totalPage != null) hasNext = this.optUp.page.num < totalPage; // 是否还有下一页 + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据量(必传) + * totalSize: 列表所有数据总数量(必传) + * systime: 服务器时间 (可空) + */ +MeScroll.prototype.endBySize = function(dataSize, totalSize, systime) { + let hasNext; + if (this.optUp.use && totalSize != null) { + let loadSize = (this.optUp.page.num - 1) * this.optUp.page.size + dataSize; // 已加载的数据总数 + hasNext = loadSize < totalSize; // 是否还有下一页 + } + this.endSuccess(dataSize, hasNext, systime); +} + +/* 联网回调成功,结束下拉刷新和上拉加载 + * dataSize: 当前页的数据个数(不是所有页的数据总和),用于上拉加载判断是否还有下一页.如果不传,则会判断还有下一页 + * hasNext: 是否还有下一页,布尔类型;用来解决这个小问题:比如列表共有20条数据,每页加载10条,共2页.如果只根据dataSize判断,则需翻到第三页才会知道无更多数据,如果传了hasNext,则翻到第二页即可显示无更多数据. + * systime: 服务器时间(可空);用来解决这个小问题:当准备翻下一页时,数据库新增了几条记录,此时翻下一页,前面的几条数据会和上一页的重复;这里传入了systime,那么upCallback的page.time就会有值,把page.time传给服务器,让后台过滤新加入的那几条记录 + */ +MeScroll.prototype.endSuccess = function(dataSize, hasNext, systime) { + let me = this; + // 结束下拉刷新 + if (me.isDownScrolling) { + me.isDownEndSuccess = true + me.endDownScroll(); + } + + // 结束上拉加载 + if (me.optUp.use) { + let isShowNoMore; // 是否已无更多数据 + if (dataSize != null) { + let pageNum = me.optUp.page.num; // 当前页码 + let pageSize = me.optUp.page.size; // 每页长度 + // 如果是第一页 + if (pageNum === 1) { + if (systime) me.optUp.page.time = systime; // 设置加载列表数据第一页的时间 + } + if (dataSize < pageSize || hasNext === false) { + // 返回的数据不满一页时,则说明已无更多数据 + me.optUp.hasNext = false; + if (dataSize === 0 && pageNum === 1) { + // 如果第一页无任何数据且配置了空布局 + isShowNoMore = false; + me.showEmpty(); + } else { + // 总列表数少于配置的数量,则不显示无更多数据 + let allDataSize = (pageNum - 1) * pageSize + dataSize; + if (allDataSize < me.optUp.noMoreSize) { + isShowNoMore = false; + } else { + isShowNoMore = true; + } + me.removeEmpty(); // 移除空布局 + } + } else { + // 还有下一页 + isShowNoMore = false; + me.optUp.hasNext = true; + me.removeEmpty(); // 移除空布局 + } + } + + // 隐藏上拉 + me.endUpScroll(isShowNoMore); + } +} + +/* 回调失败,结束下拉刷新和上拉加载 */ +MeScroll.prototype.endErr = function(errDistance) { + // 结束下拉,回调失败重置回原来的页码和时间 + if (this.isDownScrolling) { + this.isDownEndSuccess = false + let page = this.optUp.page; + if (page && this.prePageNum) { + page.num = this.prePageNum; + page.time = this.prePageTime; + } + this.endDownScroll(); + } + // 结束上拉,回调失败重置回原来的页码 + if (this.isUpScrolling) { + this.optUp.page.num--; + this.endUpScroll(false); + // 如果是mescroll-body,则需往回滚一定距离 + if(this.isScrollBody && errDistance !== 0){ // 不处理0 + if(!errDistance) errDistance = this.optUp.errDistance; // 不传,则取默认 + this.scrollTo(this.getScrollTop() - errDistance, 0) // 往上回滚的距离 + } + } +} + +/* 显示空布局 */ +MeScroll.prototype.showEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(true) +} + +/* 移除空布局 */ +MeScroll.prototype.removeEmpty = function() { + this.optUp.empty.use && this.optUp.empty.onShow && this.optUp.empty.onShow(false) +} + +/* 显示回到顶部的按钮 */ +MeScroll.prototype.showTopBtn = function() { + if (!this.topBtnShow) { + this.topBtnShow = true; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(true); + } +} + +/* 隐藏回到顶部的按钮 */ +MeScroll.prototype.hideTopBtn = function() { + if (this.topBtnShow) { + this.topBtnShow = false; + this.optUp.toTop.onShow && this.optUp.toTop.onShow(false); + } +} + +/* 获取滚动条的位置 */ +MeScroll.prototype.getScrollTop = function() { + return this.scrollTop || 0 +} + +/* 记录滚动条的位置 */ +MeScroll.prototype.setScrollTop = function(y) { + this.scrollTop = y; +} + +/* 滚动到指定位置 */ +MeScroll.prototype.scrollTo = function(y, t) { + this.myScrollTo && this.myScrollTo(y, t) // scrollview需自定义回到顶部方法 +} + +/* 自定义scrollTo */ +MeScroll.prototype.resetScrollTo = function(myScrollTo) { + this.myScrollTo = myScrollTo +} + +/* 滚动条到底部的距离 */ +MeScroll.prototype.getScrollBottom = function() { + return this.getScrollHeight() - this.getClientHeight() - this.getScrollTop() +} + +/* 计步器 + star: 开始值 + end: 结束值 + callback(step,timer): 回调step值,计步器timer,可自行通过window.clearInterval(timer)结束计步器; + t: 计步时长,传0则直接回调end值;不传则默认300ms + rate: 周期;不传则默认30ms计步一次 + * */ +MeScroll.prototype.getStep = function(star, end, callback, t, rate) { + let diff = end - star; // 差值 + if (t === 0 || diff === 0) { + callback && callback(end); + return; + } + t = t || 300; // 时长 300ms + rate = rate || 30; // 周期 30ms + let count = t / rate; // 次数 + let step = diff / count; // 步长 + let i = 0; // 计数 + let timer = setInterval(function() { + if (i < count - 1) { + star += step; + callback && callback(star, timer); + i++; + } else { + callback && callback(end, timer); // 最后一次直接设置end,避免计算误差 + clearInterval(timer); + } + }, rate); +} + +/* 滚动容器的高度 */ +MeScroll.prototype.getClientHeight = function(isReal) { + let h = this.clientHeight || 0 + if (h === 0 && isReal !== true) { // 未获取到容器的高度,可临时取body的高度 (可能会有误差) + h = this.getBodyHeight() + } + return h +} +MeScroll.prototype.setClientHeight = function(h) { + this.clientHeight = h; +} + +/* 滚动内容的高度 */ +MeScroll.prototype.getScrollHeight = function() { + return this.scrollHeight || 0; +} +MeScroll.prototype.setScrollHeight = function(h) { + this.scrollHeight = h; +} + +/* body的高度 */ +MeScroll.prototype.getBodyHeight = function() { + return this.bodyHeight || 0; +} +MeScroll.prototype.setBodyHeight = function(h) { + this.bodyHeight = h; +} + +/* 阻止浏览器默认滚动事件 */ +MeScroll.prototype.preventDefault = function(e) { + // 小程序不支持e.preventDefault, 已在wxs中禁止 + // app的bounce只能通过配置pages.json的style.app-plus.bounce为"none"来禁止, 或使用renderjs禁止 + // cancelable:是否可以被禁用; defaultPrevented:是否已经被禁用 + if (e && e.cancelable && !e.defaultPrevented) e.preventDefault() +} \ No newline at end of file diff --git a/components/mescroll-uni/mescroll-uni.vue b/components/mescroll-uni/mescroll-uni.vue new file mode 100644 index 0000000..f73b0ca --- /dev/null +++ b/components/mescroll-uni/mescroll-uni.vue @@ -0,0 +1,430 @@ + + + + + + + + + + + + + + + diff --git a/components/mescroll-uni/mixins/mescroll-comp.js b/components/mescroll-uni/mixins/mescroll-comp.js new file mode 100644 index 0000000..b504894 --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-comp.js @@ -0,0 +1,48 @@ +/** + * mescroll-body写在子组件时,需通过mescroll的mixins补充子组件缺少的生命周期 + */ +const MescrollCompMixin = { + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 (一级) + onPageScroll(e) { + this.handlePageScroll(e) + }, + onReachBottom() { + this.handleReachBottom() + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + this.handlePullDownRefresh() + }, + // mescroll-body写在子子子...组件的情况 (多级) + data() { + return { + mescroll: { + onPageScroll: e=>{ + this.handlePageScroll(e) + }, + onReachBottom: ()=>{ + this.handleReachBottom() + }, + onPullDownRefresh: ()=>{ + this.handlePullDownRefresh() + } + } + } + }, + methods:{ + handlePageScroll(e){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPageScroll(e); + }, + handleReachBottom(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onReachBottom(); + }, + handlePullDownRefresh(){ + let item = this.$refs["mescrollItem"]; + if(item && item.mescroll) item.mescroll.onPullDownRefresh(); + } + } +} + +export default MescrollCompMixin; diff --git a/components/mescroll-uni/mixins/mescroll-more-item.js b/components/mescroll-uni/mixins/mescroll-more-item.js new file mode 100644 index 0000000..5cb920b --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-more-item.js @@ -0,0 +1,59 @@ +/** + * mescroll-more-item的mixins, 仅在多个 mescroll-body 写在子组件时使用 (参考 mescroll-more 案例) + */ +const MescrollMoreItemMixin = { + // 支付宝小程序不支持props的mixin,需写在具体的页面中 + // #ifndef MP-ALIPAY || MP-DINGTALK + props:{ + i: Number, // 每个tab页的专属下标 + index: { // 当前tab的下标 + type: Number, + default(){ + return 0 + } + } + }, + // #endif + data() { + return { + downOption:{ + auto:false // 不自动加载 + }, + upOption:{ + auto:false // 不自动加载 + }, + isInit: false // 当前tab是否已初始化 + } + }, + watch:{ + // 监听下标的变化 + index(val){ + if (this.i === val && !this.isInit) { + this.isInit = true; // 标记为true + this.mescroll && this.mescroll.triggerDownScroll(); + } + } + }, + methods: { + // 以ref的方式初始化mescroll对象 (兼容字节跳动小程序) + mescrollInitByRef() { + if(!this.mescroll || !this.mescroll.resetUpScroll){ + // 字节跳动小程序编辑器不支持一个页面存在相同的ref, 多mescroll的ref需动态生成, 格式为'mescrollRef下标' + let mescrollRef = this.$refs.mescrollRef || this.$refs['mescrollRef'+this.i]; + if(mescrollRef) this.mescroll = mescrollRef.mescroll + } + }, + // mescroll组件初始化的回调,可获取到mescroll对象 (覆盖mescroll-mixins.js的mescrollInit, 为了标记isInit) + mescrollInit(mescroll) { + this.mescroll = mescroll; + this.mescrollInitByRef && this.mescrollInitByRef(); // 兼容字节跳动小程序 + // 自动加载当前tab的数据 + if(this.i === this.index){ + this.isInit = true; // 标记为true + this.mescroll.triggerDownScroll(); + } + }, + } +} + +export default MescrollMoreItemMixin; diff --git a/components/mescroll-uni/mixins/mescroll-more.js b/components/mescroll-uni/mixins/mescroll-more.js new file mode 100644 index 0000000..d765088 --- /dev/null +++ b/components/mescroll-uni/mixins/mescroll-more.js @@ -0,0 +1,74 @@ +/** + * mescroll-body写在子组件时, 需通过mescroll的mixins补充子组件缺少的生命周期 + */ +const MescrollMoreMixin = { + data() { + return { + tabIndex: 0, // 当前tab下标 + mescroll: { + onPageScroll: e=>{ + this.handlePageScroll(e) + }, + onReachBottom: ()=>{ + this.handleReachBottom() + }, + onPullDownRefresh: ()=>{ + this.handlePullDownRefresh() + } + } + } + }, + // 因为子组件无onPageScroll和onReachBottom的页面生命周期,需在页面传递进到子组件 + onPageScroll(e) { + this.handlePageScroll(e) + }, + onReachBottom() { + this.handleReachBottom() + }, + // 当down的native: true时, 还需传递此方法进到子组件 + onPullDownRefresh(){ + this.handlePullDownRefresh() + }, + methods:{ + handlePageScroll(e){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPageScroll(e); + }, + handleReachBottom(){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onReachBottom(); + }, + handlePullDownRefresh(){ + let mescroll = this.getMescroll(this.tabIndex); + mescroll && mescroll.onPullDownRefresh(); + }, + // 根据下标获取对应子组件的mescroll + getMescroll(i){ + if(!this.mescrollItems) this.mescrollItems = []; + if(!this.mescrollItems[i]) { + // v-for中的refs + let vForItem = this.$refs["mescrollItem"]; + if(vForItem){ + this.mescrollItems[i] = vForItem[i] + }else{ + // 普通的refs,不可重复 + this.mescrollItems[i] = this.$refs["mescrollItem"+i]; + } + } + let item = this.mescrollItems[i] + return item ? item.mescroll : null + }, + // 切换tab,恢复滚动条位置 + tabChange(i){ + let mescroll = this.getMescroll(i); + if(mescroll){ + // 延时(比$nextTick靠谱一些),确保元素已渲染 + setTimeout(()=>{ + mescroll.scrollTo(mescroll.getScrollTop(),0) + },30) + } + } + } +} + +export default MescrollMoreMixin; diff --git a/components/mescroll-uni/wxs/mixins.js b/components/mescroll-uni/wxs/mixins.js new file mode 100644 index 0000000..34ffa3c --- /dev/null +++ b/components/mescroll-uni/wxs/mixins.js @@ -0,0 +1,109 @@ +// 定义在wxs (含renderjs) 逻辑层的数据和方法, 与视图层相互通信 +const WxsMixin = { + data() { + return { + // 传入wxs视图层的数据 (响应式) + wxsProp: { + optDown:{}, // 下拉刷新的配置 + scrollTop:0, // 滚动条的距离 + bodyHeight:0, // body的高度 + isDownScrolling:false, // 是否正在下拉刷新中 + isUpScrolling:false, // 是否正在上拉加载中 + isScrollBody:true, // 是否为mescroll-body滚动 + isUpBoth:true, // 上拉加载时,是否同时可以下拉刷新 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 标记调用wxs视图层的方法 + callProp: { + callType: '', // 方法名 + t: 0 // 数据更新的标记 (只有数据更新了,才会触发wxs的Observer) + }, + + // 不用wxs的平台使用此处的wxsBiz对象,抹平wxs的写法 (微信小程序和APP使用的wxsBiz对象是./wxs/wxs.wxs) + // #ifndef MP-WEIXIN || MP-QQ || APP-PLUS || H5 + wxsBiz: { + //注册列表touchstart事件,用于下拉刷新 + touchstartEvent: e=> { + this.mescroll.touchstartEvent(e); + }, + //注册列表touchmove事件,用于下拉刷新 + touchmoveEvent: e=> { + this.mescroll.touchmoveEvent(e); + }, + //注册列表touchend事件,用于下拉刷新 + touchendEvent: e=> { + this.mescroll.touchendEvent(e); + }, + propObserver(){}, // 抹平wxs的写法 + callObserver(){} // 抹平wxs的写法 + }, + // #endif + + // 不用renderjs的平台使用此处的renderBiz对象,抹平renderjs的写法 (app 和 h5 使用的renderBiz对象是./wxs/renderjs.js) + // #ifndef APP-PLUS || H5 + renderBiz: { + propObserver(){} // 抹平renderjs的写法 + } + // #endif + } + }, + methods: { + // wxs视图层调用逻辑层的回调 + wxsCall(msg){ + if(msg.type === 'setWxsProp'){ + // 更新wxsProp数据 (值改变才触发更新) + this.wxsProp = { + optDown: this.mescroll.optDown, + scrollTop: this.mescroll.getScrollTop(), + bodyHeight: this.mescroll.getBodyHeight(), + isDownScrolling: this.mescroll.isDownScrolling, + isUpScrolling: this.mescroll.isUpScrolling, + isUpBoth: this.mescroll.optUp.isBoth, + isScrollBody:this.mescroll.isScrollBody, + t: Date.now() + } + }else if(msg.type === 'setLoadType'){ + // 设置inOffset,outOffset的状态 + this.downLoadType = msg.downLoadType + // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如中 + this.$set(this.mescroll, 'downLoadType', this.downLoadType) + // 重置是否加载成功的状态 + this.$set(this.mescroll, 'isDownEndSuccess', null) + }else if(msg.type === 'triggerDownScroll'){ + // 主动触发下拉刷新 + this.mescroll.triggerDownScroll(); + }else if(msg.type === 'endDownScroll'){ + // 结束下拉刷新 + this.mescroll.endDownScroll(); + }else if(msg.type === 'triggerUpScroll'){ + // 主动触发上拉加载 + this.mescroll.triggerUpScroll(true); + } + } + }, + mounted() { + // #ifdef MP-WEIXIN || MP-QQ || APP-PLUS || H5 + // 配置主动触发wxs显示加载进度的回调 + this.mescroll.optDown.afterLoading = ()=>{ + this.callProp = {callType: "showLoading", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + // 配置主动触发wxs隐藏加载进度的回调 + this.mescroll.optDown.afterEndDownScroll = ()=>{ + this.callProp = {callType: "endDownScroll", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + let delay = 300 + (this.mescroll.optDown.beforeEndDelay || 0) + setTimeout(()=>{ + if(this.downLoadType === 4 || this.downLoadType === 0){ + this.callProp = {callType: "clearTransform", t: Date.now()} // 触发wxs的方法 (值改变才触发更新) + } + // 状态挂载到mescroll对象, 以便在其他组件中使用, 比如中 + this.$set(this.mescroll, 'downLoadType', this.downLoadType) + }, delay) + } + // 初始化wxs的数据 + this.wxsCall({type: 'setWxsProp'}) + // #endif + } +} + +export default WxsMixin; diff --git a/components/mescroll-uni/wxs/renderjs.js b/components/mescroll-uni/wxs/renderjs.js new file mode 100644 index 0000000..207f388 --- /dev/null +++ b/components/mescroll-uni/wxs/renderjs.js @@ -0,0 +1,92 @@ +// 使用renderjs直接操作window对象,实现动态控制app和h5的bounce +// bounce: iOS橡皮筋,Android半月弧,h5浏览器下拉背景等效果 (下拉刷新时禁止) +// https://uniapp.dcloud.io/frame?id=renderjs + +// 与wxs的me实例一致 +var me = {} + +// 初始化window对象的touch事件 (仅初始化一次) +if(window && !window.$mescrollRenderInit){ + window.$mescrollRenderInit = true + + + window.addEventListener('touchstart', function(e){ + if (me.disabled()) return; + me.startPoint = me.getPoint(e); // 记录起点 + }, {passive: true}) + + + window.addEventListener('touchmove', function(e){ + if (me.disabled()) return; + if (me.getScrollTop() > 0) return; // 需在顶部下拉,才禁止bounce + + var curPoint = me.getPoint(e); // 当前点 + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 向下拉 + if (moveY > 0) { + // 可下拉的条件 + if (!me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && me.isUpBoth))) { + + // 只有touch在mescroll的view上面,才禁止bounce + var el = e.target; + var isMescrollTouch = false; + while (el && el.tagName && el.tagName !== 'UNI-PAGE-BODY' && el.tagName != "BODY") { + var cls = el.classList; + if (cls && cls.contains('mescroll-render-touch')) { + isMescrollTouch = true + break; + } + el = el.parentNode; // 继续检查其父元素 + } + // 禁止bounce (不会对swiper和iOS侧滑返回造成影响) + if (isMescrollTouch && e.cancelable && !e.defaultPrevented) e.preventDefault(); + } + } + }, {passive: false}) +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || 0 +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth +} + +/* 导出模块 */ +const renderBiz = { + data() { + return { + propObserver: propObserver, + } + } +} + +export default renderBiz; \ No newline at end of file diff --git a/components/mescroll-uni/wxs/wxs.wxs b/components/mescroll-uni/wxs/wxs.wxs new file mode 100644 index 0000000..3fb4ad9 --- /dev/null +++ b/components/mescroll-uni/wxs/wxs.wxs @@ -0,0 +1,268 @@ +// 使用wxs处理交互动画, 提高性能, 同时避免小程序bounce对下拉刷新的影响 +// https://uniapp.dcloud.io/frame?id=wxs +// https://developers.weixin.qq.com/miniprogram/dev/framework/view/interactive-animation.html + +// 模拟mescroll实例, 与mescroll.js的写法尽量保持一致 +var me = {} + +// ------ 自定义下拉刷新动画 start ------ + +/* 下拉过程中的回调,滑动过程一直在执行 (rate<1为inOffset; rate>1为outOffset) */ +me.onMoving = function (ins, rate, downHight){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'transform', // 可解决下拉过程中, image和swiper脱离文档流的问题 + 'transform': 'translateY(' + downHight + 'px)', + 'transition': '' + }) + // 环形进度条 + var progress = ins.selectComponent('.mescroll-wxs-progress') + progress && progress.setStyle({transform: 'rotate(' + 360 * rate + 'deg)'}) + }) +} + +/* 显示下拉刷新进度 */ +me.showLoading = function (ins){ + me.downHight = me.optDown.offset + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(' + me.downHight + 'px)', + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉 */ +me.endDownScroll = function (ins){ + me.downHight = 0; + me.isDownScrolling = false; + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': 'auto', + 'transform': 'translateY(0)', // 不可以写空串,否则scroll-view渲染不完整 (延时350ms会调clearTransform置空) + 'transition': 'transform 300ms' + }) + }) +} + +/* 结束下拉动画执行完毕后, 清除transform和transition, 避免对列表内容样式造成影响, 如: h5的list-msg示例下拉进度条漏出来等 */ +me.clearTransform = function (ins){ + ins.requestAnimationFrame(function () { + ins.selectComponent('.mescroll-wxs-content').setStyle({ + 'will-change': '', + 'transform': '', + 'transition': '' + }) + }) +} + +// ------ 自定义下拉刷新动画 end ------ + +/** + * 监听逻辑层数据的变化 (实时更新数据) + */ +function propObserver(wxsProp) { + me.optDown = wxsProp.optDown + me.scrollTop = wxsProp.scrollTop + me.bodyHeight = wxsProp.bodyHeight + me.isDownScrolling = wxsProp.isDownScrolling + me.isUpScrolling = wxsProp.isUpScrolling + me.isUpBoth = wxsProp.isUpBoth + me.isScrollBody = wxsProp.isScrollBody + me.startTop = wxsProp.scrollTop // 及时更新touchstart触发的startTop, 避免scroll-view快速惯性滚动到顶部取值不准确 +} + +/** + * 监听逻辑层数据的变化 (调用wxs的方法) + */ +function callObserver(callProp, oldValue, ins) { + if (me.disabled()) return; + if(callProp.callType){ + // 逻辑层(App Service)的style已失效,需在视图层(Webview)设置style + if(callProp.callType === 'showLoading'){ + me.showLoading(ins) + }else if(callProp.callType === 'endDownScroll'){ + me.endDownScroll(ins) + }else if(callProp.callType === 'clearTransform'){ + me.clearTransform(ins) + } + } +} + +/** + * touch事件 + */ +function touchstartEvent(e, ins) { + me.downHight = 0; // 下拉的距离 + me.startPoint = me.getPoint(e); // 记录起点 + me.startTop = me.getScrollTop(); // 记录此时的滚动条位置 + me.startAngle = 0; // 初始角度 + me.lastPoint = me.startPoint; // 重置上次move的点 + me.maxTouchmoveY = me.getBodyHeight() - me.optDown.bottomOffset; // 手指触摸的最大范围(写在touchstart避免body获取高度为0的情况) + me.inTouchend = false; // 标记不是touchend + + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +function touchmoveEvent(e, ins) { + var isPrevent = true // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) + + if (me.disabled()) return isPrevent; + + var scrollTop = me.getScrollTop(); // 当前滚动条的距离 + var curPoint = me.getPoint(e); // 当前点 + + var moveY = curPoint.y - me.startPoint.y; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + + // 向下拉 && 在顶部 + // mescroll-body,直接判定在顶部即可 + // scroll-view在滚动时不会触发touchmove,当触顶/底/左/右时,才会触发touchmove + // scroll-view滚动到顶部时,scrollTop不一定为0,也有可能大于0; 在iOS的APP中scrollTop可能为负数,不一定和startTop相等 + if (moveY > 0 && ( + (me.isScrollBody && scrollTop <= 0) + || + (!me.isScrollBody && (scrollTop <= 0 || (scrollTop <= me.optDown.startTop && scrollTop === me.startTop)) ) + )) { + // 可下拉的条件 + if (!me.inTouchend && !me.isDownScrolling && !me.optDown.isLock && (!me.isUpScrolling || (me.isUpScrolling && + me.isUpBoth))) { + + // 下拉的角度是否在配置的范围内 + if(!me.startAngle) me.startAngle = me.getAngle(me.lastPoint, curPoint); // 两点之间的角度,区间 [0,90] + if (me.startAngle < me.optDown.minAngle) return isPrevent; // 如果小于配置的角度,则不往下执行下拉刷新 + + // 如果手指的位置超过配置的距离,则提前结束下拉,避免Webview嵌套导致touchend无法触发 + if (me.maxTouchmoveY > 0 && curPoint.y >= me.maxTouchmoveY) { + me.inTouchend = true; // 标记执行touchend + touchendEvent(e, ins); // 提前触发touchend + return isPrevent; + } + + isPrevent = false // 小程序是return false + + var diff = curPoint.y - me.lastPoint.y; // 和上次比,移动的距离 (大于0向下,小于0向上) + + // 下拉距离 < 指定距离 + if (me.downHight < me.optDown.offset) { + if (me.movetype !== 1) { + me.movetype = 1; // 加入标记,保证只执行一次 + // me.optDown.inOffset && me.optDown.inOffset(me); // 进入指定距离范围内那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 1}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + me.downHight += diff * me.optDown.inOffsetRate; // 越往下,高度变化越小 + + // 指定距离 <= 下拉距离 + } else { + if (me.movetype !== 2) { + me.movetype = 2; // 加入标记,保证只执行一次 + // me.optDown.outOffset && me.optDown.outOffset(me); // 下拉超过指定距离那一刻的回调,只执行一次 + me.callMethod(ins, {type: 'setLoadType', downLoadType: 2}) + me.isMoveDown = true; // 标记下拉区域高度改变,在touchend重置回来 + } + if (diff > 0) { // 向下拉 + me.downHight += diff * me.optDown.outOffsetRate; // 越往下,高度变化越小 + } else { // 向上收 + me.downHight += diff; // 向上收回高度,则向上滑多少收多少高度 + } + } + + me.downHight = Math.round(me.downHight) // 取整 + var rate = me.downHight / me.optDown.offset; // 下拉区域当前高度与指定距离的比值 + // me.optDown.onMoving && me.optDown.onMoving(me, rate, me.downHight); // 下拉过程中的回调,一直在执行 + me.onMoving(ins, rate, me.downHight) + } + } + + me.lastPoint = curPoint; // 记录本次移动的点 + + return isPrevent // false表示不往上冒泡,相当于调用了同时调用了stopPropagation和preventDefault (对小程序生效, h5和app无效) +} + +function touchendEvent(e, ins) { + // 如果下拉区域高度已改变,则需重置回来 + if (me.isMoveDown) { + if (me.downHight >= me.optDown.offset) { + // 符合触发刷新的条件 + me.downHight = me.optDown.offset; // 更新下拉区域高度 + // me.triggerDownScroll(); + me.callMethod(ins, {type: 'triggerDownScroll'}) + } else { + // 不符合的话 则重置 + me.downHight = 0; + // me.optDown.endDownScroll && me.optDown.endDownScroll(me); + me.callMethod(ins, {type: 'endDownScroll'}) + } + me.movetype = 0; + me.isMoveDown = false; + } else if (!me.isScrollBody && me.getScrollTop() === me.startTop) { // scroll-view到顶/左/右/底的滑动事件 + var isScrollUp = me.getPoint(e).y - me.startPoint.y < 0; // 和起点比,移动的距离,大于0向下拉,小于0向上拉 + // 上滑 + if (isScrollUp) { + // 需检查滑动的角度 + var angle = me.getAngle(me.getPoint(e), me.startPoint); // 两点之间的角度,区间 [0,90] + if (angle > 80) { + // 检查并触发上拉 + // me.triggerUpScroll(true); + me.callMethod(ins, {type: 'triggerUpScroll'}) + } + } + } + me.callMethod(ins, {type: 'setWxsProp'}) // 同步更新wxsProp的数据 (小程序是异步的,可能touchmove先执行,才到propObserver; h5和app是同步) +} + +/* 是否禁用下拉刷新 */ +me.disabled = function(){ + return !me.optDown || !me.optDown.use || me.optDown.native +} + +/* 根据点击滑动事件获取第一个手指的坐标 */ +me.getPoint = function(e) { + if (!e) { + return {x: 0,y: 0} + } + if (e.touches && e.touches[0]) { + return {x: e.touches[0].pageX,y: e.touches[0].pageY} + } else if (e.changedTouches && e.changedTouches[0]) { + return {x: e.changedTouches[0].pageX,y: e.changedTouches[0].pageY} + } else { + return {x: e.clientX,y: e.clientY} + } +} + +/* 计算两点之间的角度: 区间 [0,90]*/ +me.getAngle = function (p1, p2) { + var x = Math.abs(p1.x - p2.x); + var y = Math.abs(p1.y - p2.y); + var z = Math.sqrt(x * x + y * y); + var angle = 0; + if (z !== 0) { + angle = Math.asin(y / z) / Math.PI * 180; + } + return angle +} + +/* 获取滚动条的位置 */ +me.getScrollTop = function() { + return me.scrollTop || 0 +} + +/* 获取body的高度 */ +me.getBodyHeight = function() { + return me.bodyHeight || 0; +} + +/* 调用逻辑层的方法 */ +me.callMethod = function(ins, param) { + if(ins) ins.callMethod('wxsCall', param) +} + +/* 导出模块 */ +module.exports = { + propObserver: propObserver, + callObserver: callObserver, + touchstartEvent: touchstartEvent, + touchmoveEvent: touchmoveEvent, + touchendEvent: touchendEvent +} \ No newline at end of file diff --git a/components/mplogin-popup/mplogin-popup.vue b/components/mplogin-popup/mplogin-popup.vue new file mode 100644 index 0000000..9f0e3b9 --- /dev/null +++ b/components/mplogin-popup/mplogin-popup.vue @@ -0,0 +1,204 @@ + + + + + diff --git a/components/my-coupons/my-coupons.vue b/components/my-coupons/my-coupons.vue new file mode 100644 index 0000000..7a19c1c --- /dev/null +++ b/components/my-coupons/my-coupons.vue @@ -0,0 +1,72 @@ + + + + diff --git a/components/order-dialog/order-dialog.vue b/components/order-dialog/order-dialog.vue new file mode 100644 index 0000000..8a6a6b6 --- /dev/null +++ b/components/order-dialog/order-dialog.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/components/order-goods/order-goods.vue b/components/order-goods/order-goods.vue new file mode 100644 index 0000000..772a60f --- /dev/null +++ b/components/order-goods/order-goods.vue @@ -0,0 +1,147 @@ + + + + diff --git a/components/order-list/order-list.vue b/components/order-list/order-list.vue new file mode 100644 index 0000000..15fed33 --- /dev/null +++ b/components/order-list/order-list.vue @@ -0,0 +1,314 @@ + + + + + + + diff --git a/components/order-shop/order-shop.vue b/components/order-shop/order-shop.vue new file mode 100644 index 0000000..c86450b --- /dev/null +++ b/components/order-shop/order-shop.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/components/price-format/price-format.vue b/components/price-format/price-format.vue new file mode 100644 index 0000000..dd445b7 --- /dev/null +++ b/components/price-format/price-format.vue @@ -0,0 +1,86 @@ + + + + \ No newline at end of file diff --git a/components/product-swiper/product-swiper.vue b/components/product-swiper/product-swiper.vue new file mode 100644 index 0000000..6940a0d --- /dev/null +++ b/components/product-swiper/product-swiper.vue @@ -0,0 +1,146 @@ + + + + diff --git a/components/record-cell/record-cell.vue b/components/record-cell/record-cell.vue new file mode 100644 index 0000000..14e78df --- /dev/null +++ b/components/record-cell/record-cell.vue @@ -0,0 +1,53 @@ + + + + + + diff --git a/components/share-popup/poster.vue b/components/share-popup/poster.vue new file mode 100644 index 0000000..3035881 --- /dev/null +++ b/components/share-popup/poster.vue @@ -0,0 +1,147 @@ + + + + + diff --git a/components/share-popup/share-popup.vue b/components/share-popup/share-popup.vue new file mode 100644 index 0000000..1cdf887 --- /dev/null +++ b/components/share-popup/share-popup.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/components/shop-item/shop-item.vue b/components/shop-item/shop-item.vue new file mode 100644 index 0000000..935bd0b --- /dev/null +++ b/components/shop-item/shop-item.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/components/shop-recommend/shop-recommend.vue b/components/shop-recommend/shop-recommend.vue new file mode 100644 index 0000000..b878580 --- /dev/null +++ b/components/shop-recommend/shop-recommend.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/components/shop-title/shop-title.vue b/components/shop-title/shop-title.vue new file mode 100644 index 0000000..c8f7bfe --- /dev/null +++ b/components/shop-title/shop-title.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/components/sort-nav/sort-nav.vue b/components/sort-nav/sort-nav.vue new file mode 100644 index 0000000..a74a824 --- /dev/null +++ b/components/sort-nav/sort-nav.vue @@ -0,0 +1,118 @@ + + + + + diff --git a/components/spec-popup/spec-popup.vue b/components/spec-popup/spec-popup.vue new file mode 100644 index 0000000..e4cf7ef --- /dev/null +++ b/components/spec-popup/spec-popup.vue @@ -0,0 +1,418 @@ + + + + diff --git a/components/spread-order/spread-order.vue b/components/spread-order/spread-order.vue new file mode 100644 index 0000000..572f84f --- /dev/null +++ b/components/spread-order/spread-order.vue @@ -0,0 +1,197 @@ + + + + diff --git a/components/tab/tab.vue b/components/tab/tab.vue new file mode 100644 index 0000000..2da702d --- /dev/null +++ b/components/tab/tab.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/components/tabbar/tabbar.vue b/components/tabbar/tabbar.vue new file mode 100644 index 0000000..d136c91 --- /dev/null +++ b/components/tabbar/tabbar.vue @@ -0,0 +1,47 @@ + + + diff --git a/components/tabs/tabs.vue b/components/tabs/tabs.vue new file mode 100644 index 0000000..2c27c41 --- /dev/null +++ b/components/tabs/tabs.vue @@ -0,0 +1,428 @@ + + + + + diff --git a/components/tki-qrcode/qrcode.js b/components/tki-qrcode/qrcode.js new file mode 100644 index 0000000..6ea6553 --- /dev/null +++ b/components/tki-qrcode/qrcode.js @@ -0,0 +1,1201 @@ +let QRCode = {}; +(function () { + /** + * 获取单个字符的utf8编码 + * unicode BMP平面约65535个字符 + * @param {num} code + * return {array} + */ + function unicodeFormat8(code) { + // 1 byte + var c0, c1, c2; + if (code < 128) { + return [code]; + // 2 bytes + } else if (code < 2048) { + c0 = 192 + (code >> 6); + c1 = 128 + (code & 63); + return [c0, c1]; + // 3 bytes + } else { + c0 = 224 + (code >> 12); + c1 = 128 + (code >> 6 & 63); + c2 = 128 + (code & 63); + return [c0, c1, c2]; + } + } + /** + * 获取字符串的utf8编码字节串 + * @param {string} string + * @return {array} + */ + function getUTF8Bytes(string) { + var utf8codes = []; + for (var i = 0; i < string.length; i++) { + var code = string.charCodeAt(i); + var utf8 = unicodeFormat8(code); + for (var j = 0; j < utf8.length; j++) { + utf8codes.push(utf8[j]); + } + } + return utf8codes; + } + /** + * 二维码算法实现 + * @param {string} data 要编码的信息字符串 + * @param {num} errorCorrectLevel 纠错等级 + */ + function QRCodeAlg(data, errorCorrectLevel) { + this.typeNumber = -1; //版本 + this.errorCorrectLevel = errorCorrectLevel; + this.modules = null; //二维矩阵,存放最终结果 + this.moduleCount = 0; //矩阵大小 + this.dataCache = null; //数据缓存 + this.rsBlocks = null; //版本数据信息 + this.totalDataCount = -1; //可使用的数据量 + this.data = data; + this.utf8bytes = getUTF8Bytes(data); + this.make(); + } + QRCodeAlg.prototype = { + constructor: QRCodeAlg, + /** + * 获取二维码矩阵大小 + * @return {num} 矩阵大小 + */ + getModuleCount: function () { + return this.moduleCount; + }, + /** + * 编码 + */ + make: function () { + this.getRightType(); + this.dataCache = this.createData(); + this.createQrcode(); + }, + /** + * 设置二位矩阵功能图形 + * @param {bool} test 表示是否在寻找最好掩膜阶段 + * @param {num} maskPattern 掩膜的版本 + */ + makeImpl: function (maskPattern) { + this.moduleCount = this.typeNumber * 4 + 17; + this.modules = new Array(this.moduleCount); + for (var row = 0; row < this.moduleCount; row++) { + this.modules[row] = new Array(this.moduleCount); + } + this.setupPositionProbePattern(0, 0); + this.setupPositionProbePattern(this.moduleCount - 7, 0); + this.setupPositionProbePattern(0, this.moduleCount - 7); + this.setupPositionAdjustPattern(); + this.setupTimingPattern(); + this.setupTypeInfo(true, maskPattern); + if (this.typeNumber >= 7) { + this.setupTypeNumber(true); + } + this.mapData(this.dataCache, maskPattern); + }, + /** + * 设置二维码的位置探测图形 + * @param {num} row 探测图形的中心横坐标 + * @param {num} col 探测图形的中心纵坐标 + */ + setupPositionProbePattern: function (row, col) { + for (var r = -1; r <= 7; r++) { + if (row + r <= -1 || this.moduleCount <= row + r) continue; + for (var c = -1; c <= 7; c++) { + if (col + c <= -1 || this.moduleCount <= col + c) continue; + if ((0 <= r && r <= 6 && (c == 0 || c == 6)) || (0 <= c && c <= 6 && (r == 0 || r == 6)) || (2 <= r && r <= 4 && 2 <= c && c <= 4)) { + this.modules[row + r][col + c] = true; + } else { + this.modules[row + r][col + c] = false; + } + } + } + }, + /** + * 创建二维码 + * @return {[type]} [description] + */ + createQrcode: function () { + var minLostPoint = 0; + var pattern = 0; + var bestModules = null; + for (var i = 0; i < 8; i++) { + this.makeImpl(i); + var lostPoint = QRUtil.getLostPoint(this); + if (i == 0 || minLostPoint > lostPoint) { + minLostPoint = lostPoint; + pattern = i; + bestModules = this.modules; + } + } + this.modules = bestModules; + this.setupTypeInfo(false, pattern); + if (this.typeNumber >= 7) { + this.setupTypeNumber(false); + } + }, + /** + * 设置定位图形 + * @return {[type]} [description] + */ + setupTimingPattern: function () { + for (var r = 8; r < this.moduleCount - 8; r++) { + if (this.modules[r][6] != null) { + continue; + } + this.modules[r][6] = (r % 2 == 0); + if (this.modules[6][r] != null) { + continue; + } + this.modules[6][r] = (r % 2 == 0); + } + }, + /** + * 设置矫正图形 + * @return {[type]} [description] + */ + setupPositionAdjustPattern: function () { + var pos = QRUtil.getPatternPosition(this.typeNumber); + for (var i = 0; i < pos.length; i++) { + for (var j = 0; j < pos.length; j++) { + var row = pos[i]; + var col = pos[j]; + if (this.modules[row][col] != null) { + continue; + } + for (var r = -2; r <= 2; r++) { + for (var c = -2; c <= 2; c++) { + if (r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0)) { + this.modules[row + r][col + c] = true; + } else { + this.modules[row + r][col + c] = false; + } + } + } + } + } + }, + /** + * 设置版本信息(7以上版本才有) + * @param {bool} test 是否处于判断最佳掩膜阶段 + * @return {[type]} [description] + */ + setupTypeNumber: function (test) { + var bits = QRUtil.getBCHTypeNumber(this.typeNumber); + for (var i = 0; i < 18; i++) { + var mod = (!test && ((bits >> i) & 1) == 1); + this.modules[Math.floor(i / 3)][i % 3 + this.moduleCount - 8 - 3] = mod; + this.modules[i % 3 + this.moduleCount - 8 - 3][Math.floor(i / 3)] = mod; + } + }, + /** + * 设置格式信息(纠错等级和掩膜版本) + * @param {bool} test + * @param {num} maskPattern 掩膜版本 + * @return {} + */ + setupTypeInfo: function (test, maskPattern) { + var data = (QRErrorCorrectLevel[this.errorCorrectLevel] << 3) | maskPattern; + var bits = QRUtil.getBCHTypeInfo(data); + // vertical + for (var i = 0; i < 15; i++) { + var mod = (!test && ((bits >> i) & 1) == 1); + if (i < 6) { + this.modules[i][8] = mod; + } else if (i < 8) { + this.modules[i + 1][8] = mod; + } else { + this.modules[this.moduleCount - 15 + i][8] = mod; + } + // horizontal + var mod = (!test && ((bits >> i) & 1) == 1); + if (i < 8) { + this.modules[8][this.moduleCount - i - 1] = mod; + } else if (i < 9) { + this.modules[8][15 - i - 1 + 1] = mod; + } else { + this.modules[8][15 - i - 1] = mod; + } + } + // fixed module + this.modules[this.moduleCount - 8][8] = (!test); + }, + /** + * 数据编码 + * @return {[type]} [description] + */ + createData: function () { + var buffer = new QRBitBuffer(); + var lengthBits = this.typeNumber > 9 ? 16 : 8; + buffer.put(4, 4); //添加模式 + buffer.put(this.utf8bytes.length, lengthBits); + for (var i = 0, l = this.utf8bytes.length; i < l; i++) { + buffer.put(this.utf8bytes[i], 8); + } + if (buffer.length + 4 <= this.totalDataCount * 8) { + buffer.put(0, 4); + } + // padding + while (buffer.length % 8 != 0) { + buffer.putBit(false); + } + // padding + while (true) { + if (buffer.length >= this.totalDataCount * 8) { + break; + } + buffer.put(QRCodeAlg.PAD0, 8); + if (buffer.length >= this.totalDataCount * 8) { + break; + } + buffer.put(QRCodeAlg.PAD1, 8); + } + return this.createBytes(buffer); + }, + /** + * 纠错码编码 + * @param {buffer} buffer 数据编码 + * @return {[type]} + */ + createBytes: function (buffer) { + var offset = 0; + var maxDcCount = 0; + var maxEcCount = 0; + var length = this.rsBlock.length / 3; + var rsBlocks = new Array(); + for (var i = 0; i < length; i++) { + var count = this.rsBlock[i * 3 + 0]; + var totalCount = this.rsBlock[i * 3 + 1]; + var dataCount = this.rsBlock[i * 3 + 2]; + for (var j = 0; j < count; j++) { + rsBlocks.push([dataCount, totalCount]); + } + } + var dcdata = new Array(rsBlocks.length); + var ecdata = new Array(rsBlocks.length); + for (var r = 0; r < rsBlocks.length; r++) { + var dcCount = rsBlocks[r][0]; + var ecCount = rsBlocks[r][1] - dcCount; + maxDcCount = Math.max(maxDcCount, dcCount); + maxEcCount = Math.max(maxEcCount, ecCount); + dcdata[r] = new Array(dcCount); + for (var i = 0; i < dcdata[r].length; i++) { + dcdata[r][i] = 0xff & buffer.buffer[i + offset]; + } + offset += dcCount; + var rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount); + var rawPoly = new QRPolynomial(dcdata[r], rsPoly.getLength() - 1); + var modPoly = rawPoly.mod(rsPoly); + ecdata[r] = new Array(rsPoly.getLength() - 1); + for (var i = 0; i < ecdata[r].length; i++) { + var modIndex = i + modPoly.getLength() - ecdata[r].length; + ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0; + } + } + var data = new Array(this.totalDataCount); + var index = 0; + for (var i = 0; i < maxDcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < dcdata[r].length) { + data[index++] = dcdata[r][i]; + } + } + } + for (var i = 0; i < maxEcCount; i++) { + for (var r = 0; r < rsBlocks.length; r++) { + if (i < ecdata[r].length) { + data[index++] = ecdata[r][i]; + } + } + } + return data; + + }, + /** + * 布置模块,构建最终信息 + * @param {} data + * @param {} maskPattern + * @return {} + */ + mapData: function (data, maskPattern) { + var inc = -1; + var row = this.moduleCount - 1; + var bitIndex = 7; + var byteIndex = 0; + for (var col = this.moduleCount - 1; col > 0; col -= 2) { + if (col == 6) col--; + while (true) { + for (var c = 0; c < 2; c++) { + if (this.modules[row][col - c] == null) { + var dark = false; + if (byteIndex < data.length) { + dark = (((data[byteIndex] >>> bitIndex) & 1) == 1); + } + var mask = QRUtil.getMask(maskPattern, row, col - c); + if (mask) { + dark = !dark; + } + this.modules[row][col - c] = dark; + bitIndex--; + if (bitIndex == -1) { + byteIndex++; + bitIndex = 7; + } + } + } + row += inc; + if (row < 0 || this.moduleCount <= row) { + row -= inc; + inc = -inc; + break; + } + } + } + } + }; + /** + * 填充字段 + */ + QRCodeAlg.PAD0 = 0xEC; + QRCodeAlg.PAD1 = 0x11; + //--------------------------------------------------------------------- + // 纠错等级对应的编码 + //--------------------------------------------------------------------- + var QRErrorCorrectLevel = [1, 0, 3, 2]; + //--------------------------------------------------------------------- + // 掩膜版本 + //--------------------------------------------------------------------- + var QRMaskPattern = { + PATTERN000: 0, + PATTERN001: 1, + PATTERN010: 2, + PATTERN011: 3, + PATTERN100: 4, + PATTERN101: 5, + PATTERN110: 6, + PATTERN111: 7 + }; + //--------------------------------------------------------------------- + // 工具类 + //--------------------------------------------------------------------- + var QRUtil = { + /* + 每个版本矫正图形的位置 + */ + PATTERN_POSITION_TABLE: [ + [], + [6, 18], + [6, 22], + [6, 26], + [6, 30], + [6, 34], + [6, 22, 38], + [6, 24, 42], + [6, 26, 46], + [6, 28, 50], + [6, 30, 54], + [6, 32, 58], + [6, 34, 62], + [6, 26, 46, 66], + [6, 26, 48, 70], + [6, 26, 50, 74], + [6, 30, 54, 78], + [6, 30, 56, 82], + [6, 30, 58, 86], + [6, 34, 62, 90], + [6, 28, 50, 72, 94], + [6, 26, 50, 74, 98], + [6, 30, 54, 78, 102], + [6, 28, 54, 80, 106], + [6, 32, 58, 84, 110], + [6, 30, 58, 86, 114], + [6, 34, 62, 90, 118], + [6, 26, 50, 74, 98, 122], + [6, 30, 54, 78, 102, 126], + [6, 26, 52, 78, 104, 130], + [6, 30, 56, 82, 108, 134], + [6, 34, 60, 86, 112, 138], + [6, 30, 58, 86, 114, 142], + [6, 34, 62, 90, 118, 146], + [6, 30, 54, 78, 102, 126, 150], + [6, 24, 50, 76, 102, 128, 154], + [6, 28, 54, 80, 106, 132, 158], + [6, 32, 58, 84, 110, 136, 162], + [6, 26, 54, 82, 110, 138, 166], + [6, 30, 58, 86, 114, 142, 170] + ], + G15: (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0), + G18: (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0), + G15_MASK: (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1), + /* + BCH编码格式信息 + */ + getBCHTypeInfo: function (data) { + var d = data << 10; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15) >= 0) { + d ^= (QRUtil.G15 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G15))); + } + return ((data << 10) | d) ^ QRUtil.G15_MASK; + }, + /* + BCH编码版本信息 + */ + getBCHTypeNumber: function (data) { + var d = data << 12; + while (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18) >= 0) { + d ^= (QRUtil.G18 << (QRUtil.getBCHDigit(d) - QRUtil.getBCHDigit(QRUtil.G18))); + } + return (data << 12) | d; + }, + /* + 获取BCH位信息 + */ + getBCHDigit: function (data) { + var digit = 0; + while (data != 0) { + digit++; + data >>>= 1; + } + return digit; + }, + /* + 获取版本对应的矫正图形位置 + */ + getPatternPosition: function (typeNumber) { + return QRUtil.PATTERN_POSITION_TABLE[typeNumber - 1]; + }, + /* + 掩膜算法 + */ + getMask: function (maskPattern, i, j) { + switch (maskPattern) { + case QRMaskPattern.PATTERN000: + return (i + j) % 2 == 0; + case QRMaskPattern.PATTERN001: + return i % 2 == 0; + case QRMaskPattern.PATTERN010: + return j % 3 == 0; + case QRMaskPattern.PATTERN011: + return (i + j) % 3 == 0; + case QRMaskPattern.PATTERN100: + return (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0; + case QRMaskPattern.PATTERN101: + return (i * j) % 2 + (i * j) % 3 == 0; + case QRMaskPattern.PATTERN110: + return ((i * j) % 2 + (i * j) % 3) % 2 == 0; + case QRMaskPattern.PATTERN111: + return ((i * j) % 3 + (i + j) % 2) % 2 == 0; + default: + throw new Error("bad maskPattern:" + maskPattern); + } + }, + /* + 获取RS的纠错多项式 + */ + getErrorCorrectPolynomial: function (errorCorrectLength) { + var a = new QRPolynomial([1], 0); + for (var i = 0; i < errorCorrectLength; i++) { + a = a.multiply(new QRPolynomial([1, QRMath.gexp(i)], 0)); + } + return a; + }, + /* + 获取评价 + */ + getLostPoint: function (qrCode) { + var moduleCount = qrCode.getModuleCount(), + lostPoint = 0, + darkCount = 0; + for (var row = 0; row < moduleCount; row++) { + var sameCount = 0; + var head = qrCode.modules[row][0]; + for (var col = 0; col < moduleCount; col++) { + var current = qrCode.modules[row][col]; + //level 3 评价 + if (col < moduleCount - 6) { + if (current && !qrCode.modules[row][col + 1] && qrCode.modules[row][col + 2] && qrCode.modules[row][col + 3] && qrCode.modules[row][col + 4] && !qrCode.modules[row][col + 5] && qrCode.modules[row][col + 6]) { + if (col < moduleCount - 10) { + if (qrCode.modules[row][col + 7] && qrCode.modules[row][col + 8] && qrCode.modules[row][col + 9] && qrCode.modules[row][col + 10]) { + lostPoint += 40; + } + } else if (col > 3) { + if (qrCode.modules[row][col - 1] && qrCode.modules[row][col - 2] && qrCode.modules[row][col - 3] && qrCode.modules[row][col - 4]) { + lostPoint += 40; + } + } + } + } + //level 2 评价 + if ((row < moduleCount - 1) && (col < moduleCount - 1)) { + var count = 0; + if (current) count++; + if (qrCode.modules[row + 1][col]) count++; + if (qrCode.modules[row][col + 1]) count++; + if (qrCode.modules[row + 1][col + 1]) count++; + if (count == 0 || count == 4) { + lostPoint += 3; + } + } + //level 1 评价 + if (head ^ current) { + sameCount++; + } else { + head = current; + if (sameCount >= 5) { + lostPoint += (3 + sameCount - 5); + } + sameCount = 1; + } + //level 4 评价 + if (current) { + darkCount++; + } + } + } + for (var col = 0; col < moduleCount; col++) { + var sameCount = 0; + var head = qrCode.modules[0][col]; + for (var row = 0; row < moduleCount; row++) { + var current = qrCode.modules[row][col]; + //level 3 评价 + if (row < moduleCount - 6) { + if (current && !qrCode.modules[row + 1][col] && qrCode.modules[row + 2][col] && qrCode.modules[row + 3][col] && qrCode.modules[row + 4][col] && !qrCode.modules[row + 5][col] && qrCode.modules[row + 6][col]) { + if (row < moduleCount - 10) { + if (qrCode.modules[row + 7][col] && qrCode.modules[row + 8][col] && qrCode.modules[row + 9][col] && qrCode.modules[row + 10][col]) { + lostPoint += 40; + } + } else if (row > 3) { + if (qrCode.modules[row - 1][col] && qrCode.modules[row - 2][col] && qrCode.modules[row - 3][col] && qrCode.modules[row - 4][col]) { + lostPoint += 40; + } + } + } + } + //level 1 评价 + if (head ^ current) { + sameCount++; + } else { + head = current; + if (sameCount >= 5) { + lostPoint += (3 + sameCount - 5); + } + sameCount = 1; + } + } + } + // LEVEL4 + var ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5; + lostPoint += ratio * 10; + return lostPoint; + } + + }; + //--------------------------------------------------------------------- + // QRMath使用的数学工具 + //--------------------------------------------------------------------- + var QRMath = { + /* + 将n转化为a^m + */ + glog: function (n) { + if (n < 1) { + throw new Error("glog(" + n + ")"); + } + return QRMath.LOG_TABLE[n]; + }, + /* + 将a^m转化为n + */ + gexp: function (n) { + while (n < 0) { + n += 255; + } + while (n >= 256) { + n -= 255; + } + return QRMath.EXP_TABLE[n]; + }, + EXP_TABLE: new Array(256), + LOG_TABLE: new Array(256) + + }; + for (var i = 0; i < 8; i++) { + QRMath.EXP_TABLE[i] = 1 << i; + } + for (var i = 8; i < 256; i++) { + QRMath.EXP_TABLE[i] = QRMath.EXP_TABLE[i - 4] ^ QRMath.EXP_TABLE[i - 5] ^ QRMath.EXP_TABLE[i - 6] ^ QRMath.EXP_TABLE[i - 8]; + } + for (var i = 0; i < 255; i++) { + QRMath.LOG_TABLE[QRMath.EXP_TABLE[i]] = i; + } + //--------------------------------------------------------------------- + // QRPolynomial 多项式 + //--------------------------------------------------------------------- + /** + * 多项式类 + * @param {Array} num 系数 + * @param {num} shift a^shift + */ + function QRPolynomial(num, shift) { + if (num.length == undefined) { + throw new Error(num.length + "/" + shift); + } + var offset = 0; + while (offset < num.length && num[offset] == 0) { + offset++; + } + this.num = new Array(num.length - offset + shift); + for (var i = 0; i < num.length - offset; i++) { + this.num[i] = num[i + offset]; + } + } + QRPolynomial.prototype = { + get: function (index) { + return this.num[index]; + }, + getLength: function () { + return this.num.length; + }, + /** + * 多项式乘法 + * @param {QRPolynomial} e 被乘多项式 + * @return {[type]} [description] + */ + multiply: function (e) { + var num = new Array(this.getLength() + e.getLength() - 1); + for (var i = 0; i < this.getLength(); i++) { + for (var j = 0; j < e.getLength(); j++) { + num[i + j] ^= QRMath.gexp(QRMath.glog(this.get(i)) + QRMath.glog(e.get(j))); + } + } + return new QRPolynomial(num, 0); + }, + /** + * 多项式模运算 + * @param {QRPolynomial} e 模多项式 + * @return {} + */ + mod: function (e) { + var tl = this.getLength(), + el = e.getLength(); + if (tl - el < 0) { + return this; + } + var num = new Array(tl); + for (var i = 0; i < tl; i++) { + num[i] = this.get(i); + } + while (num.length >= el) { + var ratio = QRMath.glog(num[0]) - QRMath.glog(e.get(0)); + + for (var i = 0; i < e.getLength(); i++) { + num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio); + } + while (num[0] == 0) { + num.shift(); + } + } + return new QRPolynomial(num, 0); + } + }; + + //--------------------------------------------------------------------- + // RS_BLOCK_TABLE + //--------------------------------------------------------------------- + /* + 二维码各个版本信息[块数, 每块中的数据块数, 每块中的信息块数] + */ + var RS_BLOCK_TABLE = [ + // L + // M + // Q + // H + // 1 + [1, 26, 19], + [1, 26, 16], + [1, 26, 13], + [1, 26, 9], + + // 2 + [1, 44, 34], + [1, 44, 28], + [1, 44, 22], + [1, 44, 16], + + // 3 + [1, 70, 55], + [1, 70, 44], + [2, 35, 17], + [2, 35, 13], + + // 4 + [1, 100, 80], + [2, 50, 32], + [2, 50, 24], + [4, 25, 9], + + // 5 + [1, 134, 108], + [2, 67, 43], + [2, 33, 15, 2, 34, 16], + [2, 33, 11, 2, 34, 12], + + // 6 + [2, 86, 68], + [4, 43, 27], + [4, 43, 19], + [4, 43, 15], + + // 7 + [2, 98, 78], + [4, 49, 31], + [2, 32, 14, 4, 33, 15], + [4, 39, 13, 1, 40, 14], + + // 8 + [2, 121, 97], + [2, 60, 38, 2, 61, 39], + [4, 40, 18, 2, 41, 19], + [4, 40, 14, 2, 41, 15], + + // 9 + [2, 146, 116], + [3, 58, 36, 2, 59, 37], + [4, 36, 16, 4, 37, 17], + [4, 36, 12, 4, 37, 13], + + // 10 + [2, 86, 68, 2, 87, 69], + [4, 69, 43, 1, 70, 44], + [6, 43, 19, 2, 44, 20], + [6, 43, 15, 2, 44, 16], + + // 11 + [4, 101, 81], + [1, 80, 50, 4, 81, 51], + [4, 50, 22, 4, 51, 23], + [3, 36, 12, 8, 37, 13], + + // 12 + [2, 116, 92, 2, 117, 93], + [6, 58, 36, 2, 59, 37], + [4, 46, 20, 6, 47, 21], + [7, 42, 14, 4, 43, 15], + + // 13 + [4, 133, 107], + [8, 59, 37, 1, 60, 38], + [8, 44, 20, 4, 45, 21], + [12, 33, 11, 4, 34, 12], + + // 14 + [3, 145, 115, 1, 146, 116], + [4, 64, 40, 5, 65, 41], + [11, 36, 16, 5, 37, 17], + [11, 36, 12, 5, 37, 13], + + // 15 + [5, 109, 87, 1, 110, 88], + [5, 65, 41, 5, 66, 42], + [5, 54, 24, 7, 55, 25], + [11, 36, 12], + + // 16 + [5, 122, 98, 1, 123, 99], + [7, 73, 45, 3, 74, 46], + [15, 43, 19, 2, 44, 20], + [3, 45, 15, 13, 46, 16], + + // 17 + [1, 135, 107, 5, 136, 108], + [10, 74, 46, 1, 75, 47], + [1, 50, 22, 15, 51, 23], + [2, 42, 14, 17, 43, 15], + + // 18 + [5, 150, 120, 1, 151, 121], + [9, 69, 43, 4, 70, 44], + [17, 50, 22, 1, 51, 23], + [2, 42, 14, 19, 43, 15], + + // 19 + [3, 141, 113, 4, 142, 114], + [3, 70, 44, 11, 71, 45], + [17, 47, 21, 4, 48, 22], + [9, 39, 13, 16, 40, 14], + + // 20 + [3, 135, 107, 5, 136, 108], + [3, 67, 41, 13, 68, 42], + [15, 54, 24, 5, 55, 25], + [15, 43, 15, 10, 44, 16], + + // 21 + [4, 144, 116, 4, 145, 117], + [17, 68, 42], + [17, 50, 22, 6, 51, 23], + [19, 46, 16, 6, 47, 17], + + // 22 + [2, 139, 111, 7, 140, 112], + [17, 74, 46], + [7, 54, 24, 16, 55, 25], + [34, 37, 13], + + // 23 + [4, 151, 121, 5, 152, 122], + [4, 75, 47, 14, 76, 48], + [11, 54, 24, 14, 55, 25], + [16, 45, 15, 14, 46, 16], + + // 24 + [6, 147, 117, 4, 148, 118], + [6, 73, 45, 14, 74, 46], + [11, 54, 24, 16, 55, 25], + [30, 46, 16, 2, 47, 17], + + // 25 + [8, 132, 106, 4, 133, 107], + [8, 75, 47, 13, 76, 48], + [7, 54, 24, 22, 55, 25], + [22, 45, 15, 13, 46, 16], + + // 26 + [10, 142, 114, 2, 143, 115], + [19, 74, 46, 4, 75, 47], + [28, 50, 22, 6, 51, 23], + [33, 46, 16, 4, 47, 17], + + // 27 + [8, 152, 122, 4, 153, 123], + [22, 73, 45, 3, 74, 46], + [8, 53, 23, 26, 54, 24], + [12, 45, 15, 28, 46, 16], + + // 28 + [3, 147, 117, 10, 148, 118], + [3, 73, 45, 23, 74, 46], + [4, 54, 24, 31, 55, 25], + [11, 45, 15, 31, 46, 16], + + // 29 + [7, 146, 116, 7, 147, 117], + [21, 73, 45, 7, 74, 46], + [1, 53, 23, 37, 54, 24], + [19, 45, 15, 26, 46, 16], + + // 30 + [5, 145, 115, 10, 146, 116], + [19, 75, 47, 10, 76, 48], + [15, 54, 24, 25, 55, 25], + [23, 45, 15, 25, 46, 16], + + // 31 + [13, 145, 115, 3, 146, 116], + [2, 74, 46, 29, 75, 47], + [42, 54, 24, 1, 55, 25], + [23, 45, 15, 28, 46, 16], + + // 32 + [17, 145, 115], + [10, 74, 46, 23, 75, 47], + [10, 54, 24, 35, 55, 25], + [19, 45, 15, 35, 46, 16], + + // 33 + [17, 145, 115, 1, 146, 116], + [14, 74, 46, 21, 75, 47], + [29, 54, 24, 19, 55, 25], + [11, 45, 15, 46, 46, 16], + + // 34 + [13, 145, 115, 6, 146, 116], + [14, 74, 46, 23, 75, 47], + [44, 54, 24, 7, 55, 25], + [59, 46, 16, 1, 47, 17], + + // 35 + [12, 151, 121, 7, 152, 122], + [12, 75, 47, 26, 76, 48], + [39, 54, 24, 14, 55, 25], + [22, 45, 15, 41, 46, 16], + + // 36 + [6, 151, 121, 14, 152, 122], + [6, 75, 47, 34, 76, 48], + [46, 54, 24, 10, 55, 25], + [2, 45, 15, 64, 46, 16], + + // 37 + [17, 152, 122, 4, 153, 123], + [29, 74, 46, 14, 75, 47], + [49, 54, 24, 10, 55, 25], + [24, 45, 15, 46, 46, 16], + + // 38 + [4, 152, 122, 18, 153, 123], + [13, 74, 46, 32, 75, 47], + [48, 54, 24, 14, 55, 25], + [42, 45, 15, 32, 46, 16], + + // 39 + [20, 147, 117, 4, 148, 118], + [40, 75, 47, 7, 76, 48], + [43, 54, 24, 22, 55, 25], + [10, 45, 15, 67, 46, 16], + + // 40 + [19, 148, 118, 6, 149, 119], + [18, 75, 47, 31, 76, 48], + [34, 54, 24, 34, 55, 25], + [20, 45, 15, 61, 46, 16] + ]; + + /** + * 根据数据获取对应版本 + * @return {[type]} [description] + */ + QRCodeAlg.prototype.getRightType = function () { + for (var typeNumber = 1; typeNumber < 41; typeNumber++) { + var rsBlock = RS_BLOCK_TABLE[(typeNumber - 1) * 4 + this.errorCorrectLevel]; + if (rsBlock == undefined) { + throw new Error("bad rs block @ typeNumber:" + typeNumber + "/errorCorrectLevel:" + this.errorCorrectLevel); + } + var length = rsBlock.length / 3; + var totalDataCount = 0; + for (var i = 0; i < length; i++) { + var count = rsBlock[i * 3 + 0]; + var dataCount = rsBlock[i * 3 + 2]; + totalDataCount += dataCount * count; + } + var lengthBytes = typeNumber > 9 ? 2 : 1; + if (this.utf8bytes.length + lengthBytes < totalDataCount || typeNumber == 40) { + this.typeNumber = typeNumber; + this.rsBlock = rsBlock; + this.totalDataCount = totalDataCount; + break; + } + } + }; + + //--------------------------------------------------------------------- + // QRBitBuffer + //--------------------------------------------------------------------- + function QRBitBuffer() { + this.buffer = new Array(); + this.length = 0; + } + QRBitBuffer.prototype = { + get: function (index) { + var bufIndex = Math.floor(index / 8); + return ((this.buffer[bufIndex] >>> (7 - index % 8)) & 1); + }, + put: function (num, length) { + for (var i = 0; i < length; i++) { + this.putBit(((num >>> (length - i - 1)) & 1)); + } + }, + putBit: function (bit) { + var bufIndex = Math.floor(this.length / 8); + if (this.buffer.length <= bufIndex) { + this.buffer.push(0); + } + if (bit) { + this.buffer[bufIndex] |= (0x80 >>> (this.length % 8)); + } + this.length++; + } + }; + + + + // xzedit + let qrcodeAlgObjCache = []; + /** + * 二维码构造函数,主要用于绘制 + * @param {参数列表} opt 传递参数 + * @return {} + */ + QRCode = function (opt) { + //设置默认参数 + this.options = { + text: '', + size: 256, + correctLevel: 3, + background: '#ffffff', + foreground: '#000000', + pdground: '#000000', + image: '', + imageSize: 30, + canvasId: opt.canvasId, + context: opt.context, + usingComponents: opt.usingComponents, + showLoading: opt.showLoading, + loadingText: opt.loadingText, + }; + if (typeof opt === 'string') { // 只编码ASCII字符串 + opt = { + text: opt + }; + } + if (opt) { + for (var i in opt) { + this.options[i] = opt[i]; + } + } + //使用QRCodeAlg创建二维码结构 + var qrCodeAlg = null; + for (var i = 0, l = qrcodeAlgObjCache.length; i < l; i++) { + if (qrcodeAlgObjCache[i].text == this.options.text && qrcodeAlgObjCache[i].text.correctLevel == this.options.correctLevel) { + qrCodeAlg = qrcodeAlgObjCache[i].obj; + break; + } + } + if (i == l) { + qrCodeAlg = new QRCodeAlg(this.options.text, this.options.correctLevel); + qrcodeAlgObjCache.push({ + text: this.options.text, + correctLevel: this.options.correctLevel, + obj: qrCodeAlg + }); + } + /** + * 计算矩阵点的前景色 + * @param {Obj} config + * @param {Number} config.row 点x坐标 + * @param {Number} config.col 点y坐标 + * @param {Number} config.count 矩阵大小 + * @param {Number} config.options 组件的options + * @return {String} + */ + let getForeGround = function (config) { + var options = config.options; + if (options.pdground && ( + (config.row > 1 && config.row < 5 && config.col > 1 && config.col < 5) || + (config.row > (config.count - 6) && config.row < (config.count - 2) && config.col > 1 && config.col < 5) || + (config.row > 1 && config.row < 5 && config.col > (config.count - 6) && config.col < (config.count - 2)) + )) { + return options.pdground; + } + return options.foreground; + } + // 创建canvas + let createCanvas = function (options) { + if (options.showLoading) { + uni.showLoading({ + title: options.loadingText, + mask: true + }); + } + var ctx = uni.createCanvasContext(options.canvasId, options.context); + var count = qrCodeAlg.getModuleCount(); + var ratioSize = options.size; + var ratioImgSize = options.imageSize; + //计算每个点的长宽 + var tileW = (ratioSize / count).toPrecision(4); + var tileH = (ratioSize / count).toPrecision(4); + //绘制 + for (var row = 0; row < count; row++) { + for (var col = 0; col < count; col++) { + var w = (Math.ceil((col + 1) * tileW) - Math.floor(col * tileW)); + var h = (Math.ceil((row + 1) * tileW) - Math.floor(row * tileW)); + var foreground = getForeGround({ + row: row, + col: col, + count: count, + options: options + }); + ctx.setFillStyle(qrCodeAlg.modules[row][col] ? foreground : options.background); + ctx.fillRect(Math.round(col * tileW), Math.round(row * tileH), w, h); + } + } + if (options.image) { + var x = Number(((ratioSize - ratioImgSize) / 2).toFixed(2)); + var y = Number(((ratioSize - ratioImgSize) / 2).toFixed(2)); + drawRoundedRect(ctx, x, y, ratioImgSize, ratioImgSize, 2, 6, true, true) + ctx.drawImage(options.image, x, y, ratioImgSize, ratioImgSize); + // 画圆角矩形 + function drawRoundedRect(ctxi, x, y, width, height, r, lineWidth, fill, stroke) { + ctxi.setLineWidth(lineWidth); + ctxi.setFillStyle(options.background); + ctxi.setStrokeStyle(options.background); + ctxi.beginPath(); // draw top and top right corner + ctxi.moveTo(x + r, y); + ctxi.arcTo(x + width, y, x + width, y + r, r); // draw right side and bottom right corner + ctxi.arcTo(x + width, y + height, x + width - r, y + height, r); // draw bottom and bottom left corner + ctxi.arcTo(x, y + height, x, y + height - r, r); // draw left and top left corner + ctxi.arcTo(x, y, x + r, y, r); + ctxi.closePath(); + if (fill) { + ctxi.fill(); + } + if (stroke) { + ctxi.stroke(); + } + } + } + setTimeout(() => { + ctx.draw(true, () => { + // 保存到临时区域 + setTimeout(() => { + uni.canvasToTempFilePath({ + width: options.width, + height: options.height, + destWidth: options.width, + destHeight: options.height, + canvasId: options.canvasId, + quality: Number(1), + success: function (res) { + if (options.cbResult) { + options.cbResult(res.tempFilePath) + } + }, + fail: function (res) { + if (options.cbResult) { + options.cbResult(res) + } + }, + complete: function () { + if (options.showLoading){ + uni.hideLoading(); + } + }, + }, options.context); + }, options.text.length + 100); + }); + }, options.usingComponents ? 0 : 150); + } + createCanvas(this.options); + // 空判定 + let empty = function (v) { + let tp = typeof v, + rt = false; + if (tp == "number" && String(v) == "") { + rt = true + } else if (tp == "undefined") { + rt = true + } else if (tp == "object") { + if (JSON.stringify(v) == "{}" || JSON.stringify(v) == "[]" || v == null) rt = true + } else if (tp == "string") { + if (v == "" || v == "undefined" || v == "null" || v == "{}" || v == "[]") rt = true + } else if (tp == "function") { + rt = false + } + return rt + } + }; + QRCode.prototype.clear = function (fn) { + var ctx = uni.createCanvasContext(this.options.canvasId, this.options.context) + ctx.clearRect(0, 0, this.options.size, this.options.size) + ctx.draw(false, () => { + if (fn) { + fn() + } + }) + }; +})() + +export default QRCode \ No newline at end of file diff --git a/components/tki-qrcode/tki-qrcode.vue b/components/tki-qrcode/tki-qrcode.vue new file mode 100644 index 0000000..115a08c --- /dev/null +++ b/components/tki-qrcode/tki-qrcode.vue @@ -0,0 +1,211 @@ + + + + diff --git a/components/trigonometry/trigonometry.vue b/components/trigonometry/trigonometry.vue new file mode 100644 index 0000000..596ee79 --- /dev/null +++ b/components/trigonometry/trigonometry.vue @@ -0,0 +1,49 @@ + + + + \ No newline at end of file diff --git a/components/uploader/uploader.vue b/components/uploader/uploader.vue new file mode 100644 index 0000000..ba6cebd --- /dev/null +++ b/components/uploader/uploader.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/components/uview-ui/LICENSE b/components/uview-ui/LICENSE new file mode 100644 index 0000000..8e39ead --- /dev/null +++ b/components/uview-ui/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 www.uviewui.com + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/components/uview-ui/README.md b/components/uview-ui/README.md new file mode 100644 index 0000000..06d5676 --- /dev/null +++ b/components/uview-ui/README.md @@ -0,0 +1,106 @@ +

+ logo +

+

uView

+

多平台快速开发的UI框架

+ + +## 说明 + +uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水 + +## 特性 + +- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序 +- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用 +- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨 +- 众多的常用页面和布局,让您专注逻辑,事半功倍 +- 详尽的文档支持,现代化的演示效果 +- 按需引入,精简打包体积 + + +## 安装 + +```bash +# npm方式安装 +npm i uview-ui +``` + +## 快速上手 + +1. `main.js`引入uView库 +```js +// main.js +import uView from 'uview-ui'; +Vue.use(uView); +``` + +2. `App.vue`引入基础样式(注意style标签需声明scss属性支持) +```css +/* App.vue */ + +``` + +3. `uni.scss`引入全局scss变量文件 +```css +/* uni.scss */ +@import "uview-ui/theme.scss"; +``` + +4. `pages.json`配置easycom规则(按需引入) + +```js +// pages.json +{ + "easycom": { + // npm安装的方式不需要前面的"@/",下载安装的方式需要"@/" + // npm安装方式 + "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" + // 下载安装方式 + // "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue" + }, + // 此为本身已有的内容 + "pages": [ + // ...... + ] +} +``` + +请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 + +## 使用方法 +配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。 + +```html + +``` + +请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容 + +## 链接 + +- [官方文档](https://uviewui.com/) +- [更新日志](https://uviewui.com/components/changelog.html) +- [升级指南](https://uviewui.com/components/changelog.html) +- [关于我们](https://uviewui.com/cooperation/about.html) + +## 预览 + +您可以通过**微信**扫码,查看最佳的演示效果。 +
+
+ + + +## 版权信息 +uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。 diff --git a/components/uview-ui/components/u-action-sheet/u-action-sheet.vue b/components/uview-ui/components/u-action-sheet/u-action-sheet.vue new file mode 100644 index 0000000..722b668 --- /dev/null +++ b/components/uview-ui/components/u-action-sheet/u-action-sheet.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/components/uview-ui/components/u-alert-tips/u-alert-tips.vue b/components/uview-ui/components/u-alert-tips/u-alert-tips.vue new file mode 100644 index 0000000..e81fc37 --- /dev/null +++ b/components/uview-ui/components/u-alert-tips/u-alert-tips.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/components/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue b/components/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue new file mode 100644 index 0000000..a48dd54 --- /dev/null +++ b/components/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue @@ -0,0 +1,290 @@ + + + + + diff --git a/components/uview-ui/components/u-avatar-cropper/weCropper.js b/components/uview-ui/components/u-avatar-cropper/weCropper.js new file mode 100644 index 0000000..df02483 --- /dev/null +++ b/components/uview-ui/components/u-avatar-cropper/weCropper.js @@ -0,0 +1,1265 @@ +/** + * we-cropper v1.3.9 + * (c) 2020 dlhandsome + * @license MIT + */ +(function(global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.WeCropper = factory()); +}(this, (function() { + 'use strict'; + + var device = void 0; + var TOUCH_STATE = ['touchstarted', 'touchmoved', 'touchended']; + + function firstLetterUpper(str) { + return str.charAt(0).toUpperCase() + str.slice(1) + } + + function setTouchState(instance) { + var arg = [], + len = arguments.length - 1; + while (len-- > 0) arg[len] = arguments[len + 1]; + + TOUCH_STATE.forEach(function(key, i) { + if (arg[i] !== undefined) { + instance[key] = arg[i]; + } + }); + } + + function validator(instance, o) { + Object.defineProperties(instance, o); + } + + function getDevice() { + if (!device) { + device = uni.getSystemInfoSync(); + } + return device + } + + var tmp = {}; + + var ref = getDevice(); + var pixelRatio = ref.pixelRatio; + + var DEFAULT = { + id: { + default: 'cropper', + get: function get() { + return tmp.id + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("id:" + value + " is invalid")); + } + tmp.id = value; + } + }, + width: { + default: 750, + get: function get() { + return tmp.width + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("width:" + value + " is invalid")); + } + tmp.width = value; + } + }, + height: { + default: 750, + get: function get() { + return tmp.height + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("height:" + value + " is invalid")); + } + tmp.height = value; + } + }, + pixelRatio: { + default: pixelRatio, + get: function get() { + return tmp.pixelRatio + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("pixelRatio:" + value + " is invalid")); + } + tmp.pixelRatio = value; + } + }, + scale: { + default: 2.5, + get: function get() { + return tmp.scale + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("scale:" + value + " is invalid")); + } + tmp.scale = value; + } + }, + zoom: { + default: 5, + get: function get() { + return tmp.zoom + }, + set: function set(value) { + if (typeof(value) !== 'number') { + console.error(("zoom:" + value + " is invalid")); + } else if (value < 0 || value > 10) { + console.error("zoom should be ranged in 0 ~ 10"); + } + tmp.zoom = value; + } + }, + src: { + default: '', + get: function get() { + return tmp.src + }, + set: function set(value) { + if (typeof(value) !== 'string') { + console.error(("src:" + value + " is invalid")); + } + tmp.src = value; + } + }, + cut: { + default: {}, + get: function get() { + return tmp.cut + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("cut:" + value + " is invalid")); + } + tmp.cut = value; + } + }, + boundStyle: { + default: {}, + get: function get() { + return tmp.boundStyle + }, + set: function set(value) { + if (typeof(value) !== 'object') { + console.error(("boundStyle:" + value + " is invalid")); + } + tmp.boundStyle = value; + } + }, + onReady: { + default: null, + get: function get() { + return tmp.ready + }, + set: function set(value) { + tmp.ready = value; + } + }, + onBeforeImageLoad: { + default: null, + get: function get() { + return tmp.beforeImageLoad + }, + set: function set(value) { + tmp.beforeImageLoad = value; + } + }, + onImageLoad: { + default: null, + get: function get() { + return tmp.imageLoad + }, + set: function set(value) { + tmp.imageLoad = value; + } + }, + onBeforeDraw: { + default: null, + get: function get() { + return tmp.beforeDraw + }, + set: function set(value) { + tmp.beforeDraw = value; + } + } + }; + + var ref$1 = getDevice(); + var windowWidth = ref$1.windowWidth; + + function prepare() { + var self = this; + + // v1.4.0 版本中将不再自动绑定we-cropper实例 + self.attachPage = function() { + var pages = getCurrentPages(); + // 获取到当前page上下文 + var pageContext = pages[pages.length - 1]; + // 把this依附在Page上下文的wecropper属性上,便于在page钩子函数中访问 + Object.defineProperty(pageContext, 'wecropper', { + get: function get() { + console.warn( + 'Instance will not be automatically bound to the page after v1.4.0\n\n' + + 'Please use a custom instance name instead\n\n' + + 'Example: \n' + + 'this.mycropper = new WeCropper(options)\n\n' + + '// ...\n' + + 'this.mycropper.getCropperImage()' + ); + return self + }, + configurable: true + }); + }; + + self.createCtx = function() { + var id = self.id; + var targetId = self.targetId; + + if (id) { + self.ctx = self.ctx || uni.createCanvasContext(id); + self.targetCtx = self.targetCtx || uni.createCanvasContext(targetId); + } else { + console.error("constructor: create canvas context failed, 'id' must be valuable"); + } + }; + + self.deviceRadio = windowWidth / 750; + } + + var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== + 'undefined' ? self : {}; + + + + + + function createCommonjsModule(fn, module) { + return module = { + exports: {} + }, fn(module, module.exports), module.exports; + } + + var tools = createCommonjsModule(function(module, exports) { + /** + * String type check + */ + exports.isStr = function(v) { + return typeof v === 'string'; + }; + /** + * Number type check + */ + exports.isNum = function(v) { + return typeof v === 'number'; + }; + /** + * Array type check + */ + exports.isArr = Array.isArray; + /** + * undefined type check + */ + exports.isUndef = function(v) { + return v === undefined; + }; + + exports.isTrue = function(v) { + return v === true; + }; + + exports.isFalse = function(v) { + return v === false; + }; + /** + * Function type check + */ + exports.isFunc = function(v) { + return typeof v === 'function'; + }; + /** + * Quick object check - this is primarily used to tell + * Objects from primitive values when we know the value + * is a JSON-compliant type. + */ + exports.isObj = exports.isObject = function(obj) { + return obj !== null && typeof obj === 'object' + }; + + /** + * Strict object type check. Only returns true + * for plain JavaScript objects. + */ + var _toString = Object.prototype.toString; + exports.isPlainObject = function(obj) { + return _toString.call(obj) === '[object Object]' + }; + + /** + * Check whether the object has the property. + */ + var hasOwnProperty = Object.prototype.hasOwnProperty; + exports.hasOwn = function(obj, key) { + return hasOwnProperty.call(obj, key) + }; + + /** + * Perform no operation. + * Stubbing args to make Flow happy without leaving useless transpiled code + * with ...rest (https://flow.org/blog/2017/05/07/Strict-Function-Call-Arity/) + */ + exports.noop = function(a, b, c) {}; + + /** + * Check if val is a valid array index. + */ + exports.isValidArrayIndex = function(val) { + var n = parseFloat(String(val)); + return n >= 0 && Math.floor(n) === n && isFinite(val) + }; + }); + + var tools_7 = tools.isFunc; + var tools_10 = tools.isPlainObject; + + var EVENT_TYPE = ['ready', 'beforeImageLoad', 'beforeDraw', 'imageLoad']; + + function observer() { + var self = this; + + self.on = function(event, fn) { + if (EVENT_TYPE.indexOf(event) > -1) { + if (tools_7(fn)) { + event === 'ready' ? + fn(self) : + self[("on" + (firstLetterUpper(event)))] = fn; + } + } else { + console.error(("event: " + event + " is invalid")); + } + return self + }; + } + + function wxPromise(fn) { + return function(obj) { + var args = [], + len = arguments.length - 1; + while (len-- > 0) args[len] = arguments[len + 1]; + + if (obj === void 0) obj = {}; + return new Promise(function(resolve, reject) { + obj.success = function(res) { + resolve(res); + }; + obj.fail = function(err) { + reject(err); + }; + fn.apply(void 0, [obj].concat(args)); + }) + } + } + + function draw(ctx, reserve) { + if (reserve === void 0) reserve = false; + + return new Promise(function(resolve) { + ctx.draw(reserve, resolve); + }) + } + + var getImageInfo = wxPromise(uni.getImageInfo); + + var canvasToTempFilePath = wxPromise(uni.canvasToTempFilePath); + + var base64 = createCommonjsModule(function(module, exports) { + /*! http://mths.be/base64 v0.1.0 by @mathias | MIT license */ + (function(root) { + + // Detect free variables `exports`. + var freeExports = 'object' == 'object' && exports; + + // Detect free variable `module`. + var freeModule = 'object' == 'object' && module && + module.exports == freeExports && module; + + // Detect free variable `global`, from Node.js or Browserified code, and use + // it as `root`. + var freeGlobal = typeof commonjsGlobal == 'object' && commonjsGlobal; + if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + var InvalidCharacterError = function(message) { + this.message = message; + }; + InvalidCharacterError.prototype = new Error; + InvalidCharacterError.prototype.name = 'InvalidCharacterError'; + + var error = function(message) { + // Note: the error messages used throughout this file match those used by + // the native `atob`/`btoa` implementation in Chromium. + throw new InvalidCharacterError(message); + }; + + var TABLE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + // http://whatwg.org/html/common-microsyntaxes.html#space-character + var REGEX_SPACE_CHARACTERS = /[\t\n\f\r ]/g; + + // `decode` is designed to be fully compatible with `atob` as described in the + // HTML Standard. http://whatwg.org/html/webappapis.html#dom-windowbase64-atob + // The optimized base64-decoding algorithm used is based on @atk’s excellent + // implementation. https://gist.github.com/atk/1020396 + var decode = function(input) { + input = String(input) + .replace(REGEX_SPACE_CHARACTERS, ''); + var length = input.length; + if (length % 4 == 0) { + input = input.replace(/==?$/, ''); + length = input.length; + } + if ( + length % 4 == 1 || + // http://whatwg.org/C#alphanumeric-ascii-characters + /[^+a-zA-Z0-9/]/.test(input) + ) { + error( + 'Invalid character: the string to be decoded is not correctly encoded.' + ); + } + var bitCounter = 0; + var bitStorage; + var buffer; + var output = ''; + var position = -1; + while (++position < length) { + buffer = TABLE.indexOf(input.charAt(position)); + bitStorage = bitCounter % 4 ? bitStorage * 64 + buffer : buffer; + // Unless this is the first of a group of 4 characters… + if (bitCounter++ % 4) { + // …convert the first 8 bits to a single ASCII character. + output += String.fromCharCode( + 0xFF & bitStorage >> (-2 * bitCounter & 6) + ); + } + } + return output; + }; + + // `encode` is designed to be fully compatible with `btoa` as described in the + // HTML Standard: http://whatwg.org/html/webappapis.html#dom-windowbase64-btoa + var encode = function(input) { + input = String(input); + if (/[^\0-\xFF]/.test(input)) { + // Note: no need to special-case astral symbols here, as surrogates are + // matched, and the input is supposed to only contain ASCII anyway. + error( + 'The string to be encoded contains characters outside of the ' + + 'Latin1 range.' + ); + } + var padding = input.length % 3; + var output = ''; + var position = -1; + var a; + var b; + var c; + var buffer; + // Make sure any padding is handled outside of the loop. + var length = input.length - padding; + + while (++position < length) { + // Read three bytes, i.e. 24 bits. + a = input.charCodeAt(position) << 16; + b = input.charCodeAt(++position) << 8; + c = input.charCodeAt(++position); + buffer = a + b + c; + // Turn the 24 bits into four chunks of 6 bits each, and append the + // matching character for each of them to the output. + output += ( + TABLE.charAt(buffer >> 18 & 0x3F) + + TABLE.charAt(buffer >> 12 & 0x3F) + + TABLE.charAt(buffer >> 6 & 0x3F) + + TABLE.charAt(buffer & 0x3F) + ); + } + + if (padding == 2) { + a = input.charCodeAt(position) << 8; + b = input.charCodeAt(++position); + buffer = a + b; + output += ( + TABLE.charAt(buffer >> 10) + + TABLE.charAt((buffer >> 4) & 0x3F) + + TABLE.charAt((buffer << 2) & 0x3F) + + '=' + ); + } else if (padding == 1) { + buffer = input.charCodeAt(position); + output += ( + TABLE.charAt(buffer >> 2) + + TABLE.charAt((buffer << 4) & 0x3F) + + '==' + ); + } + + return output; + }; + + var base64 = { + 'encode': encode, + 'decode': decode, + 'version': '0.1.0' + }; + + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + typeof undefined == 'function' && + typeof undefined.amd == 'object' && + undefined.amd + ) { + undefined(function() { + return base64; + }); + } else if (freeExports && !freeExports.nodeType) { + if (freeModule) { // in Node.js or RingoJS v0.8.0+ + freeModule.exports = base64; + } else { // in Narwhal or RingoJS v0.7.0- + for (var key in base64) { + base64.hasOwnProperty(key) && (freeExports[key] = base64[key]); + } + } + } else { // in Rhino or a web browser + root.base64 = base64; + } + + }(commonjsGlobal)); + }); + + function makeURI(strData, type) { + return 'data:' + type + ';base64,' + strData + } + + function fixType(type) { + type = type.toLowerCase().replace(/jpg/i, 'jpeg'); + var r = type.match(/png|jpeg|bmp|gif/)[0]; + return 'image/' + r + } + + function encodeData(data) { + var str = ''; + if (typeof data === 'string') { + str = data; + } else { + for (var i = 0; i < data.length; i++) { + str += String.fromCharCode(data[i]); + } + } + return base64.encode(str) + } + + /** + * 获取图像区域隐含的像素数据 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param done 完成回调 + */ + function getImageData(canvasId, x, y, width, height, done) { + uni.canvasGetImageData({ + canvasId: canvasId, + x: x, + y: y, + width: width, + height: height, + success: function success(res) { + done(res, null); + }, + fail: function fail(res) { + done(null, res); + } + }); + } + + /** + * 生成bmp格式图片 + * 按照规则生成图片响应头和响应体 + * @param oData 用来描述 canvas 区域隐含的像素数据 { data, width, height } = oData + * @returns {*} base64字符串 + */ + function genBitmapImage(oData) { + // + // BITMAPFILEHEADER: http://msdn.microsoft.com/en-us/library/windows/desktop/dd183374(v=vs.85).aspx + // BITMAPINFOHEADER: http://msdn.microsoft.com/en-us/library/dd183376.aspx + // + var biWidth = oData.width; + var biHeight = oData.height; + var biSizeImage = biWidth * biHeight * 3; + var bfSize = biSizeImage + 54; // total header size = 54 bytes + + // + // typedef struct tagBITMAPFILEHEADER { + // WORD bfType; + // DWORD bfSize; + // WORD bfReserved1; + // WORD bfReserved2; + // DWORD bfOffBits; + // } BITMAPFILEHEADER; + // + var BITMAPFILEHEADER = [ + // WORD bfType -- The file type signature; must be "BM" + 0x42, 0x4D, + // DWORD bfSize -- The size, in bytes, of the bitmap file + bfSize & 0xff, bfSize >> 8 & 0xff, bfSize >> 16 & 0xff, bfSize >> 24 & 0xff, + // WORD bfReserved1 -- Reserved; must be zero + 0, 0, + // WORD bfReserved2 -- Reserved; must be zero + 0, 0, + // DWORD bfOffBits -- The offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits. + 54, 0, 0, 0 + ]; + + // + // typedef struct tagBITMAPINFOHEADER { + // DWORD biSize; + // LONG biWidth; + // LONG biHeight; + // WORD biPlanes; + // WORD biBitCount; + // DWORD biCompression; + // DWORD biSizeImage; + // LONG biXPelsPerMeter; + // LONG biYPelsPerMeter; + // DWORD biClrUsed; + // DWORD biClrImportant; + // } BITMAPINFOHEADER, *PBITMAPINFOHEADER; + // + var BITMAPINFOHEADER = [ + // DWORD biSize -- The number of bytes required by the structure + 40, 0, 0, 0, + // LONG biWidth -- The width of the bitmap, in pixels + biWidth & 0xff, biWidth >> 8 & 0xff, biWidth >> 16 & 0xff, biWidth >> 24 & 0xff, + // LONG biHeight -- The height of the bitmap, in pixels + biHeight & 0xff, biHeight >> 8 & 0xff, biHeight >> 16 & 0xff, biHeight >> 24 & 0xff, + // WORD biPlanes -- The number of planes for the target device. This value must be set to 1 + 1, 0, + // WORD biBitCount -- The number of bits-per-pixel, 24 bits-per-pixel -- the bitmap + // has a maximum of 2^24 colors (16777216, Truecolor) + 24, 0, + // DWORD biCompression -- The type of compression, BI_RGB (code 0) -- uncompressed + 0, 0, 0, 0, + // DWORD biSizeImage -- The size, in bytes, of the image. This may be set to zero for BI_RGB bitmaps + biSizeImage & 0xff, biSizeImage >> 8 & 0xff, biSizeImage >> 16 & 0xff, biSizeImage >> 24 & 0xff, + // LONG biXPelsPerMeter, unused + 0, 0, 0, 0, + // LONG biYPelsPerMeter, unused + 0, 0, 0, 0, + // DWORD biClrUsed, the number of color indexes of palette, unused + 0, 0, 0, 0, + // DWORD biClrImportant, unused + 0, 0, 0, 0 + ]; + + var iPadding = (4 - ((biWidth * 3) % 4)) % 4; + + var aImgData = oData.data; + + var strPixelData = ''; + var biWidth4 = biWidth << 2; + var y = biHeight; + var fromCharCode = String.fromCharCode; + + do { + var iOffsetY = biWidth4 * (y - 1); + var strPixelRow = ''; + for (var x = 0; x < biWidth; x++) { + var iOffsetX = x << 2; + strPixelRow += fromCharCode(aImgData[iOffsetY + iOffsetX + 2]) + + fromCharCode(aImgData[iOffsetY + iOffsetX + 1]) + + fromCharCode(aImgData[iOffsetY + iOffsetX]); + } + + for (var c = 0; c < iPadding; c++) { + strPixelRow += String.fromCharCode(0); + } + + strPixelData += strPixelRow; + } while (--y) + + var strEncoded = encodeData(BITMAPFILEHEADER.concat(BITMAPINFOHEADER)) + encodeData(strPixelData); + + return strEncoded + } + + /** + * 转换为图片base64 + * @param canvasId canvas标识 + * @param x 将要被提取的图像数据矩形区域的左上角 x 坐标 + * @param y 将要被提取的图像数据矩形区域的左上角 y 坐标 + * @param width 将要被提取的图像数据矩形区域的宽度 + * @param height 将要被提取的图像数据矩形区域的高度 + * @param type 转换图片类型 + * @param done 完成回调 + */ + function convertToImage(canvasId, x, y, width, height, type, done) { + if (done === void 0) done = function() {}; + + if (type === undefined) { + type = 'png'; + } + type = fixType(type); + if (/bmp/.test(type)) { + getImageData(canvasId, x, y, width, height, function(data, err) { + var strData = genBitmapImage(data); + tools_7(done) && done(makeURI(strData, 'image/' + type), err); + }); + } else { + console.error('暂不支持生成\'' + type + '\'类型的base64图片'); + } + } + + var CanvasToBase64 = { + convertToImage: convertToImage, + // convertToPNG: function (width, height, done) { + // return convertToImage(width, height, 'png', done) + // }, + // convertToJPEG: function (width, height, done) { + // return convertToImage(width, height, 'jpeg', done) + // }, + // convertToGIF: function (width, height, done) { + // return convertToImage(width, height, 'gif', done) + // }, + convertToBMP: function(ref, done) { + if (ref === void 0) ref = {}; + var canvasId = ref.canvasId; + var x = ref.x; + var y = ref.y; + var width = ref.width; + var height = ref.height; + if (done === void 0) done = function() {}; + + return convertToImage(canvasId, x, y, width, height, 'bmp', done) + } + }; + + function methods() { + var self = this; + + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; // 裁剪框默认高度,即整个画布高度 + + var id = self.id; + var targetId = self.targetId; + var pixelRatio = self.pixelRatio; + + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + self.updateCanvas = function(done) { + if (self.croperTarget) { + // 画布绘制图片 + self.ctx.drawImage( + self.croperTarget, + self.imgLeft, + self.imgTop, + self.scaleWidth, + self.scaleHeight + ); + } + tools_7(self.onBeforeDraw) && self.onBeforeDraw(self.ctx, self); + + self.setBoundStyle(self.boundStyle); // 设置边界样式 + + self.ctx.draw(false, done); + return self + }; + + self.pushOrigin = self.pushOrign = function(src) { + self.src = src; + + tools_7(self.onBeforeImageLoad) && self.onBeforeImageLoad(self.ctx, self); + + return getImageInfo({ + src: src + }) + .then(function(res) { + var innerAspectRadio = res.width / res.height; + var customAspectRadio = width / height; + + self.croperTarget = res.path; + + if (innerAspectRadio < customAspectRadio) { + self.rectX = x; + self.baseWidth = width; + self.baseHeight = width / innerAspectRadio; + self.rectY = y - Math.abs((height - self.baseHeight) / 2); + } else { + self.rectY = y; + self.baseWidth = height * innerAspectRadio; + self.baseHeight = height; + self.rectX = x - Math.abs((width - self.baseWidth) / 2); + } + + self.imgLeft = self.rectX; + self.imgTop = self.rectY; + self.scaleWidth = self.baseWidth; + self.scaleHeight = self.baseHeight; + + self.update(); + + return new Promise(function(resolve) { + self.updateCanvas(resolve); + }) + }) + .then(function() { + tools_7(self.onImageLoad) && self.onImageLoad(self.ctx, self); + }) + }; + + self.removeImage = function() { + self.src = ''; + self.croperTarget = ''; + return draw(self.ctx) + }; + + self.getCropperBase64 = function(done) { + if (done === void 0) done = function() {}; + + CanvasToBase64.convertToBMP({ + canvasId: id, + x: x, + y: y, + width: width, + height: height + }, done); + }; + + self.getCropperImage = function(opt, fn) { + var customOptions = opt; + + var canvasOptions = { + canvasId: id, + x: x, + y: y, + width: width, + height: height + }; + + var task = function() { + return Promise.resolve(); + }; + + if ( + tools_10(customOptions) && + customOptions.original + ) { + // original mode + task = function() { + self.targetCtx.drawImage( + self.croperTarget, + self.imgLeft * pixelRatio, + self.imgTop * pixelRatio, + self.scaleWidth * pixelRatio, + self.scaleHeight * pixelRatio + ); + + canvasOptions = { + canvasId: targetId, + x: x * pixelRatio, + y: y * pixelRatio, + width: width * pixelRatio, + height: height * pixelRatio + }; + + return draw(self.targetCtx) + }; + } + + return task() + .then(function() { + if (tools_10(customOptions)) { + canvasOptions = Object.assign({}, canvasOptions, customOptions); + } + + if (tools_7(customOptions)) { + fn = customOptions; + } + + var arg = canvasOptions.componentContext ? + [canvasOptions, canvasOptions.componentContext] : + [canvasOptions]; + + return canvasToTempFilePath.apply(null, arg) + }) + .then(function(res) { + var tempFilePath = res.tempFilePath; + + return tools_7(fn) ? + fn.call(self, tempFilePath, null) : + tempFilePath + }) + .catch(function(err) { + if (tools_7(fn)) { + fn.call(self, null, err); + } else { + throw err + } + }) + }; + } + + /** + * 获取最新缩放值 + * @param oldScale 上一次触摸结束后的缩放值 + * @param oldDistance 上一次触摸结束后的双指距离 + * @param zoom 缩放系数 + * @param touch0 第一指touch对象 + * @param touch1 第二指touch对象 + * @returns {*} + */ + var getNewScale = function(oldScale, oldDistance, zoom, touch0, touch1) { + var xMove, yMove, newDistance; + // 计算二指最新距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + newDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + return oldScale + 0.001 * zoom * (newDistance - oldDistance) + }; + + function update() { + var self = this; + + if (!self.src) { + return + } + + self.__oneTouchStart = function(touch) { + self.touchX0 = Math.round(touch.x); + self.touchY0 = Math.round(touch.y); + }; + + self.__oneTouchMove = function(touch) { + var xMove, yMove; + // 计算单指移动的距离 + if (self.touchended) { + return self.updateCanvas() + } + xMove = Math.round(touch.x - self.touchX0); + yMove = Math.round(touch.y - self.touchY0); + + var imgLeft = Math.round(self.rectX + xMove); + var imgTop = Math.round(self.rectY + yMove); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__twoTouchStart = function(touch0, touch1) { + var xMove, yMove, oldDistance; + + self.touchX1 = Math.round(self.rectX + self.scaleWidth / 2); + self.touchY1 = Math.round(self.rectY + self.scaleHeight / 2); + + // 计算两指距离 + xMove = Math.round(touch1.x - touch0.x); + yMove = Math.round(touch1.y - touch0.y); + oldDistance = Math.round(Math.sqrt(xMove * xMove + yMove * yMove)); + + self.oldDistance = oldDistance; + }; + + self.__twoTouchMove = function(touch0, touch1) { + var oldScale = self.oldScale; + var oldDistance = self.oldDistance; + var scale = self.scale; + var zoom = self.zoom; + + self.newScale = getNewScale(oldScale, oldDistance, zoom, touch0, touch1); + + // 设定缩放范围 + self.newScale <= 1 && (self.newScale = 1); + self.newScale >= scale && (self.newScale = scale); + + self.scaleWidth = Math.round(self.newScale * self.baseWidth); + self.scaleHeight = Math.round(self.newScale * self.baseHeight); + var imgLeft = Math.round(self.touchX1 - self.scaleWidth / 2); + var imgTop = Math.round(self.touchY1 - self.scaleHeight / 2); + + self.outsideBound(imgLeft, imgTop); + + self.updateCanvas(); + }; + + self.__xtouchEnd = function() { + self.oldScale = self.newScale; + self.rectX = self.imgLeft; + self.rectY = self.imgTop; + }; + } + + var handle = { + // 图片手势初始监测 + touchStart: function touchStart(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, true, null, null); + + // 计算第一个触摸点的位置,并参照改点进行缩放 + self.__oneTouchStart(touch0); + + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchStart(touch0, touch1); + } + }, + + // 图片手势动态缩放 + touchMove: function touchMove(e) { + var self = this; + var ref = e.touches; + var touch0 = ref[0]; + var touch1 = ref[1]; + + if (!self.src) { + return + } + + setTouchState(self, null, true); + + // 单指手势时触发 + if (e.touches.length === 1) { + self.__oneTouchMove(touch0); + } + // 两指手势触发 + if (e.touches.length >= 2) { + self.__twoTouchMove(touch0, touch1); + } + }, + + touchEnd: function touchEnd(e) { + var self = this; + + if (!self.src) { + return + } + + setTouchState(self, false, false, true); + self.__xtouchEnd(); + } + }; + + function cut() { + var self = this; + var boundWidth = self.width; // 裁剪框默认宽度,即整个画布宽度 + var boundHeight = self.height; + // 裁剪框默认高度,即整个画布高度 + var ref = self.cut; + var x = ref.x; + if (x === void 0) x = 0; + var y = ref.y; + if (y === void 0) y = 0; + var width = ref.width; + if (width === void 0) width = boundWidth; + var height = ref.height; + if (height === void 0) height = boundHeight; + + /** + * 设置边界 + * @param imgLeft 图片左上角横坐标值 + * @param imgTop 图片左上角纵坐标值 + */ + self.outsideBound = function(imgLeft, imgTop) { + self.imgLeft = imgLeft >= x ? + x : + self.scaleWidth + imgLeft - x <= width ? + x + width - self.scaleWidth : + imgLeft; + + self.imgTop = imgTop >= y ? + y : + self.scaleHeight + imgTop - y <= height ? + y + height - self.scaleHeight : + imgTop; + }; + + /** + * 设置边界样式 + * @param color 边界颜色 + */ + self.setBoundStyle = function(ref) { + if (ref === void 0) ref = {}; + var color = ref.color; + if (color === void 0) color = '#04b00f'; + var mask = ref.mask; + if (mask === void 0) mask = 'rgba(0, 0, 0, 0.3)'; + var lineWidth = ref.lineWidth; + if (lineWidth === void 0) lineWidth = 1; + + var half = lineWidth / 2; + var boundOption = [{ + start: { + x: x - half, + y: y + 10 - half + }, + step1: { + x: x - half, + y: y - half + }, + step2: { + x: x + 10 - half, + y: y - half + } + }, + { + start: { + x: x - half, + y: y + height - 10 + half + }, + step1: { + x: x - half, + y: y + height + half + }, + step2: { + x: x + 10 - half, + y: y + height + half + } + }, + { + start: { + x: x + width - 10 + half, + y: y - half + }, + step1: { + x: x + width + half, + y: y - half + }, + step2: { + x: x + width + half, + y: y + 10 - half + } + }, + { + start: { + x: x + width + half, + y: y + height - 10 + half + }, + step1: { + x: x + width + half, + y: y + height + half + }, + step2: { + x: x + width - 10 + half, + y: y + height + half + } + } + ]; + + // 绘制半透明层 + self.ctx.beginPath(); + self.ctx.setFillStyle(mask); + self.ctx.fillRect(0, 0, x, boundHeight); + self.ctx.fillRect(x, 0, width, y); + self.ctx.fillRect(x, y + height, width, boundHeight - y - height); + self.ctx.fillRect(x + width, 0, boundWidth - x - width, boundHeight); + self.ctx.fill(); + + boundOption.forEach(function(op) { + self.ctx.beginPath(); + self.ctx.setStrokeStyle(color); + self.ctx.setLineWidth(lineWidth); + self.ctx.moveTo(op.start.x, op.start.y); + self.ctx.lineTo(op.step1.x, op.step1.y); + self.ctx.lineTo(op.step2.x, op.step2.y); + self.ctx.stroke(); + }); + }; + } + + var version = "1.3.9"; + + var WeCropper = function WeCropper(params) { + var self = this; + var _default = {}; + + validator(self, DEFAULT); + + Object.keys(DEFAULT).forEach(function(key) { + _default[key] = DEFAULT[key].default; + }); + Object.assign(self, _default, params); + + self.prepare(); + self.attachPage(); + self.createCtx(); + self.observer(); + self.cutt(); + self.methods(); + self.init(); + self.update(); + + return self + }; + + WeCropper.prototype.init = function init() { + var self = this; + var src = self.src; + + self.version = version; + + typeof self.onReady === 'function' && self.onReady(self.ctx, self); + + if (src) { + self.pushOrign(src); + } else { + self.updateCanvas(); + } + setTouchState(self, false, false, false); + + self.oldScale = 1; + self.newScale = 1; + + return self + }; + + Object.assign(WeCropper.prototype, handle); + + WeCropper.prototype.prepare = prepare; + WeCropper.prototype.observer = observer; + WeCropper.prototype.methods = methods; + WeCropper.prototype.cutt = cut; + WeCropper.prototype.update = update; + + return WeCropper; + +}))); diff --git a/components/uview-ui/components/u-avatar/u-avatar.vue b/components/uview-ui/components/u-avatar/u-avatar.vue new file mode 100644 index 0000000..289b9b0 --- /dev/null +++ b/components/uview-ui/components/u-avatar/u-avatar.vue @@ -0,0 +1,244 @@ + + + + + diff --git a/components/uview-ui/components/u-back-top/u-back-top.vue b/components/uview-ui/components/u-back-top/u-back-top.vue new file mode 100644 index 0000000..7970fc7 --- /dev/null +++ b/components/uview-ui/components/u-back-top/u-back-top.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/components/uview-ui/components/u-badge/u-badge.vue b/components/uview-ui/components/u-badge/u-badge.vue new file mode 100644 index 0000000..e85b133 --- /dev/null +++ b/components/uview-ui/components/u-badge/u-badge.vue @@ -0,0 +1,216 @@ + + + + + \ No newline at end of file diff --git a/components/uview-ui/components/u-button/u-button.vue b/components/uview-ui/components/u-button/u-button.vue new file mode 100644 index 0000000..82c3a6f --- /dev/null +++ b/components/uview-ui/components/u-button/u-button.vue @@ -0,0 +1,596 @@ + + + + + diff --git a/components/uview-ui/components/u-calendar/u-calendar.vue b/components/uview-ui/components/u-calendar/u-calendar.vue new file mode 100644 index 0000000..6602bd0 --- /dev/null +++ b/components/uview-ui/components/u-calendar/u-calendar.vue @@ -0,0 +1,639 @@ + + + + \ No newline at end of file diff --git a/components/uview-ui/components/u-car-keyboard/u-car-keyboard.vue b/components/uview-ui/components/u-car-keyboard/u-car-keyboard.vue new file mode 100644 index 0000000..84b1467 --- /dev/null +++ b/components/uview-ui/components/u-car-keyboard/u-car-keyboard.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/components/uview-ui/components/u-card/u-card.vue b/components/uview-ui/components/u-card/u-card.vue new file mode 100644 index 0000000..a3cb2aa --- /dev/null +++ b/components/uview-ui/components/u-card/u-card.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/components/uview-ui/components/u-cell-group/u-cell-group.vue b/components/uview-ui/components/u-cell-group/u-cell-group.vue new file mode 100644 index 0000000..3fbca72 --- /dev/null +++ b/components/uview-ui/components/u-cell-group/u-cell-group.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/components/uview-ui/components/u-cell-item/u-cell-item.vue b/components/uview-ui/components/u-cell-item/u-cell-item.vue new file mode 100644 index 0000000..055af3a --- /dev/null +++ b/components/uview-ui/components/u-cell-item/u-cell-item.vue @@ -0,0 +1,316 @@ + + + + + diff --git a/components/uview-ui/components/u-checkbox-group/u-checkbox-group.vue b/components/uview-ui/components/u-checkbox-group/u-checkbox-group.vue new file mode 100644 index 0000000..6a149b3 --- /dev/null +++ b/components/uview-ui/components/u-checkbox-group/u-checkbox-group.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/components/uview-ui/components/u-checkbox/u-checkbox.vue b/components/uview-ui/components/u-checkbox/u-checkbox.vue new file mode 100644 index 0000000..9414461 --- /dev/null +++ b/components/uview-ui/components/u-checkbox/u-checkbox.vue @@ -0,0 +1,284 @@ + + + + + diff --git a/components/uview-ui/components/u-circle-progress/u-circle-progress.vue b/components/uview-ui/components/u-circle-progress/u-circle-progress.vue new file mode 100644 index 0000000..46e7c18 --- /dev/null +++ b/components/uview-ui/components/u-circle-progress/u-circle-progress.vue @@ -0,0 +1,220 @@ + + + + + diff --git a/components/uview-ui/components/u-col/u-col.vue b/components/uview-ui/components/u-col/u-col.vue new file mode 100644 index 0000000..3b6cc64 --- /dev/null +++ b/components/uview-ui/components/u-col/u-col.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/components/uview-ui/components/u-collapse-item/u-collapse-item.vue b/components/uview-ui/components/u-collapse-item/u-collapse-item.vue new file mode 100644 index 0000000..3b66bfa --- /dev/null +++ b/components/uview-ui/components/u-collapse-item/u-collapse-item.vue @@ -0,0 +1,204 @@ + + + + + diff --git a/components/uview-ui/components/u-collapse/u-collapse.vue b/components/uview-ui/components/u-collapse/u-collapse.vue new file mode 100644 index 0000000..8572957 --- /dev/null +++ b/components/uview-ui/components/u-collapse/u-collapse.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/components/uview-ui/components/u-column-notice/u-column-notice.vue b/components/uview-ui/components/u-column-notice/u-column-notice.vue new file mode 100644 index 0000000..dd8bd31 --- /dev/null +++ b/components/uview-ui/components/u-column-notice/u-column-notice.vue @@ -0,0 +1,237 @@ + + + + + diff --git a/components/uview-ui/components/u-count-down/u-count-down.vue b/components/uview-ui/components/u-count-down/u-count-down.vue new file mode 100644 index 0000000..e6c8ee9 --- /dev/null +++ b/components/uview-ui/components/u-count-down/u-count-down.vue @@ -0,0 +1,320 @@ + + + + + diff --git a/components/uview-ui/components/u-count-to/u-count-to.vue b/components/uview-ui/components/u-count-to/u-count-to.vue new file mode 100644 index 0000000..053dc5f --- /dev/null +++ b/components/uview-ui/components/u-count-to/u-count-to.vue @@ -0,0 +1,241 @@ + + + + + diff --git a/components/uview-ui/components/u-divider/u-divider.vue b/components/uview-ui/components/u-divider/u-divider.vue new file mode 100644 index 0000000..6f8d7e6 --- /dev/null +++ b/components/uview-ui/components/u-divider/u-divider.vue @@ -0,0 +1,153 @@ + + + + + diff --git a/components/uview-ui/components/u-dropdown-item/u-dropdown-item.vue b/components/uview-ui/components/u-dropdown-item/u-dropdown-item.vue new file mode 100644 index 0000000..ba60d8f --- /dev/null +++ b/components/uview-ui/components/u-dropdown-item/u-dropdown-item.vue @@ -0,0 +1,132 @@ + + + + + diff --git a/components/uview-ui/components/u-dropdown/u-dropdown.vue b/components/uview-ui/components/u-dropdown/u-dropdown.vue new file mode 100644 index 0000000..a62e469 --- /dev/null +++ b/components/uview-ui/components/u-dropdown/u-dropdown.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/components/uview-ui/components/u-empty/u-empty.vue b/components/uview-ui/components/u-empty/u-empty.vue new file mode 100644 index 0000000..2c77b24 --- /dev/null +++ b/components/uview-ui/components/u-empty/u-empty.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/components/uview-ui/components/u-field/u-field.vue b/components/uview-ui/components/u-field/u-field.vue new file mode 100644 index 0000000..b79accc --- /dev/null +++ b/components/uview-ui/components/u-field/u-field.vue @@ -0,0 +1,390 @@ +