This commit is contained in:
唐明明
2021-09-24 16:46:02 +08:00
53 changed files with 4990 additions and 4338 deletions

View File

@@ -14,6 +14,10 @@
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]

View File

@@ -1,33 +1,33 @@
/**
* Web-zdx
* moduleName:核销相关操作
*/
import {
request
} from '../index'
// 扫码前置条件 get 核销前置 post 表示核销
const scanInfo = (apiUrl, data, method) => {
return request({
url: apiUrl,
method: method,
data: data
})
}
// 核销记录
const scanList = (apiUrl, data) => {
return request({
url: apiUrl,
method: 'GET',
data: data
})
}
export {
scanInfo,
scanList
/**
* Web-zdx
* moduleName:核销相关操作
*/
import {
request
} from '../index'
// 扫码前置条件 get 核销前置 post 表示核销
const scanInfo = (apiUrl, data, method) => {
return request({
url: apiUrl,
method: method,
data: data
})
}
// 核销记录
const scanList = (apiUrl, data) => {
return request({
url: apiUrl,
method: 'GET',
data: data
})
}
export {
scanInfo,
scanList
}

View File

@@ -0,0 +1,84 @@
/**
* Web-zdx
* moduleName: 登录(手机号)
*/
import { request } from '../index'
// 手机号登陆接口
const login = (data) => {
return request({
url: 'user/socialite/login/wechat/mini',
method: 'POST',
data: data
})
}
// 修改用户信息
const wechatbind = (data) => {
return request({
url: 'user/socialite/wechatbind',
method: 'PUT',
data: data
})
}
// 修改用户头像或昵称
const resetUserInfo = (data) => {
return request({
url: 'user/' + data.key,
method: 'PUT',
data: {
value: data.value
}
})
}
// 获取用户的Openid
const getOpenid = (code) => {
return request({
url: 'user/socialite/login/wechat/openid',
method: 'GET',
data: {
code: code
}
})
}
// 隐私条款
const agreementSecret = (data) => {
return request({
url: 'articles/agreement/secret'
})
}
// 注册协议
const agreementLogin = (data) => {
return request({
url: 'articles/agreement/login'
})
}
// 获取用户设置中心的信息
const getUserSettingInfo = () => {
return request({
url: 'user/setting'
})
}
// 关于我们
const aboutUs = () => {
return request({
url: 'articles/about'
})
}
export {
login,
wechatbind,
getOpenid,
agreementSecret,
agreementLogin,
resetUserInfo,
getUserSettingInfo,
aboutUs
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,118 +1,132 @@
{
"pages": [{
"path": "pages/index/index",
"name": "Index",
"aliasPath": "/",
"style": {
"navigationBarTitleText":"发现能量"
"path": "pages/index/index",
"name": "Index",
"aliasPath": "/",
"style": {
"navigationBarTitleText": "发现能量"
}
}, {
"path": "pages/found/index",
"name": "Found",
"auth": true,
"style": {
"navigationBarTitleText":"发现更多"
"path": "pages/found/index",
"name": "Found",
"auth": true,
"style": {
"navigationBarTitleText": "发现更多"
}
}, {
"path": "pages/user/index",
"name": "User",
"auth": true,
"style": {
"navigationBarTitleText":"节点中心"
"path": "pages/user/index",
"name": "User",
"auth": true,
"style": {
"navigationBarTitleText": "节点中心"
}
}, {
"path": "pages/instrument/basics",
"name": "instrumentBasics",
"style": {
"navigationBarTitleText":"企业基础信息"
"path": "pages/instrument/basics",
"name": "instrumentBasics",
"style": {
"navigationBarTitleText": "企业基础信息"
}
}, {
"path": "pages/goods/management",
"name": "goodsManagement",
"style": {
"navigationBarTitleText":"商品权证管理"
"path": "pages/goods/management",
"name": "goodsManagement",
"style": {
"navigationBarTitleText": "商品权证管理"
}
}, {
"path": "pages/goods/addClassify",
"name": "goodsaddClassify",
"style": {
"navigationBarTitleText":"发布商品类目"
"path": "pages/goods/addClassify",
"name": "goodsaddClassify",
"style": {
"navigationBarTitleText": "发布商品类目"
}
}, {
"path": "pages/goods/add",
"name": "goodsAdd",
"style": {
"navigationBarTitleText":"商品权证创建"
"path": "pages/goods/add",
"name": "goodsAdd",
"style": {
"navigationBarTitleText": "商品权证创建"
}
}, {
"path": "pages/goods/goodsAuth",
"name": "goodsAddAuth",
"style": {
"navigationBarTitleText":"商品权证认证"
}
"path": "pages/goods/goodsAuth",
"name": "goodsAddAuth",
"style": {
"navigationBarTitleText": "商品权证认证"
}
}, {
"path": "pages/coupons/management",
"name": "couponsManagement",
"style": {
"navigationBarTitleText":"优惠券管理"
}
"path": "pages/coupons/management",
"name": "couponsManagement",
"style": {
"navigationBarTitleText": "创建优惠券"
}
}, {
"path": "pages/coupons/add",
"name": "couponsAdd",
"style": {
"navigationBarTitleText":"创建优惠券"
}
"path": "pages/coupons/add",
"name": "couponsAdd",
"style": {
"navigationBarTitleText": "创建优惠券"
}
}, {
"path": "pages/coupons/magDetails",
"name": "couponsDetails",
"style": {
"navigationBarTitleText":"优惠券详情"
}
"path": "pages/coupons/magDetails",
"name": "couponsDetails",
"style": {
"navigationBarTitleText": "优惠券详情"
}
}, {
"path": "pages/coupons/selectGoods",
"name": "couponsSelectGoods",
"style": {
"navigationBarTitleText":"关联产品"
}
}, {
"path": "pages/login/login",
"name": "Login",
"style": {
"navigationBarTitleText":"登录"
}
}, {
"path" : "pages/certification/personal",
"name" : "Personal",
"auth" : true,
"style": {
"navigationBarTitleText":"个人认证"
}
"path": "pages/coupons/selectGoods",
"name": "couponsSelectGoods",
"style": {
"navigationBarTitleText": "关联产品"
}
}, {
"path": "pages/login/login",
"name": "Login",
"style": {
"navigationBarTitleText": "登录"
}
}, {
"path": "pages/certification/personal",
"name": "Personal",
"auth": true,
"style": {
"navigationBarTitleText": "个人认证"
}
}, {
"path": "pages/setting/setting",
"name": "setting",
"auth": true,
"style": {
"navigationBarTitleText": "设置中心"
}
}, {
"path": "pages/setting/aboutUs",
"name": "aboutUs",
"auth": true,
"style": {
"navigationBarTitleText": "关于我们"
}
}],
"globalStyle": {
"navigationStyle": "custom",
"backgroundColor": "#F5F5F5"
},
"tabBar": {
"borderStyle": "white",
"backgroundColor": "#FFFFFF",
"selectedColor" : "#774ffd",
"iconWidth":"26px",
"spacing": "0",
"height":"60px",
"tabBar": {
"borderStyle": "white",
"backgroundColor": "#FFFFFF",
"selectedColor": "#774ffd",
"iconWidth": "26px",
"spacing": "0",
"height": "60px",
"list": [{
"text": "发现能量",
"iconPath":"static/tabBar/tabBar_icon_00.png",
"selectedIconPath":"static/tabBar/tabBar_show_00.png",
"text": "发现能量",
"iconPath": "static/tabBar/tabBar_icon_00.png",
"selectedIconPath": "static/tabBar/tabBar_show_00.png",
"pagePath": "pages/index/index"
}, {
"text": "发现更多",
"iconPath":"static/tabBar/tabBar_icon_01.png",
"selectedIconPath":"static/tabBar/tabBar_show_01.png",
"text": "发现更多",
"iconPath": "static/tabBar/tabBar_icon_01.png",
"selectedIconPath": "static/tabBar/tabBar_show_01.png",
"pagePath": "pages/found/index"
}, {
"text": "节点中心",
"iconPath":"static/tabBar/tabBar_icon_02.png",
"selectedIconPath":"static/tabBar/tabBar_show_02.png",
"text": "节点中心",
"iconPath": "static/tabBar/tabBar_icon_02.png",
"selectedIconPath": "static/tabBar/tabBar_show_02.png",
"pagePath": "pages/user/index"
}]
},

View File

@@ -73,9 +73,16 @@
front_card: this.positive.path,
back_card: this.reverse.path,
}).then(res=>{
console.log(res)
uni.showModal({
title: '提示',
content: '个人认证信息已提交,请耐心等待审核',
showCancel: false,
confirmColor: '#8b64fd',
success: modalRes => {
this.$Router.back()
}
})
}).catch(err => {
console.log(err)
uni.showToast({
icon: 'none',
title: err.message

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
<template>
<template>
<view class="content">
<!-- 商品图片 -->
<view class="form-block">
@@ -19,7 +19,7 @@
</view>
</view>
</view>
</view>
</view>
<!-- 商品基本信息 -->
<view class="form-block">
<view class="form-box inputs-flex">
@@ -51,7 +51,7 @@
</view>
</view>
</view>
</view>
</view>
<!-- 商品价格 -->
<view class="form-block">
<view class="form-box inputs-flex input-unit">
@@ -69,7 +69,7 @@
<input type="digit" v-model="skus_charge" placeholder="0.00"/>
<text class="units">{{skus_unit != '' ? '/' + skus_unit : ''}}</text>
</view>
</view>
</view>
<!-- 商品详情介绍 -->
<view class="form-block">
<view class="form-box picker-flex">
@@ -169,15 +169,15 @@
<view class="footer">
<button class="footer-btn" type="default" @click="submitAdd">{{type == 2 ? '发布': '发布并认证'}}</button>
<view class="ios-bottom"></view>
</view>
</view>
</template>
<script>
import { managesGoodsCreate, managesCreate, managesGoodsEdit, managesGoodsPut } from '@/apis/interfaces/goods'
import { uploads } from '@/apis/interfaces/uploading'
export default {
data() {
</view>
</view>
</template>
<script>
import { managesGoodsCreate, managesCreate, managesGoodsEdit, managesGoodsPut } from '@/apis/interfaces/goods'
import { uploads } from '@/apis/interfaces/uploading'
export default {
data() {
return {
categoryId : '', // 一级分类
categoryCid : '', // 二级分类
@@ -206,8 +206,8 @@
tags : [], // 可选商品标签
tagsIndex : 0, // 选择标签的下标
servicesArr : [], // 可选服务
type : 1, // 1为商品2为服务
};
type : 1, // 1为商品2为服务
};
},
created() {
// 编辑状态信息
@@ -289,7 +289,7 @@
icon : 'none'
})
})
},
},
methods: {
// 选择商品服务
opnePopup(key){
@@ -415,10 +415,10 @@
})
})
}
}
}
</script>
}
}
</script>
<style lang="scss" scoped>
.content{
padding-bottom: 150rpx;
@@ -623,5 +623,5 @@
}
}
}
}
</style>
}
</style>

View File

@@ -1,4 +1,4 @@
<template>
<template>
<view class="content">
<view class="form-block">
<view class="form-upd">
@@ -51,22 +51,22 @@
<label class="form-label">生产商地址</label>
<input type="text" v-model="productAddress" placeholder="输入商品生产商地址"/>
</view>
</view>
</view>
<!-- 安全区 -->
<view class="ios-bottom"></view>
<!-- footer -->
<view class="footer">
<button class="footer-btn" type="default" @click="submitAdd">提交认证审核</button>
<view class="ios-bottom"></view>
</view>
</view>
</template>
<script>
import { managesGoodsAuth, managesGoodsExtends } from '@/apis/interfaces/goods'
import { uploads } from '@/apis/interfaces/uploading'
export default {
data() {
</view>
</view>
</template>
<script>
import { managesGoodsAuth, managesGoodsExtends } from '@/apis/interfaces/goods'
import { uploads } from '@/apis/interfaces/uploading'
export default {
data() {
return {
productedAt : '', // 生产日期
expiriedAt : '', // 过期时间
@@ -74,7 +74,7 @@
productName : '', // 生产商名称
productAddress : '', // 生产商地址
extendCover : [] // 实物图片
};
};
},
created() {
if(this.$Route.query.edit == 'true'){
@@ -92,7 +92,7 @@
})
})
}
},
},
methods: {
// picker选择
pickerChange(e, key){
@@ -163,10 +163,10 @@
})
})
}
}
}
</script>
}
}
</script>
<style lang="scss" scoped>
.content{
padding-bottom: 150rpx;
@@ -371,5 +371,5 @@
}
}
}
}
</style>
}
</style>

View File

@@ -1,5 +1,5 @@
<template>
<view class="content">
<template>
<view class="content">
<!-- 分类 -->
<view class="tabs">
<view class="item" :class="{'show': status == '0'}" @click="onTabs('0')">已发布</view>
@@ -33,43 +33,43 @@
</template>
</goodsList>
<!-- 燃烧 增发 弹窗 -->
<uni-popup ref="popupLay" :safe-area="true" background-color="#ffffff">
<view class="popup">
<uni-popup ref="popupLay" :safe-area="true" background-color="#ffffff">
<view class="popup">
<view class="title">库存{{stockType == 'goodsMint' ? '增发': '燃烧'}}</view>
<view class="des">
剩余库存
<text>{{itemGoods.stock}}</text>
</view>
<view class="des">
数量
<uni-number-box v-model='stock' :min="1" :max="stockType == 'goodsBurn' ? itemGoods.stock : 9999"></uni-number-box>
</view>
<view class="btn" @click="additionalOrBurning">确认</view>
</view>
</view>
<view class="des">
数量
<uni-number-box v-model='stock' :min="1" :max="stockType == 'goodsBurn' ? itemGoods.stock : 9999"></uni-number-box>
</view>
<view class="btn" @click="additionalOrBurning">确认</view>
</view>
</uni-popup>
</view>
</template>
</view>
</template>
<script>
import { managesGoodsIndex, managesGoodsDelete, managesGoodsBurn, managesGoodsMint, managesGoodsCreateBefore } from '@/apis/interfaces/goods'
import goodsList from '@/components/goods-list/goods-list'
export default {
components: {
goodsList
},
data() {
import goodsList from '@/components/goods-list/goods-list'
export default {
components: {
goodsList
},
data() {
return {
status : 0,
status : 0,
goods : [],
pages : {},
itemGoods : {},
stock : 1,
stock : 1,
stockType : ''
};
},
};
},
onShow() {
this.getList()
},
this.getList()
},
methods: {
// tabs
onTabs(value){
@@ -115,9 +115,9 @@
},
// 提交燃烧,增发
additionalOrBurning(){
let data = {
id : this.itemGoods.goods_id,
stock: this.stock
let data = {
id : this.itemGoods.goods_id,
stock: this.stock
}
switch (this.stockType){
case 'goodsBurn':
@@ -154,32 +154,32 @@
},
// 移出删除商品
goodsRemove(id){
let index = this.goods.findIndex(val => val.goods_id == id)
let index = this.goods.findIndex(val => val.goods_id == id)
managesGoodsDelete(id).then(res => {
this.goods.splice(index,1)
if(this.goods.length === 0) this.getList()
uni.showToast({
title: '商品权证已删除',
icon : 'none'
})
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
}
},
onNavigationBarButtonTap() {
this.$Router.push({name: 'addClassify'})
}
}
</script>
}
}
</script>
<style lang="scss" scoped>
.content{
padding-top: 90rpx;
}
}
// tabs
.tabs{
position: fixed;
@@ -223,38 +223,38 @@
}
}
}
// 增发燃烧弹窗
.popup {
width: 100%;
// 增发燃烧弹窗
.popup {
width: 100%;
background-color: #fff;
padding-bottom: $padding;
.title {
font-size: 36rpx;
text-align: center;
padding: 50rpx 30rpx 30rpx 30rpx;
font-weight: bold;
}
.btn {
background-color: $text-price;
height: 90rpx;
line-height: 90rpx;
text-align: center;
padding-bottom: $padding;
.title {
font-size: 36rpx;
text-align: center;
padding: 50rpx 30rpx 30rpx 30rpx;
font-weight: bold;
}
.btn {
background-color: $text-price;
height: 90rpx;
line-height: 90rpx;
text-align: center;
color: #fff;
font-weight: bold;
font-size: $title-size;
margin: $padding * 2;
}
.des {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
font-size: $title-size;
margin: $padding * 2;
}
.des {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
padding: $padding $padding * 2;
color: $text-gray;
text{
color: $text-color;
}
}
}
}
}
}
</style>

View File

@@ -101,16 +101,16 @@
<style lang="scss">
.block-shadow{
box-shadow: 0 0 2rpx 2rpx rgba($color: #000000, $alpha: .02);
}
// 背景
.deal-back {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, #009B69, #00562d);
}
// 背景
.deal-back {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, #009B69, #00562d);
}
// 区块详情
.chian-hash{
@@ -169,5 +169,5 @@
color: white;
font-size: $title-size;
}
}
}
</style>

View File

@@ -1,74 +1,74 @@
<template>
<view>
<!-- 区块信息 -->
<view class="info-back"></view>
<view class="info-list">
<view class="flex" v-for="(item, index) in assetsList" :key="index">
<view class="item-name ellipsis">
<image class="icon" :src="item.icon" mode="widthFix" />
{{ item.name || '-' }}
</view>
<view class="item-label">
<view class="number ellipsis">{{ item.balance || '0.00' }}</view>
<view class="unit ellipsis">{{ item.symbol || '-' }}</view>
</view>
</view>
</view>
<!-- 区块链变化 -->
<view class="movements">
<view class="title">区块链变化</view>
<view class="chart">
<l-f2 ref="chartChange"></l-f2>
</view>
</view>
<!-- 区块记录 -->
<view class="chain-record">
<view class="title">区块记录</view>
<chain-list :list="chainList" @onChain="chainInfo"/>
</view>
<!-- 底部安全区 -->
<view class="ios-bottom"></view>
</view>
</template>
<template>
<view>
<!-- 区块信息 -->
<view class="info-back"></view>
<view class="info-list">
<view class="flex" v-for="(item, index) in assetsList" :key="index">
<view class="item-name ellipsis">
<image class="icon" :src="item.icon" mode="widthFix" />
{{ item.name || '-' }}
</view>
<view class="item-label">
<view class="number ellipsis">{{ item.balance || '0.00' }}</view>
<view class="unit ellipsis">{{ item.symbol || '-' }}</view>
</view>
</view>
</view>
<!-- 区块链变化 -->
<view class="movements">
<view class="title">区块链变化</view>
<view class="chart">
<l-f2 ref="chartChange"></l-f2>
</view>
</view>
<!-- 区块记录 -->
<view class="chain-record">
<view class="title">区块记录</view>
<chain-list :list="chainList" @onChain="chainInfo"/>
</view>
<!-- 底部安全区 -->
<view class="ios-bottom"></view>
</view>
</template>
<script>
import { chain, situation } from '@/apis/interfaces/chain'
import chainList from '@/components/chain/chain'
import F2 from '@/uni_modules/lime-f2/components/lime-f2/f2.min.js'
import lF2 from '@/uni_modules/lime-f2/components/lime-f2/'
export default {
components: {
chainList,
lF2
},
data() {
return {
data: [{
time: '2021-08-08 00:00:00',
value: 30
}, {
time: '2021-08-09 00:10:00',
value: 36
}, {
time: '2021-08-10 00:12:00',
value: 38
}, {
time: '2021-08-11 10:32:00',
value: 40
}, {
time: '2021-08-13 12:30:00',
value: 40
}, {
time: '2021-08-14 11:02:00',
value: 41
}, {
time: '2021-08-15 10:02:00',
value: 41
}],
assetsList: [],
chainList: []
};
},
import { chain, situation } from '@/apis/interfaces/chain'
import chainList from '@/components/chain/chain'
import F2 from '@/uni_modules/lime-f2/components/lime-f2/f2.min.js'
import lF2 from '@/uni_modules/lime-f2/components/lime-f2/'
export default {
components: {
chainList,
lF2
},
data() {
return {
data: [{
time: '2021-08-08 00:00:00',
value: 30
}, {
time: '2021-08-09 00:10:00',
value: 36
}, {
time: '2021-08-10 00:12:00',
value: 38
}, {
time: '2021-08-11 10:32:00',
value: 40
}, {
time: '2021-08-13 12:30:00',
value: 40
}, {
time: '2021-08-14 11:02:00',
value: 41
}, {
time: '2021-08-15 10:02:00',
value: 41
}],
assetsList: [],
chainList: []
};
},
mounted() {
Promise.all([chain(), situation()]).then(res => {
this.chainList = res[0]
@@ -78,8 +78,8 @@
icon: 'none',
title: 'err in chain/info.vue ' + err
})
})
this.$refs.chartChange.init(config => {
})
this.$refs.chartChange.init(config => {
const chart = new F2.Chart(config);
chart.source(this.data, {
time: {
@@ -116,8 +116,8 @@
.shape('smooth');
chart.render();
return chart;
})
},
})
},
methods: {
// 区块详情
chainInfo(e){
@@ -125,85 +125,85 @@
url: './deal?hash=' + e.hash
})
}
}
}
</script>
<style lang="scss">
// 背景
.info-back {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, #009B69, #00562d);
}
// 区块信息
.info-list {
padding: 0 $padding;
.flex {
margin: $margin * 2 $margin/2;
background-color: white;
border-radius: $radius;
padding: $padding * 2;
box-shadow: 0 0 2rpx 2rpx rgba($color: #000000, $alpha: .02);
display: flex;
justify-content: space-between;
.item-name {
width: 50%;
font-size: $title-size;
.icon {
width: 38rpx;
height: 38rpx;
vertical-align: middle;
margin-bottom: 5rpx;
margin-right: $margin;
}
}
.item-label {
width: 50%;
padding-left: $padding;
text-align: right;
.number {
font-weight: bold;
font-size: $title-size;
}
.unit {
font-size: $title-size-m;
}
}
}
}
// 区块链信息
.chain-record,
.movements {
padding: $padding;
.title {
font-weight: bold;
text-align: center;
color: white;
font-size: $title-size;
padding-bottom: $padding;
}
}
.movements {
.chart {
background-color: white;
margin: $margin/2;
height: 350rpx;
border-radius: $radius;
}
}
}
}
</script>
<style lang="scss">
// 背景
.info-back {
position: fixed;
top: 0;
left: 0;
z-index: -1;
width: 100vw;
height: 100vh;
background: linear-gradient(to bottom, #009B69, #00562d);
}
// 区块信息
.info-list {
padding: 0 $padding;
.flex {
margin: $margin * 2 $margin/2;
background-color: white;
border-radius: $radius;
padding: $padding * 2;
box-shadow: 0 0 2rpx 2rpx rgba($color: #000000, $alpha: .02);
display: flex;
justify-content: space-between;
.item-name {
width: 50%;
font-size: $title-size;
.icon {
width: 38rpx;
height: 38rpx;
vertical-align: middle;
margin-bottom: 5rpx;
margin-right: $margin;
}
}
.item-label {
width: 50%;
padding-left: $padding;
text-align: right;
.number {
font-weight: bold;
font-size: $title-size;
}
.unit {
font-size: $title-size-m;
}
}
}
}
// 区块链信息
.chain-record,
.movements {
padding: $padding;
.title {
font-weight: bold;
text-align: center;
color: white;
font-size: $title-size;
padding-bottom: $padding;
}
}
.movements {
.chart {
background-color: white;
margin: $margin/2;
height: 350rpx;
border-radius: $radius;
}
}
</style>

View File

@@ -1,20 +1,20 @@
<template>
<view class="kline">
<l-f2 ref="chart"></l-f2>
</view>
</template>
<script>
<template>
<view class="kline">
<l-f2 ref="chart"></l-f2>
</view>
</template>
<script>
import F2 from '@/uni_modules/lime-f2/components/lime-f2/f2.min.js'
import lF2 from '@/uni_modules/lime-f2/components/lime-f2/'
export default {
components: {
lF2,
},
data() {
return {
}
},
import lF2 from '@/uni_modules/lime-f2/components/lime-f2/'
export default {
components: {
lF2,
},
data() {
return {
}
},
async mounted() {
let data = await this.getData()
// 绘制K线
@@ -136,28 +136,28 @@
.shape('candle');
chart.render();
return chart;
});
},
methods: {
});
},
methods: {
getData() {
// plus.screen.lockOrientation('landscape-primary')
return new Promise((resolve) => {
uni.request({
url: 'https://gw.alipayobjects.com/os/antfincdn/c4ROEPcthk/candle-sticks.json',
success: (res) => {
resolve(res.data)
}
// plus.screen.lockOrientation('landscape-primary')
return new Promise((resolve) => {
uni.request({
url: 'https://gw.alipayobjects.com/os/antfincdn/c4ROEPcthk/candle-sticks.json',
success: (res) => {
resolve(res.data)
}
})
})
}
})
}
},
onUnload() {
console.log('222')
}
}
</script>
<style lang="scss">
}
}
</script>
<style lang="scss">
.kline{
}
}
</style>

View File

@@ -1,20 +1,22 @@
<template>
<template>
<view class="content">
<view class="title">易品新境</view>
<!-- <view class="title">易品新境</view> -->
<view class="login-top">
<view class="top-logo-content">
<image class="top-logo" fit="contain" src="/static/imgs/top_logo.png" />
链商星球(中国)
</view>
<image class="top-bg" fit="contain" src="/static/imgs/top_bg.png" />
</view>
<!-- 输入手机号相关 -->
<view class="inputs phone">
<label class="label">+86</label>
<input type="number" placeholder="输入您的手机号码" v-model="phone"/>
<input type="number" placeholder="输入您的手机号码" v-model="phone" />
</view>
<view class="inputs sms">
<input type="number" placeholder="输入短信验证码" v-model="code"/>
<button
class="sms-btn"
type="default"
size="mini"
:disabled="phone == '' || getSms"
@click="getPhoneCode"
>{{getSms ? '重新发送' + smsTime + 's': '发送验证码'}}</button>
<input type="number" placeholder="输入短信验证码" v-model="code" />
<button class="sms-btn" type="default" size="mini" :disabled="phone == '' || getSms"
@click="getPhoneCode">{{getSms ? '重新发送' + smsTime + 's': '发送验证码'}}</button>
</view>
<button class="btn" type="default" :disabled="phone == '' || code == ''" @click="login">登录</button>
<!-- 快捷登录 -->
@@ -25,86 +27,133 @@
</view>
</view>
<!-- 用户登录注册协议 -->
<view class="agreement">未注册的手机号验证后将自动创建账号登录即表示同意接收<navigator url="">用户隐私规格</navigator><navigator url="">用户服务协议</navigator></view>
</view>
</template>
<view class="agreement">未注册的手机号验证后将自动创建账号登录即表示同意接收<navigator url="">用户隐私规格</navigator><navigator url="">用户服务协议
</navigator>
</view>
</view>
</template>
<script>
import { getSms, smsAuth } from '@/apis/interfaces/auth'
export default {
data() {
import {
getSms,
smsAuth
} from '@/apis/interfaces/auth'
export default {
data() {
return {
phone : "18245180131",
code : "",
smsTime : 60,
getSms : false
}
},
phone: "18245180131",
code: "",
smsTime: 60,
getSms: false
}
},
methods: {
// 用户登录
login(){
login() {
smsAuth({
mobileNo: this.phone,
code : this.code
code: this.code
}).then(res => {
this.$store.commit('setToken', res.token_type + ' ' + res.access_token)
if(!res.is_company){
this.$Router.replace({name: "Registered"})
if (!res.is_company) {
this.$Router.replace({
name: "Index"
})
return
}
this.$Router.back()
}).catch(err => {
uni.showToast({
title: err.message,
icon : "none"
icon: "none"
})
})
},
// 获取验证码
getPhoneCode(){
getPhoneCode() {
let outTime
getSms({
mobileNo: this.phone
}).then(res => {
uni.showToast({
title: res,
icon : "none"
icon: "none"
})
this.getSms = true
outTime = setInterval(()=>{
if(this.smsTime <= 1){
this.getSms = false
outTime = setInterval(() => {
if (this.smsTime <= 1) {
this.getSms = false
this.smsTime = 60
clearInterval('outTime')
}
this.smsTime -= 1
},1000)
}, 1000)
}).catch(err => {
uni.showToast({
title: err.message,
icon : "none"
icon: "none"
})
})
}
}
}
</script>
<style lang="scss" scoped>
.content{
}
}
</script>
<style lang="scss" scoped>
.content {
height: 100vh;
width: 100vw;
padding: $padding * 3;
box-sizing: border-box;
background: white;
.inputs{
background: $border-color-lg;
.login-top {
height: 36vh;
width: 100%;
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: center;
box-sizing: border-box;
position: relative;
padding-bottom: 160rpx;
.top-bg {
position: absolute;
bottom: 30rpx;
// left: 2rpx;
z-index: 2;
width: 740rpx;
margin-left: 40rpx;
}
.top-logo-content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
box-sizing: border-box;
color: #7f56a4;
font-size: 18px;
.top-logo {
margin-bottom: 20rpx;
width: 240rpx;
height: 240rpx;
}
}
}
.inputs {
background:rgba($color: $mian-color, $alpha: 0.05);
border: solid 1rpx $border-color;
position: relative;
margin-top: $margin;
height: 80rpx;
line-height: 80rpx;
input{
input {
width: 100%;
height: 80rpx;
line-height: 80rpx;
@@ -113,9 +162,11 @@
box-sizing: border-box;
font-size: $title-size-lg;
}
&.phone{
&.phone {
padding-left: 120rpx;
.label{
.label {
position: absolute;
left: 0;
top: 0;
@@ -125,9 +176,11 @@
font-size: $title-size-lg;
}
}
&.sms{
&.sms {
padding-right: 200rpx;
.sms-btn[size='mini']{
.sms-btn[size='mini'] {
width: 200rpx;
height: 80rpx;
line-height: 80rpx;
@@ -140,25 +193,29 @@
border-left: solid 1rpx $border-color;
color: $text-price;
font-size: $title-size-lg;
&::after{
&::after {
border: none;
}
&[disabled]{
&[disabled] {
color: rgba($color: $text-price, $alpha: .6);
background: $border-color-lg;
}
}
}
}
.title{
.title {
text-align: center;
font-size: $title-size + 6;
font-weight: bold;
color: $text-color;
margin-bottom: 100rpx;
}
.btn{
background: $text-price;
.btn {
background: $mian-color;
color: white;
border-radius: 0;
margin-top: $margin;
@@ -166,39 +223,47 @@
line-height: 90rpx;
height: 90rpx;
font-weight: bold;
&::after{
&::after {
border: none;
}
&[disabled]{
background: rgba($color: $text-price, $alpha: .6);
&[disabled] {
background: rgba($color: $mian-color, $alpha: .6);
}
}
.quick{
.quick {
padding-top: $padding * 3;
text-align: center;
.quick-title{
.quick-title {
text-align: center;
color: $text-gray;
font-size: $title-size-sm;
padding-bottom: $padding;
}
.quick-box{
.quick-box {
display: flex;
justify-content: center;
.quick-icon{
.quick-icon {
width: 78rpx;
}
}
}
.agreement{
.agreement {
padding-top: $padding * 4;
font-size: $title-size-sm;
color: $text-gray;
navigator{
navigator {
color: $text-price;
display: inline-block;
padding: 0 10rpx;
}
}
}
}
</style>

45
pages/setting/aboutUs.vue Normal file
View File

@@ -0,0 +1,45 @@
<template>
<view class="AboutUs">
<u-parse :html="content"></u-parse>
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
aboutUs
} from '@/apis/interfaces/setting'
export default {
data() {
return {
content: ''
};
},
onLoad(e) {
this.getInfo()
},
methods: {
getInfo() {
aboutUs().then(res => {
this.content = res.content
}).catch(err => {
this.$refs.uToast.show({
title: err.message,
type: 'primary',
duration: 3000
})
})
}
}
}
</script>
<style lang="scss" scoped>
.AboutUs{
padding: 30rpx;
width: 100%;
min-height: 100vh;
background-color: #fff;
}
</style>

432
pages/setting/setting.vue Normal file
View File

@@ -0,0 +1,432 @@
<template>
<view class="Setting">
<!-- 更多管理 -->
<view class="list">
<!-- 修改头像 -->
<view class="list-item" @click="updImgs">
<view class="list-item-left">
<image src="/static/imgs/user-avatar.png" mode="widthFix" />
<span>修改头像</span>
</view>
<view class="avatar">
<image :src="avatar.showPath?avatar.showPath:'/static/imgs/no-avatar.png'" mode="aspectFill" />
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
</view>
<!-- 修改昵称 -->
<view class="list-item">
<view class="list-item-left">
<image src="/static/imgs/mine-self-name.png" mode="widthFix" />
<span>修改昵称</span>
</view>
<view class="input">
<input type="text" :value="nickname" @blur='blur' placeholder="请输入用户的昵称" maxlength="12" />
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
</view>
<!-- 绑定微信 -->
<button class="list-item" @click="getUser" v-if="false">
<view class="list-item-left">
<image src="/static/imgs/link-wechat.png" mode="widthFix" />
<span>绑定微信</span>
</view>
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</button>
<!-- 个人认证 -->
<view @click="certification(is_certification)" class="list-item">
<view class="list-item-left">
<image src="/static/imgs/self-icon.png" mode="widthFix" />
<span>个人认证</span>
</view>
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
<!-- 企业认证 -->
<view @click="company(is_company)" class="list-item">
<view class="list-item-left">
<image src="/static/imgs/company-icon.png" mode="widthFix" />
<span>企业认证</span>
</view>
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
<!-- 关于我们 -->
<view @click="$router.push({name:'aboutUs'})" class="list-item">
<view class="list-item-left">
<image src="/static/imgs/mine-about.png" mode="widthFix" />
<span>关于链商星球</span>
</view>
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
<!-- 切换账号 -->
<view @click="loginOut" class="list-item">
<view class="list-item-left">
<image src="/static/imgs/reset-info.png" mode="widthFix" />
<span>切换账户</span>
</view>
<u-icon name="arrow-right" color="#f1f1f1" size="28" />
</view>
</view>
<view class="edition">
链商星球 beta 1.0.0
</view>
<!-- 底部版本 -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import {
wechatbind,
resetUserInfo,
getUserSettingInfo
} from '@/apis/interfaces/setting'
import {
uploads
} from '@/apis/interfaces/uploading'
export default {
name: 'Setting',
data() {
return {
canLogin: true,
nickname: '',
avatar: {
path: '',
showPath: ''
},
is_bind: true, // 微信绑定
is_certification: true, // 个人认证
is_company: true, // 企业认证
}
},
onShow() {
wx.login({
success: res => {
this.loginCode = res.code
}
})
this.getUserInfo()
},
onPullDownRefresh() {
this.getUserInfo()
},
methods: {
// 是否个人认证
certification(is_certfication) {
console.log(is_certfication)
if (is_certfication) {
// 跳转到个人认证信息完成展示页面
this.$router.push({
name: ''
})
} else {
// 跳转到个人认证信息页面
this.$router.push({
name: ''
})
}
},
// 是否展示企业信息
company(is_company) {
console.log(is_company)
if (is_company) {
// 跳转到企业认证完成信息展示页面
this.$router.push({
name: ''
})
} else {
// 跳转到企业认证页面
this.$router.push({
name: ''
})
}
},
// 获取当前用户得基本信息
getUserInfo() {
getUserSettingInfo().then(res => {
this.avatar.showPath = res.avatar
this.nickname = res.nickname
this.is_bind = res.is_bind
this.is_certification = res.is_certification
this.is_company = res.is_company
uni.stopPullDownRefresh()
}).catch(err => {
this.$refs.uToast.show({
title: err.message,
type: 'primary',
duration: 3000
})
})
},
// 点击绑定用户得授权信息,且绑定带修改
getUser() {
uni.getUserProfile({
desc: "获取你的昵称、头像、地区及性别",
success: e => {
if (e.errMsg == "getUserProfile:ok") {
this.userInfo = e.userInfo
// // 检查用户登录Code是否过期
wx.checkSession({
success: res => {
this.userLogin(e)
},
fail: err => {
// 登录过期重新获取code
uni.login({
success: res => {
this.loginCode = res.code
// 登录
this.userLogin()
}
})
}
})
} else {
uni.showToast({
duration: 1500,
title: "绑定手机号失败了",
icon: 'none'
})
}
},
fail() {
uni.showToast({
duration: 1500,
title: "您拒绝了请求",
icon: 'none'
})
}
})
},
// 登陆接口
userLogin(info) {
let that = this
uni.login({
success: res => {
let data = {
iv: info.iv,
encryptedData: info.encryptedData,
code: res.code
}
uni.showLoading({
title: '绑定中'
})
wechatbind(data).then(res => {
setTimeout(res => {
uni.hideLoading()
}, 1000)
this.$refs.uToast.show({
title: '绑定成功',
type: 'primary',
duration: 3000
})
setTimeout(res => {
this.getUserInfo()
}, 3000)
}).catch(err => {
this.$refs.uToast.show({
title: err.message,
type: 'primary',
duration: 3000
})
uni.hideLoading()
})
}
});
},
loginOut() {
uni.removeStorageSync('token')
uni.reLaunch({
url: '/pages/login/login'
})
},
// 上传头像
updImgs(type) {
uni.chooseImage({
success: res => {
let path = res.tempFiles.map((val, index) => {
return {
name: 'uploads' + index,
uri: val.path
}
})
uploads(path).then(pathRes => {
this.avatar.path = pathRes.path[0]
this.avatar.showPath = pathRes.url[0]
this.resetUserInfo('avatar', pathRes.url[0])
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
}
})
},
// 修改姓名
blur(e) {
let value = e.detail.value
if (value !== this.nickname) {
this.resetUserInfo('nickname', value)
}
},
// 修改头像或昵称
resetUserInfo(key, value) {
let data = {
key: key,
value: value
}
resetUserInfo(data).then(res => {
console.log(res, 'res...')
uni.showToast({
title: res,
icon: 'none'
})
setTimeout(res => {
this.getUserInfo()
}, 2000)
}).catch(err => {
uni.showToast({
title: err.message,
icon: 'none'
})
})
}
}
}
</script>
<style lang="scss" scoped>
.Setting {
width: 100vw;
min-height: 100vh;
position: relative;
background-color: #fff;
// 版本
.edition {
color: #cacaca;
text-align: center;
padding: 20rpx 30rpx;
}
// 更多管理
.list {
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
box-sizing: border-box;
position: relative;
top: -10rpx;
border-radius: 20rpx;
margin: 0 40rpx;
padding: 30rpx 0;
width: calc(100% - 80rpx);
button::after {
border: none;
background-color: none;
}
button {
position: relative;
display: block;
margin-left: auto;
margin-right: auto;
padding-left: 0;
padding-right: 0;
box-sizing: border-box;
font-size: $title-size *0.9;
text-align: center;
text-decoration: none;
line-height: 1;
border-radius: 5px;
-webkit-tap-highlight-color: transparent;
overflow: hidden;
color: #333;
background-color: #fff;
}
.list-item {
width: 100%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 40rpx 0;
border-bottom: solid 1rpx #f7f7f7;
box-sizing: border-box;
.avatar {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
image {
width: 100rpx;
height: 100rpx;
border-radius: 50%;
margin-right: 20rpx;
}
}
.input {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
box-sizing: border-box;
text-align: right;
flex: 1;
input {
padding-right: 30rpx;
width: 100%;
}
}
.list-item-left {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
box-sizing: border-box;
image {
width: 44rpx;
height: 44rpx;
}
span {
margin-left: 30rpx;
}
}
}
}
// 底部轮播图跳转到其他app
.mine-banner {
position: relative;
width: calc(100% - 80rpx);
top: -20rpx;
margin: 0 40rpx;
box-sizing: border-box;
margin-top: $margin*2;
}
}
.loginOut {
margin: 30rpx 50rpx;
background-color: #fff;
box-shadow: 0 0 20rpx 4rpx rgba($color: $mian-color, $alpha: 0.1);
text-align: center;
padding: 20rpx;
border-radius: 10rpx;
color: #353535;
}
</style>

View File

@@ -8,6 +8,7 @@
<view class="item" @click="$Router.push({name: 'instrumentCustomer'})">成交客户</view>
<view class="item" @click="$Router.push({name: 'Personal'})">个人认证</view>
<view class="item" @click="$Router.push({name: 'instrumentBasics'})">企业认证</view>
<view class="item" @click="$Router.push({name: 'setting'})">设置中心</view>
</view>
</view>
</template>

View File

@@ -1,9 +1,9 @@
/**
* Web唐明明
* 匆匆数载恍如梦,岁月迢迢华发增。
* 碌碌无为枉半生,一朝惊醒万事空。
* moduleName: 日期
/**
* Web唐明明
* 匆匆数载恍如梦,岁月迢迢华发增。
* 碌碌无为枉半生,一朝惊醒万事空。
* moduleName: 日期
*/
export default getDate = (type) =>{

View File

@@ -1,16 +1,16 @@
/**
* Web唐明明
* 匆匆数载恍如梦,岁月迢迢华发增。
* 碌碌无为枉半生,一朝惊醒万事空。
* moduleName: 登录
/**
* Web唐明明
* 匆匆数载恍如梦,岁月迢迢华发增。
* 碌碌无为枉半生,一朝惊醒万事空。
* moduleName: 登录
*/
import { router } from '../router'
import { keyAuth } from '../apis/interfaces/auth'
import store from '../store'
class userAuth {
class userAuth {
constructor() {
this.univerfyConfig = {
fullScreen : true,
@@ -130,6 +130,6 @@ class userAuth {
updAuthToken(){
}
}
}
export default userAuth

View File

@@ -10,7 +10,7 @@ $text-color: #333;
$text-gray: #555;
$text-gray-m: #999;
$text-price: #8b64fd;
$mian-color: #8b64fd;
$mian-color: #b11eff;
$mian-color-deep: #824f9a;
// 边框颜色

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
static/imgs/link-wechat.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 956 B

BIN
static/imgs/mine-about.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
static/imgs/no-avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
static/imgs/reset-info.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 866 B

BIN
static/imgs/self-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
static/imgs/top_bg.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

BIN
static/imgs/top_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
static/imgs/user-avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 930 B

View File

@@ -6,18 +6,18 @@
## [代码示例http://liangei.gitee.io/limeui/#/f2-example](http://liangei.gitee.io/limeui/#/f2-example)
## 0.4.92021-05-12
- fix: 修复 百度平台 多个图表时 只生效一个的bug
## 0.4.82021-05-10
- feat: 增加 `destroy` 方法,用于销毁实例
- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
```js
this.$refs.chart.canvasToTempFilePath({success: res => {
console.log('tempFilePath:', res.tempFilePath)
}})
```
## [代码示例http://liangei.gitee.io/limeui/#/f2-example](http://liangei.gitee.io/limeui/#/f2-example)
## 0.4.72021-05-10
- chore: F2 版本更新至 3.8.7
## 0.4.82021-05-10
- feat: 增加 `destroy` 方法,用于销毁实例
- feat: 增加 `canvasToTempFilePath` 方法,用于生成图片
```js
this.$refs.chart.canvasToTempFilePath({success: res => {
console.log('tempFilePath:', res.tempFilePath)
}})
```
## [代码示例http://liangei.gitee.io/limeui/#/f2-example](http://liangei.gitee.io/limeui/#/f2-example)
## 0.4.72021-05-10
- chore: F2 版本更新至 3.8.7
## 0.4.62021-05-05
- docs: nvue 使用文档更新
## [代码示例http://liangei.gitee.io/limeui/#/f2-example](http://liangei.gitee.io/limeui/#/f2-example)

View File

@@ -1,121 +1,121 @@
import {
pixelRatio,
sleep
} from './utils';
const UNI_CANVAS_CONTEXT_MAP = {
// #ifndef MP-WEIXIN
fillStyle: 'FillStyle',
fontSize: 'FontSize',
globalAlpha: 'GlobalAlpha',
opacity: 'GlobalAlpha',
lineCap: 'LineCap',
lineJoin: 'LineJoin',
lineWidth: 'LineWidth',
miterLimit: 'MiterLimit',
strokeStyle: 'StrokeStyle',
textAlign: 'TextAlign',
textBaseline: 'TextBaseline',
shadow: 'Shadow',
// #endif
// #ifdef MP-TOUTIAO || H5 || APP-PLUS
font: 'FontSize',
// #endif
};
function strLen(str) {
let len = 0;
for (let i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
len++;
} else {
len += 2;
}
}
return len;
}
// 头条小程序目前仅支持 setFontSize
// f2 会将所有属性整合为 font 简写,从中提取 fontSize 支持
const fontSizeReg = /(\d*\.?\d*)px/;
const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
export default (ctx) => {
// #ifdef H5 || APP-PLUS
ctx.uniTransform = ctx.transform
ctx.transform = (...agrs) => {
if (ctx.draw && agrs[6]) {
agrs[4] *= pixelRatio
agrs[5] *= pixelRatio
}
if (agrs.length > 6) {
agrs.pop()
}
ctx.uniTransform(...agrs)
}
// #endif
// #ifdef MP-ALIPAY
ctx.canvasGetImageData = ctx.getImageData
ctx.getImageData = null
// #endif
if (!ctx.getImageData) {
ctx.getImageData = (...agrs) => {
const [x, y, width, height] = agrs
return new Promise(resolve => {
const parms = {
canvasId: ctx.id || ctx.canvasId,
x,
y,
width,
height,
success: res => {
resolve(res.data)
}
}
// #ifndef MP-ALIPAY || MP-TOUTIAO
uni.canvasGetImageData(parms)
// #endif
// #ifdef MP-ALIPAY || MP-TOUTIAO
ctx.canvasGetImageData(parms)
// #endif
})
}
}
// 钉钉小程序框架不支持 measureText 方法,用此方法 mock
if (!ctx.measureText) {
ctx.measureText = text => {
let fontSize = 12;
const font = ctx.__font;
if (font) {
fontSize = parseInt(font.split(' ')[3], 10);
}
fontSize /= 2;
return {
width: strLen(text) * fontSize
};
}
}
Object.keys(UNI_CANVAS_CONTEXT_MAP).forEach(key => {
Object.defineProperty(ctx, key, {
set(val) {
const name = `set${UNI_CANVAS_CONTEXT_MAP[key]}`;
if (!ctx[name]) {
return;
}
if (key === 'font' && fontSizeReg.test(val)) {
const match = fontSizeReg.exec(val);
ctx[name](match[1]);
return;
}
if (key === 'shadow' && Array.isArray(val)) {
ctx[name](...val);
return;
}
if(colorReg.test(val)) {
val = val.replace(colorReg, '#$1$1$2$2$3$3')
}
ctx[name](val);
}
});
});
return ctx
import {
pixelRatio,
sleep
} from './utils';
const UNI_CANVAS_CONTEXT_MAP = {
// #ifndef MP-WEIXIN
fillStyle: 'FillStyle',
fontSize: 'FontSize',
globalAlpha: 'GlobalAlpha',
opacity: 'GlobalAlpha',
lineCap: 'LineCap',
lineJoin: 'LineJoin',
lineWidth: 'LineWidth',
miterLimit: 'MiterLimit',
strokeStyle: 'StrokeStyle',
textAlign: 'TextAlign',
textBaseline: 'TextBaseline',
shadow: 'Shadow',
// #endif
// #ifdef MP-TOUTIAO || H5 || APP-PLUS
font: 'FontSize',
// #endif
};
function strLen(str) {
let len = 0;
for (let i = 0; i < str.length; i++) {
if (str.charCodeAt(i) > 0 && str.charCodeAt(i) < 128) {
len++;
} else {
len += 2;
}
}
return len;
}
// 头条小程序目前仅支持 setFontSize
// f2 会将所有属性整合为 font 简写,从中提取 fontSize 支持
const fontSizeReg = /(\d*\.?\d*)px/;
const colorReg = /#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])\b/g;
export default (ctx) => {
// #ifdef H5 || APP-PLUS
ctx.uniTransform = ctx.transform
ctx.transform = (...agrs) => {
if (ctx.draw && agrs[6]) {
agrs[4] *= pixelRatio
agrs[5] *= pixelRatio
}
if (agrs.length > 6) {
agrs.pop()
}
ctx.uniTransform(...agrs)
}
// #endif
// #ifdef MP-ALIPAY
ctx.canvasGetImageData = ctx.getImageData
ctx.getImageData = null
// #endif
if (!ctx.getImageData) {
ctx.getImageData = (...agrs) => {
const [x, y, width, height] = agrs
return new Promise(resolve => {
const parms = {
canvasId: ctx.id || ctx.canvasId,
x,
y,
width,
height,
success: res => {
resolve(res.data)
}
}
// #ifndef MP-ALIPAY || MP-TOUTIAO
uni.canvasGetImageData(parms)
// #endif
// #ifdef MP-ALIPAY || MP-TOUTIAO
ctx.canvasGetImageData(parms)
// #endif
})
}
}
// 钉钉小程序框架不支持 measureText 方法,用此方法 mock
if (!ctx.measureText) {
ctx.measureText = text => {
let fontSize = 12;
const font = ctx.__font;
if (font) {
fontSize = parseInt(font.split(' ')[3], 10);
}
fontSize /= 2;
return {
width: strLen(text) * fontSize
};
}
}
Object.keys(UNI_CANVAS_CONTEXT_MAP).forEach(key => {
Object.defineProperty(ctx, key, {
set(val) {
const name = `set${UNI_CANVAS_CONTEXT_MAP[key]}`;
if (!ctx[name]) {
return;
}
if (key === 'font' && fontSizeReg.test(val)) {
const match = fontSizeReg.exec(val);
ctx[name](match[1]);
return;
}
if (key === 'shadow' && Array.isArray(val)) {
ctx[name](...val);
return;
}
if(colorReg.test(val)) {
val = val.replace(colorReg, '#$1$1$2$2$3$3')
}
ctx[name](val);
}
});
});
return ctx
}

View File

@@ -1,417 +1,417 @@
<template>
<view class="l-f2" :style="customStyle" v-if="canvasId">
<!-- #ifndef APP-NVUE -->
<cover-view class="l-f2__mask" v-if="isMask"></cover-view>
<canvas
class="l-f2__canvas"
v-if="use2dCanvas"
type="2d"
:id="canvasId"
:style="'width:' + width + 'px;height:' + height + 'px'"
:disable-scroll="isDisableScroll"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
/>
<canvas
class="l-f2__canvas"
v-else
:width="nodeWidth"
:height="nodeHeight"
:style="'width:' + width + 'px;height:' + height + 'px'"
:canvas-id="canvasId"
:id="canvasId"
:disable-scroll="isDisableScroll"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
/>
<view v-if="isCloud" style="width:2048px; height:2048px; position: fixed; left: 9999px;">
<canvas v-if="use2dCanvas" type="2d" :canvas-id="canvasId + '_cloud'" :id="canvasId + '_cloud'" class="l-f2__canvas"></canvas>
<canvas v-else :canvas-id="canvasId + '_cloud'" :id="canvasId + '_cloud'" class="l-f2__canvas"></canvas>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<web-view
class="l-f2__canvas"
:id="canvasId"
ref="webview"
:webviewStyles="webviewStyles"
src="http://liangei.gitee.io/limeui/hybrid/html/lime-ui/lime-f2/index.html?v=0.4.8"
@pagefinish="isFinish = true"
@onPostMessage="onMessage"
></web-view>
<!-- #endif -->
</view>
</template>
<script>
// #ifndef APP-NVUE
import extendContext from './canvas';
import { compareVersion, wrapEvent, pixelRatio } from './utils';
// #endif
// #ifdef APP-NVUE
import { base64ToPath } from './utils';
// #endif
export default {
// version: '0.5.1'
name: 'l-f2',
props: {
// #ifdef MP-WEIXIN || MP-TOUTIAO
type: {
type: String,
default: '2d'
},
// #endif
// #ifdef APP-NVUE
webviewStyles: Object,
params: {
type: Object,
default: () => {}
},
// #endif
customStyle: String,
imageMask: String,
source: {
type: Array,
default: () => []
},
isAutoPlay: Boolean,
isDisableScroll: Boolean,
isCloud: Boolean,
onInit: {
type: [Function, Object],
default: () => {}
}
},
data() {
return {
// #ifdef MP-WEIXIN || MP-TOUTIAO
use2dCanvas: true,
// #endif
// #ifndef MP-WEIXIN || MP-TOUTIAO
use2dCanvas: false,
// #endif
// #ifndef APP-NVUE
width: null,
height: null,
nodeWidth: null,
nodeHeight: null,
isMask: false,
isInited: false,
imageData: null,
config: {},
// #endif
// #ifdef APP-NVUE
isFinish: false,
file: ''
// #endif
};
},
computed: {
canvasId() {
return `l-f2${this._uid}`;
}
},
watch: {
isAutoPlay(val) {
if (val) {
this.changeData(this.source);
}
},
source: {
handler: function(data) {
if (this.isAutoPlay) {
this.changeData(data);
}
},
deep: true
}
},
beforeDestroy() {
this.clear();
this.destroy();
},
created() {
this.isMask = this.isCloud && this.imageMask;
// #ifdef MP-WEIXIN || MP-TOUTIAO
const { SDKVersion, version, platform, environment } = uni.getSystemInfoSync();
// #endif
// #ifdef MP-WEIXIN
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0 && !((/ios/i.test(platform) && /7.0.20/.test(version)) || /wxwork/i.test(environment));
// #endif
// #ifdef MP-TOUTIAO
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '1.78.0') >= 0;
// #endif
},
async mounted() {
if (this.onInit) {
this.init(this.onInit);
}
},
methods: {
// #ifdef APP-NVUE
onMessage(e) {
const res = e?.detail?.data[0] || null;
if (res?.event) {
this.$emit(res.event, JSON.parse(res.data));
} else if (res?.file) {
this.file = res.data;
} else {
console.error(res);
}
},
// #endif
async init(func, params = null) {
// #ifdef APP-NVUE
this.$watch(
'isFinish',
(n, o) => {
(n || o) && (params || this.params) && this.$refs.webview.evalJs(`init(${JSON.stringify(func.toString())}, ${JSON.stringify(params || this.params)})`);
this.isInited = true;
},
{
immediate: true
}
);
// #endif
// #ifndef APP-NVUE
let config = await this.getContext(this.canvasId);
if (this.isCloud) {
let imageMask = null;
if (this.imageMask) {
this.isMask = true;
imageMask = await this.getImageMask(config);
this.imageData = imageMask;
this.isMask = false;
}
let cloud = await this.getContext(this.canvasId + '_cloud');
config = Object.assign({}, config, { cloud, imageMask });
}
const chart = await func(config);
if (chart) {
// #ifdef H5 || APP-PLUS
chart.repaint();
// #endif
this.chart = chart;
this.canvasEl = chart.get('el');
this.isInited = true;
}
// #endif
},
changeData(data) {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.changeData(data || this.source);
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`changeData(${JSON.stringify(data || this.source)})`);
// #endif
},
clear() {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.clear();
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`clear()`);
// #endif
},
destroy() {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.destroy();
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`destroy()`);
// #endif
},
repaint() {
this.changeData(this.source);
},
reset(func, params = null) {
// #ifndef APP-NVUE
this.$watch(
'isInited',
v => v && func(this.chart),
{
immediate: true
}
);
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`reset(${JSON.stringify(func.toString())}, ${JSON.stringify(params || this.params)})`);
// #endif
},
canvasToTempFilePath(args = {}) {
// #ifndef APP-NVUE
const { use2dCanvas, canvasId, config } = this;
return new Promise((resolve, reject) => {
const copyArgs = Object.assign(
{
canvasId,
success: resolve,
fail: reject
},
args
);
if (use2dCanvas) {
let { canvas } = config[canvasId];
delete copyArgs.canvasId;
copyArgs.canvas = canvas;
}
uni.canvasToTempFilePath(copyArgs, this);
});
// #endif
// #ifdef APP-NVUE
this.file = '';
this.$refs.webview.evalJs(`canvasToTempFilePath()`);
return new Promise((resolve, reject) => {
this.$watch('file', async file => {
if (file) {
const tempFilePath = await base64ToPath(file);
resolve(args.success({ tempFilePath }));
} else {
reject(args.fail({ error: `` }));
}
});
});
// #endif
},
// #ifndef APP-NVUE
getImageMask(config) {
return new Promise(resolve => {
uni.getImageInfo({
src: this.imageMask,
success: async res => {
if (res.path) {
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
const localReg = /^\.|^\/(?=[^\/])/;
res.path = localReg.test(this.imageMask) ? `/${res.path}` : res.path;
// #endif
const { context, width, height, canvas } = config;
if (this.use2dCanvas) {
const imageMask = () => {
const imageMask = canvas.createImage();
imageMask.crossOrigin = '';
imageMask.src = res.path;
imageMask.onload = async () => {
context.drawImage(imageMask, 0, 0, res.width, res.height, 0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height).data;
context.clearRect(0, 0, width, height);
resolve(imageData);
};
};
imageMask();
} else {
// #ifndef MP-BAIDU
context.drawImage(res.path, 0, 0, res.width, res.height, 0, 0, width, height);
// #endif
// #ifdef MP-BAIDU
context.drawImage(res.path, 0, 0, width, height, 0, 0, res.width, res.height);
// #endif
await this.canvasDraw(context);
const imageData = await context.getImageData(0, 0, width, height);
context.clearRect(0, 0, width, height);
await this.canvasDraw(context);
resolve(imageData);
}
}
},
fail(err) {
console.error(JSON.stringify(err));
resolve(null);
}
});
});
},
canvasDraw(ctx) {
return new Promise(resolve => {
ctx.draw(false, () => {
setTimeout(() => {
resolve(true);
}, 100);
});
});
},
getContext(canvasId) {
const { use2dCanvas, type = '2d', config } = this;
if (config[canvasId]?.context) {
return Promise.resolve(config[canvasId]);
}
if (use2dCanvas) {
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select(`#${canvasId}`)
.fields({
node: true,
size: true
})
.exec(res => {
let { node, width, height } = res[0];
width = width || 300;
height = height || 300;
const context = node.getContext(type);
if (!canvasId.includes('_cloud')) {
this.width = width;
this.height = height;
}
node.width = width * pixelRatio;
node.height = height * pixelRatio;
this.config[canvasId] = { context: extendContext(context), width, height, pixelRatio, canvas: node };
resolve(this.config[canvasId]);
});
});
}
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select(`#${canvasId}`)
.boundingClientRect()
.exec(res => {
if (res) {
let { width, height } = res[0];
width = width || 300;
height = height || 300;
const context = uni.createCanvasContext(canvasId, this);
if (!canvasId.includes('_cloud')) {
this.width = width;
this.height = height;
// #ifdef MP-ALIPAY
this.nodeWidth = width * pixelRatio;
this.nodeHeight = height * pixelRatio;
// #endif
}
this.config[canvasId] = { context: extendContext(context), width, height, pixelRatio };
resolve(this.config[canvasId]);
}
});
});
},
touchStart(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchstart', wrapEvent(e));
}
},
touchMove(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchmove', wrapEvent(e));
}
},
touchEnd(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchend', wrapEvent(e));
}
}
// #endif
}
};
</script>
<template>
<view class="l-f2" :style="customStyle" v-if="canvasId">
<!-- #ifndef APP-NVUE -->
<cover-view class="l-f2__mask" v-if="isMask"></cover-view>
<canvas
class="l-f2__canvas"
v-if="use2dCanvas"
type="2d"
:id="canvasId"
:style="'width:' + width + 'px;height:' + height + 'px'"
:disable-scroll="isDisableScroll"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
/>
<canvas
class="l-f2__canvas"
v-else
:width="nodeWidth"
:height="nodeHeight"
:style="'width:' + width + 'px;height:' + height + 'px'"
:canvas-id="canvasId"
:id="canvasId"
:disable-scroll="isDisableScroll"
@touchstart="touchStart"
@touchmove="touchMove"
@touchend="touchEnd"
/>
<view v-if="isCloud" style="width:2048px; height:2048px; position: fixed; left: 9999px;">
<canvas v-if="use2dCanvas" type="2d" :canvas-id="canvasId + '_cloud'" :id="canvasId + '_cloud'" class="l-f2__canvas"></canvas>
<canvas v-else :canvas-id="canvasId + '_cloud'" :id="canvasId + '_cloud'" class="l-f2__canvas"></canvas>
</view>
<!-- #endif -->
<!-- #ifdef APP-NVUE -->
<web-view
class="l-f2__canvas"
:id="canvasId"
ref="webview"
:webviewStyles="webviewStyles"
src="http://liangei.gitee.io/limeui/hybrid/html/lime-ui/lime-f2/index.html?v=0.4.8"
@pagefinish="isFinish = true"
@onPostMessage="onMessage"
></web-view>
<!-- #endif -->
</view>
</template>
<script>
// #ifndef APP-NVUE
import extendContext from './canvas';
import { compareVersion, wrapEvent, pixelRatio } from './utils';
// #endif
// #ifdef APP-NVUE
import { base64ToPath } from './utils';
// #endif
export default {
// version: '0.5.1'
name: 'l-f2',
props: {
// #ifdef MP-WEIXIN || MP-TOUTIAO
type: {
type: String,
default: '2d'
},
// #endif
// #ifdef APP-NVUE
webviewStyles: Object,
params: {
type: Object,
default: () => {}
},
// #endif
customStyle: String,
imageMask: String,
source: {
type: Array,
default: () => []
},
isAutoPlay: Boolean,
isDisableScroll: Boolean,
isCloud: Boolean,
onInit: {
type: [Function, Object],
default: () => {}
}
},
data() {
return {
// #ifdef MP-WEIXIN || MP-TOUTIAO
use2dCanvas: true,
// #endif
// #ifndef MP-WEIXIN || MP-TOUTIAO
use2dCanvas: false,
// #endif
// #ifndef APP-NVUE
width: null,
height: null,
nodeWidth: null,
nodeHeight: null,
isMask: false,
isInited: false,
imageData: null,
config: {},
// #endif
// #ifdef APP-NVUE
isFinish: false,
file: ''
// #endif
};
},
computed: {
canvasId() {
return `l-f2${this._uid}`;
}
},
watch: {
isAutoPlay(val) {
if (val) {
this.changeData(this.source);
}
},
source: {
handler: function(data) {
if (this.isAutoPlay) {
this.changeData(data);
}
},
deep: true
}
},
beforeDestroy() {
this.clear();
this.destroy();
},
created() {
this.isMask = this.isCloud && this.imageMask;
// #ifdef MP-WEIXIN || MP-TOUTIAO
const { SDKVersion, version, platform, environment } = uni.getSystemInfoSync();
// #endif
// #ifdef MP-WEIXIN
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '2.9.2') >= 0 && !((/ios/i.test(platform) && /7.0.20/.test(version)) || /wxwork/i.test(environment));
// #endif
// #ifdef MP-TOUTIAO
this.use2dCanvas = this.type === '2d' && compareVersion(SDKVersion, '1.78.0') >= 0;
// #endif
},
async mounted() {
if (this.onInit) {
this.init(this.onInit);
}
},
methods: {
// #ifdef APP-NVUE
onMessage(e) {
const res = e?.detail?.data[0] || null;
if (res?.event) {
this.$emit(res.event, JSON.parse(res.data));
} else if (res?.file) {
this.file = res.data;
} else {
console.error(res);
}
},
// #endif
async init(func, params = null) {
// #ifdef APP-NVUE
this.$watch(
'isFinish',
(n, o) => {
(n || o) && (params || this.params) && this.$refs.webview.evalJs(`init(${JSON.stringify(func.toString())}, ${JSON.stringify(params || this.params)})`);
this.isInited = true;
},
{
immediate: true
}
);
// #endif
// #ifndef APP-NVUE
let config = await this.getContext(this.canvasId);
if (this.isCloud) {
let imageMask = null;
if (this.imageMask) {
this.isMask = true;
imageMask = await this.getImageMask(config);
this.imageData = imageMask;
this.isMask = false;
}
let cloud = await this.getContext(this.canvasId + '_cloud');
config = Object.assign({}, config, { cloud, imageMask });
}
const chart = await func(config);
if (chart) {
// #ifdef H5 || APP-PLUS
chart.repaint();
// #endif
this.chart = chart;
this.canvasEl = chart.get('el');
this.isInited = true;
}
// #endif
},
changeData(data) {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.changeData(data || this.source);
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`changeData(${JSON.stringify(data || this.source)})`);
// #endif
},
clear() {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.clear();
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`clear()`);
// #endif
},
destroy() {
// #ifndef APP-NVUE
if (this.chart) {
this.chart.destroy();
}
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`destroy()`);
// #endif
},
repaint() {
this.changeData(this.source);
},
reset(func, params = null) {
// #ifndef APP-NVUE
this.$watch(
'isInited',
v => v && func(this.chart),
{
immediate: true
}
);
// #endif
// #ifdef APP-NVUE
this.$refs.webview.evalJs(`reset(${JSON.stringify(func.toString())}, ${JSON.stringify(params || this.params)})`);
// #endif
},
canvasToTempFilePath(args = {}) {
// #ifndef APP-NVUE
const { use2dCanvas, canvasId, config } = this;
return new Promise((resolve, reject) => {
const copyArgs = Object.assign(
{
canvasId,
success: resolve,
fail: reject
},
args
);
if (use2dCanvas) {
let { canvas } = config[canvasId];
delete copyArgs.canvasId;
copyArgs.canvas = canvas;
}
uni.canvasToTempFilePath(copyArgs, this);
});
// #endif
// #ifdef APP-NVUE
this.file = '';
this.$refs.webview.evalJs(`canvasToTempFilePath()`);
return new Promise((resolve, reject) => {
this.$watch('file', async file => {
if (file) {
const tempFilePath = await base64ToPath(file);
resolve(args.success({ tempFilePath }));
} else {
reject(args.fail({ error: `` }));
}
});
});
// #endif
},
// #ifndef APP-NVUE
getImageMask(config) {
return new Promise(resolve => {
uni.getImageInfo({
src: this.imageMask,
success: async res => {
if (res.path) {
// #ifdef MP-WEIXIN || MP-BAIDU || MP-QQ || MP-TOUTIAO
const localReg = /^\.|^\/(?=[^\/])/;
res.path = localReg.test(this.imageMask) ? `/${res.path}` : res.path;
// #endif
const { context, width, height, canvas } = config;
if (this.use2dCanvas) {
const imageMask = () => {
const imageMask = canvas.createImage();
imageMask.crossOrigin = '';
imageMask.src = res.path;
imageMask.onload = async () => {
context.drawImage(imageMask, 0, 0, res.width, res.height, 0, 0, width, height);
const imageData = context.getImageData(0, 0, width, height).data;
context.clearRect(0, 0, width, height);
resolve(imageData);
};
};
imageMask();
} else {
// #ifndef MP-BAIDU
context.drawImage(res.path, 0, 0, res.width, res.height, 0, 0, width, height);
// #endif
// #ifdef MP-BAIDU
context.drawImage(res.path, 0, 0, width, height, 0, 0, res.width, res.height);
// #endif
await this.canvasDraw(context);
const imageData = await context.getImageData(0, 0, width, height);
context.clearRect(0, 0, width, height);
await this.canvasDraw(context);
resolve(imageData);
}
}
},
fail(err) {
console.error(JSON.stringify(err));
resolve(null);
}
});
});
},
canvasDraw(ctx) {
return new Promise(resolve => {
ctx.draw(false, () => {
setTimeout(() => {
resolve(true);
}, 100);
});
});
},
getContext(canvasId) {
const { use2dCanvas, type = '2d', config } = this;
if (config[canvasId]?.context) {
return Promise.resolve(config[canvasId]);
}
if (use2dCanvas) {
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select(`#${canvasId}`)
.fields({
node: true,
size: true
})
.exec(res => {
let { node, width, height } = res[0];
width = width || 300;
height = height || 300;
const context = node.getContext(type);
if (!canvasId.includes('_cloud')) {
this.width = width;
this.height = height;
}
node.width = width * pixelRatio;
node.height = height * pixelRatio;
this.config[canvasId] = { context: extendContext(context), width, height, pixelRatio, canvas: node };
resolve(this.config[canvasId]);
});
});
}
return new Promise(resolve => {
uni.createSelectorQuery()
.in(this)
.select(`#${canvasId}`)
.boundingClientRect()
.exec(res => {
if (res) {
let { width, height } = res[0];
width = width || 300;
height = height || 300;
const context = uni.createCanvasContext(canvasId, this);
if (!canvasId.includes('_cloud')) {
this.width = width;
this.height = height;
// #ifdef MP-ALIPAY
this.nodeWidth = width * pixelRatio;
this.nodeHeight = height * pixelRatio;
// #endif
}
this.config[canvasId] = { context: extendContext(context), width, height, pixelRatio };
resolve(this.config[canvasId]);
}
});
});
},
touchStart(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchstart', wrapEvent(e));
}
},
touchMove(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchmove', wrapEvent(e));
}
},
touchEnd(e) {
if (this.canvasEl) {
this.canvasEl.dispatchEvent('touchend', wrapEvent(e));
}
}
// #endif
}
};
</script>
<style scoped lang="stylus">
full()
// #ifndef APP-NVUE

View File

@@ -1,65 +1,65 @@
// #ifndef APP-NVUE
// 计算版本
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
}
export function wrapEvent(e) {
if (!e) return;
if (!e.preventDefault) {
e.preventDefault = function() {};
}
return e;
}
// #ifndef APP-NVUE
// 计算版本
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
}
export function wrapEvent(e) {
if (!e) return;
if (!e.preventDefault) {
e.preventDefault = function() {};
}
return e;
}
export const pixelRatio = uni.getSystemInfoSync().pixelRatio
// #endif
// #ifdef APP-NVUE
export function base64ToPath(base64) {
return new Promise((resolve, reject) => {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
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
// #ifdef APP-NVUE
export function base64ToPath(base64) {
return new Promise((resolve, reject) => {
const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64) || [];
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

View File

@@ -1,82 +1,82 @@
{
"id": "lime-f2",
"displayName": "蚂蚁图表 antv F2",
"version": "0.5.1",
"description": "全端兼容,一个专注于移动,开箱即用的可视化解决方案",
"keywords": [
"蚂蚁金服",
"AntV",
"F2",
"canvas",
"图表"
],
"repository": "https://gitee.com/liangei/lime-f2",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
},
"dependencies": {
}
}
{
"id": "lime-f2",
"displayName": "蚂蚁图表 antv F2",
"version": "0.5.1",
"description": "全端兼容,一个专注于移动,开箱即用的可视化解决方案",
"keywords": [
"蚂蚁金服",
"AntV",
"F2",
"canvas",
"图表"
],
"repository": "https://gitee.com/liangei/lime-f2",
"engines": {
"HBuilderX": "^3.1.0"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
},
"dependencies": {
}
}

View File

@@ -2,8 +2,8 @@
> F2一个专注于移动开箱即用的可视化解决方案 [查看更多](http://liangei.gitee.io/limeui/#/f2)
> 基于antv F2 做了兼容处理,更多示例请访问 [uni示例](http://liangei.gitee.io/limeui/#/f2-example) [官方示例](https://f2.antv.vision/zh/examples/gallery)
> Q群1046793420
> antv F2 v3.8.7
> antv F2 v3.8.7
## 平台兼容
@@ -13,7 +13,7 @@
| √ | √ | √ | √ | √ | √ | √ |
***注意**
***注意**
* 🔔 插件用到了 css 预编译器 [stylus](https://ext.dcloud.net.cn/plugin?name=compile-stylus) 请安装
* 🌈 本插件使用了`webview`支持`nvue`
* 📦 本插件没有对F2内部的方法和样式做过改动只是使其兼容uniapp。
@@ -249,11 +249,11 @@ export default {
```
## Nvue 使用注意事项
- 由于 nvue 使用的是字符串模板传输,打包的时候会被混淆压缩
- 所在要保持 **关键词** 不被 **混淆压缩**
- 所在要保持 **关键词** 不被 **混淆压缩**
#### 1、F2、DataSet 不需要被引入
#### 1、F2、DataSet 不需要被引入
👎 错误
👎 错误
```js
import F2 from '@/uni_modules/lime-f2/components/lime-f2/f2-all.min.js';
@@ -261,19 +261,19 @@ import DataSet from '@/antv/DataSet'
export default {
...code
}
```
```
👍 正确
👍 正确
```js
export default {
...code
}
```
```
#### 2、引用函数外面数据的**关键词**不需要声明
#### 2、引用函数外面数据的**关键词**不需要声明
👎 错误
👎 错误
```js
const {data} = this
@@ -281,52 +281,52 @@ this.$refs.chart.init(config => {
chart.source(data);
})
```
```
👍 正确
👍 正确
```js
// 所有用函数外里的数据,只要保持跟 this 里的一致
this.$refs.chart.init(config => {
chart.source(data);
})
})
- or -
- or -
this.$refs.chart.init(config => {
chart.source(this.data);
})
```
```
#### 3、引用函数外面的数据需要通过**params**或函数的第二个参数传递
#### 3、引用函数外面的数据需要通过**params**或函数的第二个参数传递
👎 错误
👎 错误
```html
<l-f2 />
<l-f2 />
- or -
- or -
this.$refs.chart.init(config => {...code})
```
```
👍 正确
👍 正确
```html
<l-f2 :params="{data}"/>
<l-f2 :params="{data}"/>
- or -
- or -
this.$refs.chart.init(config => {...code}, {data: this.data})
```
## 不支持的功能
- 目前由于小程序不支持 `document`,所以 `Guide.Html` 辅助元素组件目前仍无法使用,其他 F2 的功能全部支持。
- **Nvue**是通过`webview`实现的,所以它不受影响!
- **Nvue**是通过`webview`实现的,所以它不受影响!
- **H5** uni官方 `canvas` 模拟了 小程序 所以也不支持 。
- 缩放手势暂时不支持,因为原厂也不支持小程序,将来如果有需要考虑修改源码。
- 词云原厂也是不支持小程序本插件修改源码使得支持但头条小程序需要1.78.0以后。
- 缩放手势暂时不支持,因为原厂也不支持小程序,将来如果有需要考虑修改源码。
- 词云原厂也是不支持小程序本插件修改源码使得支持但头条小程序需要1.78.0以后。
## Props
@@ -334,25 +334,25 @@ this.$refs.chart.init(config => {...code}, {data: this.data})
| --------------- | -------- | ------- | ------------ | ----- |
| custom-style | 自定义样式 | `string` | - | - |
| params | 仅针对nvue的数据传递,同init函数的第二个参数两选一 | `object` | - | - |
| webviewStyles | 仅针对nvue的webview设置样式 | `object` | - | - |
| source | 图表数据 | `array` | - | 0.3.0 |
| webviewStyles | 仅针对nvue的webview设置样式 | `object` | - | - |
| source | 图表数据 | `array` | - | 0.3.0 |
| type | canvas 类型 2d 仅针对微信和头条有效 | `string` | `2d` | 0.3.0 |
| isAutoPlay | 设置了上方的 图表数据 再 设置本参数 ,只要数据发生改动就更新图表 | `boolean` | `false` | 0.3.0 |
| is-disable-scroll | 触摸图表时是否禁止页面滚动 | `boolean` | `false` | |
| is-disable-scroll | 触摸图表时是否禁止页面滚动 | `boolean` | `false` | |
## 事件
| 参数 | 说明 |
| --------------- | --------------- |
| init(callback, data) | **callback**: 回调函数 **data**: `nvue` 如果使用了外部数据,需要传递 |
| changeData(data) | 更新数据 ,传递是数据数组 |
| clear() | 清除所有 |
| clear() | 清除所有 |
| destroy() | 销毁实例 |
| repaint() | 用于暂时只更新数据,等需要时再调用重绘 |
| reset(callback, data) | 重新定义图形语法,改变图表类型和各种配置, **callback**: 回调函数 **data**: `nvue` 如果使用了外部数据,需要传递 |
| canvasToTempFilePath(opt) | 用于生成图片 |
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
| reset(callback, data) | 重新定义图形语法,改变图表类型和各种配置, **callback**: 回调函数 **data**: `nvue` 如果使用了外部数据,需要传递 |
| canvasToTempFilePath(opt) | 用于生成图片 |
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
![输入图片说明](https://cdn.jsdelivr.net/gh/liangei/image@latest/222521_bb543f96_518581.jpeg "微信图片编辑_20201122220352.jpg")

View File

@@ -1,132 +1,132 @@
export default {
"pulldown": "\ue588",
"refreshempty": "\ue461",
"back": "\ue471",
"forward": "\ue470",
"more": "\ue507",
"more-filled": "\ue537",
"scan": "\ue612",
"qq": "\ue264",
"weibo": "\ue260",
"weixin": "\ue261",
"pengyouquan": "\ue262",
"loop": "\ue565",
"refresh": "\ue407",
"refresh-filled": "\ue437",
"arrowthindown": "\ue585",
"arrowthinleft": "\ue586",
"arrowthinright": "\ue587",
"arrowthinup": "\ue584",
"undo-filled": "\ue7d6",
"undo": "\ue406",
"redo": "\ue405",
"redo-filled": "\ue7d9",
"bars": "\ue563",
"chatboxes": "\ue203",
"camera": "\ue301",
"chatboxes-filled": "\ue233",
"camera-filled": "\ue7ef",
"cart-filled": "\ue7f4",
"cart": "\ue7f5",
"checkbox-filled": "\ue442",
"checkbox": "\ue7fa",
"arrowleft": "\ue582",
"arrowdown": "\ue581",
"arrowright": "\ue583",
"smallcircle-filled": "\ue801",
"arrowup": "\ue580",
"circle": "\ue411",
"eye-filled": "\ue568",
"eye-slash-filled": "\ue822",
"eye-slash": "\ue823",
"eye": "\ue824",
"flag-filled": "\ue825",
"flag": "\ue508",
"gear-filled": "\ue532",
"reload": "\ue462",
"gear": "\ue502",
"hand-thumbsdown-filled": "\ue83b",
"hand-thumbsdown": "\ue83c",
"hand-thumbsup-filled": "\ue83d",
"heart-filled": "\ue83e",
"hand-thumbsup": "\ue83f",
"heart": "\ue840",
"home": "\ue500",
"info": "\ue504",
"home-filled": "\ue530",
"info-filled": "\ue534",
"circle-filled": "\ue441",
"chat-filled": "\ue847",
"chat": "\ue263",
"mail-open-filled": "\ue84d",
"email-filled": "\ue231",
"mail-open": "\ue84e",
"email": "\ue201",
"checkmarkempty": "\ue472",
"list": "\ue562",
"locked-filled": "\ue856",
"locked": "\ue506",
"map-filled": "\ue85c",
"map-pin": "\ue85e",
"map-pin-ellipse": "\ue864",
"map": "\ue364",
"minus-filled": "\ue440",
"mic-filled": "\ue332",
"minus": "\ue410",
"micoff": "\ue360",
"mic": "\ue302",
"clear": "\ue434",
"smallcircle": "\ue868",
"close": "\ue404",
"closeempty": "\ue460",
"paperclip": "\ue567",
"paperplane": "\ue503",
"paperplane-filled": "\ue86e",
"person-filled": "\ue131",
"contact-filled": "\ue130",
"person": "\ue101",
"contact": "\ue100",
"images-filled": "\ue87a",
"phone": "\ue200",
"images": "\ue87b",
"image": "\ue363",
"image-filled": "\ue877",
"location-filled": "\ue333",
"location": "\ue303",
"plus-filled": "\ue439",
"plus": "\ue409",
"plusempty": "\ue468",
"help-filled": "\ue535",
"help": "\ue505",
"navigate-filled": "\ue884",
"navigate": "\ue501",
"mic-slash-filled": "\ue892",
"search": "\ue466",
"settings": "\ue560",
"sound": "\ue590",
"sound-filled": "\ue8a1",
"spinner-cycle": "\ue465",
"download-filled": "\ue8a4",
"personadd-filled": "\ue132",
"videocam-filled": "\ue8af",
"personadd": "\ue102",
"upload": "\ue402",
"upload-filled": "\ue8b1",
"starhalf": "\ue463",
"star-filled": "\ue438",
"star": "\ue408",
"trash": "\ue401",
"phone-filled": "\ue230",
"compose": "\ue400",
"videocam": "\ue300",
"trash-filled": "\ue8dc",
"download": "\ue403",
"chatbubble-filled": "\ue232",
"chatbubble": "\ue202",
"cloud-download": "\ue8e4",
"cloud-upload-filled": "\ue8e5",
"cloud-upload": "\ue8e6",
export default {
"pulldown": "\ue588",
"refreshempty": "\ue461",
"back": "\ue471",
"forward": "\ue470",
"more": "\ue507",
"more-filled": "\ue537",
"scan": "\ue612",
"qq": "\ue264",
"weibo": "\ue260",
"weixin": "\ue261",
"pengyouquan": "\ue262",
"loop": "\ue565",
"refresh": "\ue407",
"refresh-filled": "\ue437",
"arrowthindown": "\ue585",
"arrowthinleft": "\ue586",
"arrowthinright": "\ue587",
"arrowthinup": "\ue584",
"undo-filled": "\ue7d6",
"undo": "\ue406",
"redo": "\ue405",
"redo-filled": "\ue7d9",
"bars": "\ue563",
"chatboxes": "\ue203",
"camera": "\ue301",
"chatboxes-filled": "\ue233",
"camera-filled": "\ue7ef",
"cart-filled": "\ue7f4",
"cart": "\ue7f5",
"checkbox-filled": "\ue442",
"checkbox": "\ue7fa",
"arrowleft": "\ue582",
"arrowdown": "\ue581",
"arrowright": "\ue583",
"smallcircle-filled": "\ue801",
"arrowup": "\ue580",
"circle": "\ue411",
"eye-filled": "\ue568",
"eye-slash-filled": "\ue822",
"eye-slash": "\ue823",
"eye": "\ue824",
"flag-filled": "\ue825",
"flag": "\ue508",
"gear-filled": "\ue532",
"reload": "\ue462",
"gear": "\ue502",
"hand-thumbsdown-filled": "\ue83b",
"hand-thumbsdown": "\ue83c",
"hand-thumbsup-filled": "\ue83d",
"heart-filled": "\ue83e",
"hand-thumbsup": "\ue83f",
"heart": "\ue840",
"home": "\ue500",
"info": "\ue504",
"home-filled": "\ue530",
"info-filled": "\ue534",
"circle-filled": "\ue441",
"chat-filled": "\ue847",
"chat": "\ue263",
"mail-open-filled": "\ue84d",
"email-filled": "\ue231",
"mail-open": "\ue84e",
"email": "\ue201",
"checkmarkempty": "\ue472",
"list": "\ue562",
"locked-filled": "\ue856",
"locked": "\ue506",
"map-filled": "\ue85c",
"map-pin": "\ue85e",
"map-pin-ellipse": "\ue864",
"map": "\ue364",
"minus-filled": "\ue440",
"mic-filled": "\ue332",
"minus": "\ue410",
"micoff": "\ue360",
"mic": "\ue302",
"clear": "\ue434",
"smallcircle": "\ue868",
"close": "\ue404",
"closeempty": "\ue460",
"paperclip": "\ue567",
"paperplane": "\ue503",
"paperplane-filled": "\ue86e",
"person-filled": "\ue131",
"contact-filled": "\ue130",
"person": "\ue101",
"contact": "\ue100",
"images-filled": "\ue87a",
"phone": "\ue200",
"images": "\ue87b",
"image": "\ue363",
"image-filled": "\ue877",
"location-filled": "\ue333",
"location": "\ue303",
"plus-filled": "\ue439",
"plus": "\ue409",
"plusempty": "\ue468",
"help-filled": "\ue535",
"help": "\ue505",
"navigate-filled": "\ue884",
"navigate": "\ue501",
"mic-slash-filled": "\ue892",
"search": "\ue466",
"settings": "\ue560",
"sound": "\ue590",
"sound-filled": "\ue8a1",
"spinner-cycle": "\ue465",
"download-filled": "\ue8a4",
"personadd-filled": "\ue132",
"videocam-filled": "\ue8af",
"personadd": "\ue102",
"upload": "\ue402",
"upload-filled": "\ue8b1",
"starhalf": "\ue463",
"star-filled": "\ue438",
"star": "\ue408",
"trash": "\ue401",
"phone-filled": "\ue230",
"compose": "\ue400",
"videocam": "\ue300",
"trash-filled": "\ue8dc",
"download": "\ue403",
"chatbubble-filled": "\ue232",
"chatbubble": "\ue202",
"cloud-download": "\ue8e4",
"cloud-upload-filled": "\ue8e5",
"cloud-upload": "\ue8e6",
"cloud-download-filled": "\ue8e9",
"headphones":"\ue8bf",
"shop":"\ue609"
"shop":"\ue609"
}

File diff suppressed because one or more lines are too long

View File

@@ -1,45 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keyup', listener)
})
},
render: () => {}
}
// #endif
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keyup', listener)
})
},
render: () => {}
}
// #endif

View File

@@ -1,263 +1,263 @@
<template>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{titleText}}</text>
</view>
<view v-if="mode === 'base'" class="uni-dialog-content">
<slot>
<text class="uni-dialog-content-text">{{content}}</text>
</slot>
</view>
<view v-else class="uni-dialog-content">
<slot>
<input class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholderText" :focus="focus" >
</slot>
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="closeDialog">
<text class="uni-dialog-button-text">{{cancelText}}</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">{{okText}}</text>
</view>
</view>
</view>
</template>
<script>
import popup from '../uni-popup/popup.js'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from '../uni-popup/i18n/index.js'
const { t } = initVueI18n(messages)
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式、
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
export default {
name: "uniPopupDialog",
mixins: [popup],
emits:['confirm','close'],
props: {
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: [String, Number],
default: ''
},
type: {
type: String,
default: 'error'
},
mode: {
type: String,
default: 'base'
},
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
beforeClose: {
type: Boolean,
default: false
}
},
data() {
return {
dialogType: 'error',
focus: false,
val: ""
}
},
computed: {
okText() {
return t("uni-popup.ok")
},
cancelText() {
return t("uni-popup.cancel")
},
placeholderText() {
return this.placeholder || t("uni-popup.placeholder")
},
titleText() {
return this.title || t("uni-popup.title")
}
},
watch: {
type(val) {
this.dialogType = val
},
mode(val) {
if (val === 'input') {
this.dialogType = 'info'
}
},
value(val) {
this.val = val
}
},
created() {
// 对话框遮罩不可点击
this.popup.disableMask()
// this.popup.closeMask()
if (this.mode === 'input') {
this.dialogType = 'info'
this.val = this.value
} else {
this.dialogType = this.type
}
},
mounted() {
this.focus = true
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
if (this.mode === 'input'){
this.$emit('confirm', this.val)
}else{
this.$emit('confirm')
}
if(this.beforeClose) return
this.popup.close()
},
/**
* 点击取消按钮
*/
closeDialog() {
this.$emit('close')
if(this.beforeClose) return
this.popup.close()
},
close(){
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
width: 300px;
border-radius: 15px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 15px;
padding-bottom: 5px;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px 15px 15px 15px;
}
.uni-dialog-content-text {
font-size: 14px;
color: #6e6e6e;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #f5f5f5;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 45px;
}
.uni-border-left {
border-left-color: #f0f0f0;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
font-size: 14px;
}
.uni-button-color {
color: #007aff;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
border: 1px #eee solid;
height: 40px;
padding: 0 10px;
border-radius: 5px;
color: #555;
}
.uni-popup__success {
color: #4cd964;
}
.uni-popup__warn {
color: #f0ad4e;
}
.uni-popup__error {
color: #dd524d;
}
.uni-popup__info {
color: #909399;
}
</style>
<template>
<view class="uni-popup-dialog">
<view class="uni-dialog-title">
<text class="uni-dialog-title-text" :class="['uni-popup__'+dialogType]">{{titleText}}</text>
</view>
<view v-if="mode === 'base'" class="uni-dialog-content">
<slot>
<text class="uni-dialog-content-text">{{content}}</text>
</slot>
</view>
<view v-else class="uni-dialog-content">
<slot>
<input class="uni-dialog-input" v-model="val" type="text" :placeholder="placeholderText" :focus="focus" >
</slot>
</view>
<view class="uni-dialog-button-group">
<view class="uni-dialog-button" @click="closeDialog">
<text class="uni-dialog-button-text">{{cancelText}}</text>
</view>
<view class="uni-dialog-button uni-border-left" @click="onOk">
<text class="uni-dialog-button-text uni-button-color">{{okText}}</text>
</view>
</view>
</view>
</template>
<script>
import popup from '../uni-popup/popup.js'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from '../uni-popup/i18n/index.js'
const { t } = initVueI18n(messages)
/**
* PopUp 弹出层-对话框样式
* @description 弹出层-对话框样式
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} value input 模式下的默认值
* @property {String} placeholder input 模式下输入提示
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} mode = [base|input] 模式、
* @value base 基础对话框
* @value input 可输入对话框
* @property {String} content 对话框内容
* @property {Boolean} beforeClose 是否拦截取消事件
* @event {Function} confirm 点击确认按钮触发
* @event {Function} close 点击取消按钮触发
*/
export default {
name: "uniPopupDialog",
mixins: [popup],
emits:['confirm','close'],
props: {
value: {
type: [String, Number],
default: ''
},
placeholder: {
type: [String, Number],
default: ''
},
type: {
type: String,
default: 'error'
},
mode: {
type: String,
default: 'base'
},
title: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
beforeClose: {
type: Boolean,
default: false
}
},
data() {
return {
dialogType: 'error',
focus: false,
val: ""
}
},
computed: {
okText() {
return t("uni-popup.ok")
},
cancelText() {
return t("uni-popup.cancel")
},
placeholderText() {
return this.placeholder || t("uni-popup.placeholder")
},
titleText() {
return this.title || t("uni-popup.title")
}
},
watch: {
type(val) {
this.dialogType = val
},
mode(val) {
if (val === 'input') {
this.dialogType = 'info'
}
},
value(val) {
this.val = val
}
},
created() {
// 对话框遮罩不可点击
this.popup.disableMask()
// this.popup.closeMask()
if (this.mode === 'input') {
this.dialogType = 'info'
this.val = this.value
} else {
this.dialogType = this.type
}
},
mounted() {
this.focus = true
},
methods: {
/**
* 点击确认按钮
*/
onOk() {
if (this.mode === 'input'){
this.$emit('confirm', this.val)
}else{
this.$emit('confirm')
}
if(this.beforeClose) return
this.popup.close()
},
/**
* 点击取消按钮
*/
closeDialog() {
this.$emit('close')
if(this.beforeClose) return
this.popup.close()
},
close(){
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-dialog {
width: 300px;
border-radius: 15px;
background-color: #fff;
}
.uni-dialog-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 15px;
padding-bottom: 5px;
}
.uni-dialog-title-text {
font-size: 16px;
font-weight: 500;
}
.uni-dialog-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
align-items: center;
padding: 5px 15px 15px 15px;
}
.uni-dialog-content-text {
font-size: 14px;
color: #6e6e6e;
}
.uni-dialog-button-group {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
border-top-color: #f5f5f5;
border-top-style: solid;
border-top-width: 1px;
}
.uni-dialog-button {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
justify-content: center;
align-items: center;
height: 45px;
}
.uni-border-left {
border-left-color: #f0f0f0;
border-left-style: solid;
border-left-width: 1px;
}
.uni-dialog-button-text {
font-size: 14px;
}
.uni-button-color {
color: #007aff;
}
.uni-dialog-input {
flex: 1;
font-size: 14px;
border: 1px #eee solid;
height: 40px;
padding: 0 10px;
border-radius: 5px;
color: #555;
}
.uni-popup__success {
color: #4cd964;
}
.uni-popup__warn {
color: #f0ad4e;
}
.uni-popup__error {
color: #dd524d;
}
.uni-popup__info {
color: #909399;
}
</style>

View File

@@ -1,143 +1,143 @@
<template>
<view class="uni-popup-message">
<template>
<view class="uni-popup-message">
<view class="uni-popup-message__box fixforpc-width" :class="'uni-popup__'+type">
<slot>
<text class="uni-popup-message-text" :class="'uni-popup__'+type+'-text'">{{message}}</text>
</slot>
</view>
</view>
</template>
</slot>
</view>
</view>
</template>
<script>
import popup from '../uni-popup/popup.js'
/**
* PopUp 弹出层-消息提示
* @description 弹出层-消息提示
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} message 消息提示文字
* @property {String} duration 显示时间,设置为 0 则不会自动关闭
import popup from '../uni-popup/popup.js'
/**
* PopUp 弹出层-消息提示
* @description 弹出层-消息提示
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [success|warning|info|error] 主题样式
* @value success 成功
* @value warning 提示
* @value info 消息
* @value error 错误
* @property {String} message 消息提示文字
* @property {String} duration 显示时间,设置为 0 则不会自动关闭
*/
export default {
export default {
name: 'uniPopupMessage',
mixins:[popup],
props: {
/**
* 主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'success'
},
/**
* 消息文字
*/
message: {
type: String,
default: ''
},
/**
* 显示时间,设置为 0 则不会自动关闭
*/
duration: {
type: Number,
default: 3000
mixins:[popup],
props: {
/**
* 主题 success/warning/info/error 默认 success
*/
type: {
type: String,
default: 'success'
},
/**
* 消息文字
*/
message: {
type: String,
default: ''
},
/**
* 显示时间,设置为 0 则不会自动关闭
*/
duration: {
type: Number,
default: 3000
},
maskShow:{
type:Boolean,
default:false
}
},
data() {
return {}
}
},
data() {
return {}
},
created() {
this.popup.maskShow = this.maskShow
this.popup.messageChild = this
},
methods: {
},
methods: {
timerClose(){
if(this.duration === 0) return
clearTimeout(this.timer)
this.timer = setTimeout(()=>{
this.popup.close()
},this.duration)
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-message {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
}
.uni-popup-message__box {
background-color: #e1f3d8;
padding: 10px 15px;
border-color: #eee;
border-style: solid;
border-width: 1px;
flex: 1;
}
@media screen and (min-width: 500px) {
.fixforpc-width {
margin-top: 20px;
border-radius: 4px;
flex: none;
min-width: 380px;
/* #ifndef APP-NVUE */
max-width: 50%;
/* #endif */
/* #ifdef APP-NVUE */
max-width: 500px;
/* #endif */
}
}
.uni-popup-message-text {
font-size: 14px;
padding: 0;
}
.uni-popup__success {
background-color: #e1f3d8;
}
.uni-popup__success-text {
color: #67C23A;
}
.uni-popup__warn {
background-color: #faecd8;
}
.uni-popup__warn-text {
color: #E6A23C;
}
.uni-popup__error {
background-color: #fde2e2;
}
.uni-popup__error-text {
color: #F56C6C;
}
.uni-popup__info {
background-color: #F2F6FC;
}
.uni-popup__info-text {
color: #909399;
}
</style>
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-message {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
}
.uni-popup-message__box {
background-color: #e1f3d8;
padding: 10px 15px;
border-color: #eee;
border-style: solid;
border-width: 1px;
flex: 1;
}
@media screen and (min-width: 500px) {
.fixforpc-width {
margin-top: 20px;
border-radius: 4px;
flex: none;
min-width: 380px;
/* #ifndef APP-NVUE */
max-width: 50%;
/* #endif */
/* #ifdef APP-NVUE */
max-width: 500px;
/* #endif */
}
}
.uni-popup-message-text {
font-size: 14px;
padding: 0;
}
.uni-popup__success {
background-color: #e1f3d8;
}
.uni-popup__success-text {
color: #67C23A;
}
.uni-popup__warn {
background-color: #faecd8;
}
.uni-popup__warn-text {
color: #E6A23C;
}
.uni-popup__error {
background-color: #fde2e2;
}
.uni-popup__error-text {
color: #F56C6C;
}
.uni-popup__info {
background-color: #F2F6FC;
}
.uni-popup__info-text {
color: #909399;
}
</style>

View File

@@ -1,185 +1,185 @@
<template>
<view class="uni-popup-share">
<view class="uni-share-title"><text class="uni-share-title-text">{{shareTitleText}}</text></view>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
<text class="uni-share-text">{{item.text}}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">{{cancelText}}</button>
</view>
</view>
</template>
<script>
import popup from '../uni-popup/popup.js'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from '../uni-popup/i18n/index.js'
const { t } = initVueI18n(messages)
export default {
name: 'UniPopupShare',
mixins:[popup],
emits:['select'],
props: {
title: {
type: String,
default: ''
},
beforeClose: {
type: Boolean,
default: false
}
},
data() {
return {
bottomData: [{
text: '微信',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/c2b17470-50be-11eb-b680-7980c8a877b8.png',
name: 'wx'
},
{
text: '支付宝',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png',
name: 'wx'
},
{
text: 'QQ',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png',
name: 'qq'
},
{
text: '新浪',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png',
name: 'sina'
},
{
text: '百度',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/1ec6e920-50bf-11eb-8a36-ebb87efcf8c0.png',
name: 'copy'
},
{
text: '其他',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/2e0fdfe0-50bf-11eb-b997-9918a5dda011.png',
name: 'more'
}
]
}
},
created() {},
computed: {
cancelText() {
return t("uni-popup.cancel")
},
shareTitleText() {
return this.title || t("uni-popup.shareTitle")
}
},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit('select', {
item,
index
})
this.close()
},
/**
* 关闭窗口
*/
close() {
if(this.beforeClose) return
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #fff;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3B4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>
<template>
<view class="uni-popup-share">
<view class="uni-share-title"><text class="uni-share-title-text">{{shareTitleText}}</text></view>
<view class="uni-share-content">
<view class="uni-share-content-box">
<view class="uni-share-content-item" v-for="(item,index) in bottomData" :key="index" @click.stop="select(item,index)">
<image class="uni-share-image" :src="item.icon" mode="aspectFill"></image>
<text class="uni-share-text">{{item.text}}</text>
</view>
</view>
</view>
<view class="uni-share-button-box">
<button class="uni-share-button" @click="close">{{cancelText}}</button>
</view>
</view>
</template>
<script>
import popup from '../uni-popup/popup.js'
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from '../uni-popup/i18n/index.js'
const { t } = initVueI18n(messages)
export default {
name: 'UniPopupShare',
mixins:[popup],
emits:['select'],
props: {
title: {
type: String,
default: ''
},
beforeClose: {
type: Boolean,
default: false
}
},
data() {
return {
bottomData: [{
text: '微信',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/c2b17470-50be-11eb-b680-7980c8a877b8.png',
name: 'wx'
},
{
text: '支付宝',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/d684ae40-50be-11eb-8ff1-d5dcf8779628.png',
name: 'wx'
},
{
text: 'QQ',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/e7a79520-50be-11eb-b997-9918a5dda011.png',
name: 'qq'
},
{
text: '新浪',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/0dacdbe0-50bf-11eb-8ff1-d5dcf8779628.png',
name: 'sina'
},
{
text: '百度',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/1ec6e920-50bf-11eb-8a36-ebb87efcf8c0.png',
name: 'copy'
},
{
text: '其他',
icon: 'https://vkceyugu.cdn.bspapp.com/VKCEYUGU-dc-site/2e0fdfe0-50bf-11eb-b997-9918a5dda011.png',
name: 'more'
}
]
}
},
created() {},
computed: {
cancelText() {
return t("uni-popup.cancel")
},
shareTitleText() {
return this.title || t("uni-popup.shareTitle")
}
},
methods: {
/**
* 选择内容
*/
select(item, index) {
this.$emit('select', {
item,
index
})
this.close()
},
/**
* 关闭窗口
*/
close() {
if(this.beforeClose) return
this.popup.close()
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup-share {
background-color: #fff;
}
.uni-share-title {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
justify-content: center;
height: 40px;
}
.uni-share-title-text {
font-size: 14px;
color: #666;
}
.uni-share-content {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: center;
padding-top: 10px;
}
.uni-share-content-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: wrap;
width: 360px;
}
.uni-share-content-item {
width: 90px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
padding: 10px 0;
align-items: center;
}
.uni-share-content-item:active {
background-color: #f5f5f5;
}
.uni-share-image {
width: 30px;
height: 30px;
}
.uni-share-text {
margin-top: 10px;
font-size: 14px;
color: #3B4144;
}
.uni-share-button-box {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
padding: 10px 15px;
}
.uni-share-button {
flex: 1;
border-radius: 50px;
color: #666;
font-size: 16px;
}
.uni-share-button::after {
border-radius: 50px;
}
</style>

View File

@@ -1,6 +1,6 @@
{
"uni-popup.cancel": "cancel",
"uni-popup.ok": "ok",
{
"uni-popup.cancel": "cancel",
"uni-popup.ok": "ok",
"uni-popup.placeholder": "pleace enter",
"uni-popup.title": "Hint",
"uni-popup.shareTitle": "Share to"

View File

@@ -1,8 +1,8 @@
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}

View File

@@ -1,7 +1,7 @@
{
"uni-popup.cancel": "取消",
{
"uni-popup.cancel": "取消",
"uni-popup.ok": "确定",
"uni-popup.placeholder": "请输入",
"uni-popup.title": "提示",
"uni-popup.shareTitle": "分享到"
"uni-popup.shareTitle": "分享到"
}

View File

@@ -1,7 +1,7 @@
{
"uni-popup.cancel": "取消",
{
"uni-popup.cancel": "取消",
"uni-popup.ok": "確定",
"uni-popup.placeholder": "請輸入",
"uni-popup.title": "提示",
"uni-popup.shareTitle": "分享到"
"uni-popup.shareTitle": "分享到"
}

View File

@@ -1,45 +1,45 @@
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
// this.$once('hook:beforeDestroy', () => {
// document.removeEventListener('keyup', listener)
// })
},
render: () => {}
}
// #endif
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
// this.$once('hook:beforeDestroy', () => {
// document.removeEventListener('keyup', listener)
// })
},
render: () => {}
}
// #endif

View File

@@ -1,9 +1,9 @@
export default {
data() {
return {
}
export default {
data() {
return {
}
},
created(){
this.popup = this.getParent()
@@ -22,5 +22,5 @@ export default {
}
return parent;
},
}
}
}
}

View File

@@ -1,240 +1,240 @@
<template>
<template>
<view v-if="showPopup" class="uni-popup" :class="[popupstyle, isDesktop ? 'fixforpc-z-index' : '']" @touchmove.stop.prevent="clear">
<view @touchstart="touchstart" >
<uni-transition key="1" v-if="maskShow" name="mask" mode-class="fade" :styles="maskClass" :duration="duration" :show="showTrans" @click="onTap" />
<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear"><slot /></view>
<uni-transition key="2" :mode-class="ani" name="content" :styles="transClass" :duration="duration" :show="showTrans" @click="onTap">
<view class="uni-popup__wrapper" :style="{ backgroundColor: bg }" :class="[popupstyle]" @click="clear"><slot /></view>
</uni-transition>
</view>
<!-- #ifdef H5 -->
<keypress v-if="maskShow" @esc="onTap" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif
/**
* PopUp 弹出层
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value left 左侧弹出
* @value right 右侧弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
</view>
<!-- #ifdef H5 -->
<keypress v-if="maskShow" @esc="onTap" />
<!-- #endif -->
</view>
</template>
<script>
// #ifdef H5
import keypress from './keypress.js'
// #endif
/**
* PopUp 弹出层
* @description 弹出层组件,为了解决遮罩弹层的问题
* @tutorial https://ext.dcloud.net.cn/plugin?id=329
* @property {String} type = [top|center|bottom|left|right|message|dialog|share] 弹出方式
* @value top 顶部弹出
* @value center 中间弹出
* @value bottom 底部弹出
* @value left 左侧弹出
* @value right 右侧弹出
* @value message 消息提示
* @value dialog 对话框
* @value share 底部分享示例
* @property {Boolean} animation = [ture|false] 是否开启动画
* @property {Boolean} maskClick = [ture|false] 蒙版点击是否关闭弹窗
* @property {String} backgroundColor 主窗口背景色
* @property {Boolean} safeArea 是否适配底部安全区
* @property {Boolean} safeArea 是否适配底部安全区
* @event {Function} change 打开关闭弹窗触发e={show: false}
* @event {Function} maskClick 点击遮罩触发
*/
export default {
name: 'uniPopup',
components: {
// #ifdef H5
keypress
// #endif
},
emits:['change','maskClick'],
props: {
// 开启动画
animation: {
type: Boolean,
default: true
},
// 弹出层类型可选值top: 顶部弹出层bottom底部弹出层center全屏弹出层
// message: 消息提示 ; dialog : 对话框
type: {
type: String,
default: 'center'
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: 'none'
* @event {Function} maskClick 点击遮罩触发
*/
export default {
name: 'uniPopup',
components: {
// #ifdef H5
keypress
// #endif
},
emits:['change','maskClick'],
props: {
// 开启动画
animation: {
type: Boolean,
default: true
},
// 弹出层类型可选值top: 顶部弹出层bottom底部弹出层center全屏弹出层
// message: 消息提示 ; dialog : 对话框
type: {
type: String,
default: 'center'
},
// maskClick
maskClick: {
type: Boolean,
default: true
},
backgroundColor: {
type: String,
default: 'none'
},
safeArea:{
type: Boolean,
default: true
}
},
watch: {
/**
* 监听type类型
*/
type: {
handler: function(type) {
if (!this.config[type]) return
this[this.config[type]](true)
},
immediate: true
},
isDesktop: {
handler: function(newVal) {
if (!this.config[newVal]) return
this[this.config[this.type]](true)
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick: {
handler: function(val) {
this.mkclick = val
},
immediate: true
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
popupWidth: 0,
popupHeight: 0,
config: {
top: 'top',
bottom: 'bottom',
center: 'center',
left: 'left',
right: 'right',
message: 'top',
dialog: 'center',
share: 'bottom'
},
maskClass: {
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)'
},
transClass: {
position: 'fixed',
left: 0,
right: 0
},
maskShow: true,
mkclick: true,
popupstyle: this.isDesktop ? 'fixforpc-top' : 'top'
}
},
computed: {
isDesktop() {
return this.popupWidth >= 500 && this.popupHeight >= 500
},
bg() {
if (this.backgroundColor === '' || this.backgroundColor === 'none') {
return 'transparent'
}
return this.backgroundColor
}
},
mounted() {
const fixSize = () => {
const { windowWidth, windowHeight, windowTop, safeAreaInsets } = uni.getSystemInfoSync()
this.popupWidth = windowWidth
},
watch: {
/**
* 监听type类型
*/
type: {
handler: function(type) {
if (!this.config[type]) return
this[this.config[type]](true)
},
immediate: true
},
isDesktop: {
handler: function(newVal) {
if (!this.config[newVal]) return
this[this.config[this.type]](true)
},
immediate: true
},
/**
* 监听遮罩是否可点击
* @param {Object} val
*/
maskClick: {
handler: function(val) {
this.mkclick = val
},
immediate: true
}
},
data() {
return {
duration: 300,
ani: [],
showPopup: false,
showTrans: false,
popupWidth: 0,
popupHeight: 0,
config: {
top: 'top',
bottom: 'bottom',
center: 'center',
left: 'left',
right: 'right',
message: 'top',
dialog: 'center',
share: 'bottom'
},
maskClass: {
position: 'fixed',
bottom: 0,
top: 0,
left: 0,
right: 0,
backgroundColor: 'rgba(0, 0, 0, 0.4)'
},
transClass: {
position: 'fixed',
left: 0,
right: 0
},
maskShow: true,
mkclick: true,
popupstyle: this.isDesktop ? 'fixforpc-top' : 'top'
}
},
computed: {
isDesktop() {
return this.popupWidth >= 500 && this.popupHeight >= 500
},
bg() {
if (this.backgroundColor === '' || this.backgroundColor === 'none') {
return 'transparent'
}
return this.backgroundColor
}
},
mounted() {
const fixSize = () => {
const { windowWidth, windowHeight, windowTop, safeAreaInsets } = uni.getSystemInfoSync()
this.popupWidth = windowWidth
this.popupHeight = windowHeight + windowTop
// 是否适配底部安全区
if(this.safeArea){
this.safeAreaInsets = safeAreaInsets
}else{
this.safeAreaInsets = 0
}
}
fixSize()
// #ifdef H5
// window.addEventListener('resize', fixSize)
// this.$once('hook:beforeDestroy', () => {
// window.removeEventListener('resize', fixSize)
// })
// #endif
},
created() {
this.mkclick = this.maskClick
if (this.animation) {
this.duration = 300
} else {
this.duration = 0
}
// TODO 处理 message 组件生命周期异常的问题
}
}
fixSize()
// #ifdef H5
// window.addEventListener('resize', fixSize)
// this.$once('hook:beforeDestroy', () => {
// window.removeEventListener('resize', fixSize)
// })
// #endif
},
created() {
this.mkclick = this.maskClick
if (this.animation) {
this.duration = 300
} else {
this.duration = 0
}
// TODO 处理 message 组件生命周期异常的问题
this.messageChild = null
// TODO 解决头条冒泡的问题
this.clearPropagation = false
},
methods: {
/**
* 公用方法,不显示遮罩层
*/
closeMask() {
this.maskShow = false
this.clearPropagation = false
},
methods: {
/**
* 公用方法,不显示遮罩层
*/
closeMask() {
this.maskShow = false
},
/**
* 公用方法,遮罩层禁止点击
*/
disableMask() {
this.mkclick = false
*/
disableMask() {
this.mkclick = false
},
// TODO nvue 取消冒泡
// TODO nvue 取消冒泡
clear(e) {
// #ifndef APP-NVUE
e.stopPropagation()
// #endif
this.clearPropagation = true
},
open(direction) {
let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
if (!(direction && innerType.indexOf(direction) !== -1)) {
direction = this.type
}
if (!this.config[direction]) {
console.error('缺少类型:', direction)
return
}
this[this.config[direction]]()
this.$emit('change', {
show: true,
type: direction
})
},
close(type) {
this.showTrans = false
this.$emit('change', {
show: false,
type: this.type
})
clearTimeout(this.timer)
// // 自定义关闭事件
// this.customOpen && this.customClose()
this.timer = setTimeout(() => {
this.showPopup = false
}, 300)
open(direction) {
let innerType = ['top', 'center', 'bottom', 'left', 'right', 'message', 'dialog', 'share']
if (!(direction && innerType.indexOf(direction) !== -1)) {
direction = this.type
}
if (!this.config[direction]) {
console.error('缺少类型:', direction)
return
}
this[this.config[direction]]()
this.$emit('change', {
show: true,
type: direction
})
},
close(type) {
this.showTrans = false
this.$emit('change', {
show: false,
type: this.type
})
clearTimeout(this.timer)
// // 自定义关闭事件
// this.customOpen && this.customClose()
this.timer = setTimeout(() => {
this.showPopup = false
}, 300)
},
// TODO 处理冒泡事件,头条的冒泡事件有问题 ,先这样兼容
touchstart(){
this.clearPropagation = false
},
onTap() {
if (this.clearPropagation) {
// fix by mehaotian 兼容 nvue
@@ -242,162 +242,162 @@ export default {
return
}
this.$emit('maskClick')
if (!this.mkclick) return
this.close()
},
/**
* 顶部弹出样式处理
*/
top(type) {
this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
this.ani = ['slide-top']
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
backgroundColor: this.bg
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.$nextTick(() => {
if (this.messageChild && this.type === 'message') {
this.messageChild.timerClose()
}
})
},
/**
* 底部弹出样式处理
*/
bottom(type) {
this.popupstyle = 'bottom'
this.ani = ['slide-bottom']
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
bottom: 0,
paddingBottom: (this.safeAreaInsets && this.safeAreaInsets.bottom) || 0,
backgroundColor: this.bg
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
/**
* 中间弹出样式处理
*/
center(type) {
this.popupstyle = 'center'
this.ani = ['zoom-out', 'fade']
this.transClass = {
position: 'fixed',
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column',
/* #endif */
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center'
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
left(type) {
this.popupstyle = 'left'
this.ani = ['slide-left']
this.transClass = {
position: 'fixed',
left: 0,
bottom: 0,
top: 0,
backgroundColor: this.bg,
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
/* #endif */
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
right(type) {
this.popupstyle = 'right'
this.ani = ['slide-right']
this.transClass = {
position: 'fixed',
bottom: 0,
right: 0,
top: 0,
backgroundColor: this.bg,
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
/* #endif */
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
&.top,
&.left,
&.right {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
// padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
/* #endif */
&.left,
&.right {
/* #ifdef H5 */
padding-top: var(--window-top);
/* #endif */
/* #ifndef H5 */
padding-top: 0;
/* #endif */
flex: 1;
}
}
}
.fixforpc-z-index {
/* #ifndef APP-NVUE */
z-index: 999;
/* #endif */
}
.fixforpc-top {
top: 0;
}
if (!this.mkclick) return
this.close()
},
/**
* 顶部弹出样式处理
*/
top(type) {
this.popupstyle = this.isDesktop ? 'fixforpc-top' : 'top'
this.ani = ['slide-top']
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
backgroundColor: this.bg
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
this.$nextTick(() => {
if (this.messageChild && this.type === 'message') {
this.messageChild.timerClose()
}
})
},
/**
* 底部弹出样式处理
*/
bottom(type) {
this.popupstyle = 'bottom'
this.ani = ['slide-bottom']
this.transClass = {
position: 'fixed',
left: 0,
right: 0,
bottom: 0,
paddingBottom: (this.safeAreaInsets && this.safeAreaInsets.bottom) || 0,
backgroundColor: this.bg
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
/**
* 中间弹出样式处理
*/
center(type) {
this.popupstyle = 'center'
this.ani = ['zoom-out', 'fade']
this.transClass = {
position: 'fixed',
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column',
/* #endif */
bottom: 0,
left: 0,
right: 0,
top: 0,
justifyContent: 'center',
alignItems: 'center'
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
left(type) {
this.popupstyle = 'left'
this.ani = ['slide-left']
this.transClass = {
position: 'fixed',
left: 0,
bottom: 0,
top: 0,
backgroundColor: this.bg,
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
/* #endif */
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
},
right(type) {
this.popupstyle = 'right'
this.ani = ['slide-right']
this.transClass = {
position: 'fixed',
bottom: 0,
right: 0,
top: 0,
backgroundColor: this.bg,
/* #ifndef APP-NVUE */
display: 'flex',
flexDirection: 'column'
/* #endif */
}
// TODO 兼容 type 属性 ,后续会废弃
if (type) return
this.showPopup = true
this.showTrans = true
}
}
}
</script>
<style lang="scss" scoped>
.uni-popup {
position: fixed;
/* #ifndef APP-NVUE */
z-index: 99;
/* #endif */
&.top,
&.left,
&.right {
/* #ifdef H5 */
top: var(--window-top);
/* #endif */
/* #ifndef H5 */
top: 0;
/* #endif */
}
.uni-popup__wrapper {
/* #ifndef APP-NVUE */
display: block;
/* #endif */
position: relative;
/* iphonex 等安全区设置,底部安全区适配 */
/* #ifndef APP-NVUE */
// padding-bottom: constant(safe-area-inset-bottom);
// padding-bottom: env(safe-area-inset-bottom);
/* #endif */
&.left,
&.right {
/* #ifdef H5 */
padding-top: var(--window-top);
/* #endif */
/* #ifndef H5 */
padding-top: 0;
/* #endif */
flex: 1;
}
}
}
.fixforpc-z-index {
/* #ifndef APP-NVUE */
z-index: 999;
/* #endif */
}
.fixforpc-top {
top: 0;
}
</style>

View File

@@ -1,13 +1,13 @@
## 1.2.02021-07-30
- 组件兼容 vue3如何创建vue3项目详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.12021-05-12
- 新增 示例地址
- 修复 示例项目缺少组件的Bug
## 1.1.02021-04-22
- 新增 通过方法自定义动画
- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式
- 优化 动画触发逻辑,使动画更流畅
- 优化 支持单独的动画类型
- 优化 文档示例
## 1.0.22021-02-05
- 调整为uni_modules目录规范
## 1.1.12021-05-12
- 新增 示例地址
- 修复 示例项目缺少组件的Bug
## 1.1.02021-04-22
- 新增 通过方法自定义动画
- 新增 custom-class 非 NVUE 平台支持自定义 class 定制样式
- 优化 动画触发逻辑,使动画更流畅
- 优化 支持单独的动画类型
- 优化 文档示例
## 1.0.22021-02-05
- 调整为uni_modules目录规范

View File

@@ -1,128 +1,128 @@
// const defaultOption = {
// duration: 300,
// timingFunction: 'linear',
// delay: 0,
// transformOrigin: '50% 50% 0'
// }
// #ifdef APP-NVUE
const nvueAnimation = uni.requireNativePlugin('animation')
// #endif
class MPAnimation {
constructor(options, _this) {
this.options = options
this.animation = uni.createAnimation(options)
this.currentStepAnimates = {}
this.next = 0
this.$ = _this
}
_nvuePushAnimates(type, args) {
let aniObj = this.currentStepAnimates[this.next]
let styles = {}
if (!aniObj) {
styles = {
styles: {},
config: {}
}
} else {
styles = aniObj
}
if (animateTypes1.includes(type)) {
if (!styles.styles.transform) {
styles.styles.transform = ''
// const defaultOption = {
// duration: 300,
// timingFunction: 'linear',
// delay: 0,
// transformOrigin: '50% 50% 0'
// }
// #ifdef APP-NVUE
const nvueAnimation = uni.requireNativePlugin('animation')
// #endif
class MPAnimation {
constructor(options, _this) {
this.options = options
this.animation = uni.createAnimation(options)
this.currentStepAnimates = {}
this.next = 0
this.$ = _this
}
_nvuePushAnimates(type, args) {
let aniObj = this.currentStepAnimates[this.next]
let styles = {}
if (!aniObj) {
styles = {
styles: {},
config: {}
}
} else {
styles = aniObj
}
if (animateTypes1.includes(type)) {
if (!styles.styles.transform) {
styles.styles.transform = ''
}
let unit = ''
if(type === 'rotate'){
unit = 'deg'
}
styles.styles.transform += `${type}(${args+unit}) `
} else {
styles.styles[type] = `${args}`
}
this.currentStepAnimates[this.next] = styles
}
_animateRun(styles = {}, config = {}) {
let ref = this.$.$refs['ani'].ref
if (!ref) return
}
styles.styles.transform += `${type}(${args+unit}) `
} else {
styles.styles[type] = `${args}`
}
this.currentStepAnimates[this.next] = styles
}
_animateRun(styles = {}, config = {}) {
let ref = this.$.$refs['ani'].ref
if (!ref) return
return new Promise((resolve, reject) => {
nvueAnimation.transition(ref, {
styles,
...config
}, res => {
resolve()
})
})
}
_nvueNextAnimate(animates, step = 0, fn) {
let obj = animates[step]
if (obj) {
let {
styles,
config
} = obj
this._animateRun(styles, config).then(() => {
step += 1
this._nvueNextAnimate(animates, step, fn)
})
} else {
this.currentStepAnimates = {}
typeof fn === 'function' && fn()
this.isEnd = true
}
}
nvueAnimation.transition(ref, {
styles,
...config
}, res => {
resolve()
})
})
}
_nvueNextAnimate(animates, step = 0, fn) {
let obj = animates[step]
if (obj) {
let {
styles,
config
} = obj
this._animateRun(styles, config).then(() => {
step += 1
this._nvueNextAnimate(animates, step, fn)
})
} else {
this.currentStepAnimates = {}
typeof fn === 'function' && fn()
this.isEnd = true
}
}
step(config = {}) {
// #ifndef APP-NVUE
this.animation.step(config)
// #endif
// #ifdef APP-NVUE
this.animation.step(config)
// #endif
// #ifdef APP-NVUE
this.currentStepAnimates[this.next].config = Object.assign({}, this.options, config)
this.currentStepAnimates[this.next].styles.transformOrigin = this.currentStepAnimates[this.next].config.transformOrigin
this.next++
// #endif
return this
}
run(fn) {
this.next++
// #endif
return this
}
run(fn) {
// #ifndef APP-NVUE
this.$.animationData = this.animation.export()
this.$.animationData = this.animation.export()
this.$.timer = setTimeout(() => {
typeof fn === 'function' && fn()
}, this.$.durationTime)
// #endif
// #ifdef APP-NVUE
typeof fn === 'function' && fn()
}, this.$.durationTime)
// #endif
// #ifdef APP-NVUE
this.isEnd = false
let ref = this.$.$refs['ani'] && this.$.$refs['ani'].ref
if(!ref) return
this._nvueNextAnimate(this.currentStepAnimates, 0, fn)
this.next = 0
// #endif
}
}
const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
'translateZ'
]
const animateTypes2 = ['opacity', 'backgroundColor']
const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom']
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
MPAnimation.prototype[type] = function(...args) {
if(!ref) return
this._nvueNextAnimate(this.currentStepAnimates, 0, fn)
this.next = 0
// #endif
}
}
const animateTypes1 = ['matrix', 'matrix3d', 'rotate', 'rotate3d', 'rotateX', 'rotateY', 'rotateZ', 'scale', 'scale3d',
'scaleX', 'scaleY', 'scaleZ', 'skew', 'skewX', 'skewY', 'translate', 'translate3d', 'translateX', 'translateY',
'translateZ'
]
const animateTypes2 = ['opacity', 'backgroundColor']
const animateTypes3 = ['width', 'height', 'left', 'right', 'top', 'bottom']
animateTypes1.concat(animateTypes2, animateTypes3).forEach(type => {
MPAnimation.prototype[type] = function(...args) {
// #ifndef APP-NVUE
this.animation[type](...args)
// #endif
// #ifdef APP-NVUE
this._nvuePushAnimates(type, args)
// #endif
return this
}
})
// #endif
// #ifdef APP-NVUE
this._nvuePushAnimates(type, args)
// #endif
return this
}
})
export function createAnimation(option, _this) {
if(!_this) return
clearTimeout(_this.timer)
return new MPAnimation(option, _this)
if(!_this) return
clearTimeout(_this.timer)
return new MPAnimation(option, _this)
}

View File

@@ -1,277 +1,277 @@
<template>
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
</template>
<script>
import { createAnimation } from './createAnimation'
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array|String} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
*/
export default {
name: 'uniTransition',
emits:['click','change'],
props: {
show: {
type: Boolean,
default: false
},
modeClass: {
type: [Array, String],
default() {
return 'fade'
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default() {
return {}
}
<template>
<view v-if="isShow" ref="ani" :animation="animationData" :class="customClass" :style="transformStyles" @click="onClick"><slot></slot></view>
</template>
<script>
import { createAnimation } from './createAnimation'
/**
* Transition 过渡动画
* @description 简单过渡动画组件
* @tutorial https://ext.dcloud.net.cn/plugin?id=985
* @property {Boolean} show = [false|true] 控制组件显示或隐藏
* @property {Array|String} modeClass = [fade|slide-top|slide-right|slide-bottom|slide-left|zoom-in|zoom-out] 过渡动画类型
* @value fade 渐隐渐出过渡
* @value slide-top 由上至下过渡
* @value slide-right 由右至左过渡
* @value slide-bottom 由下至上过渡
* @value slide-left 由左至右过渡
* @value zoom-in 由小到大过渡
* @value zoom-out 由大到小过渡
* @property {Number} duration 过渡动画持续时间
* @property {Object} styles 组件样式,同 css 样式,注意带’-‘连接符的属性需要使用小驼峰写法如:`backgroundColor:red`
*/
export default {
name: 'uniTransition',
emits:['click','change'],
props: {
show: {
type: Boolean,
default: false
},
modeClass: {
type: [Array, String],
default() {
return 'fade'
}
},
duration: {
type: Number,
default: 300
},
styles: {
type: Object,
default() {
return {}
}
},
customClass:{
type: String,
default: ''
}
},
data() {
return {
isShow: false,
transform: '',
opacity: 1,
animationData: {},
durationTime: 300,
config: {}
}
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open()
} else {
// 避免上来就执行 close,导致动画错乱
if (this.isShow) {
this.close()
}
}
},
immediate: true
}
},
computed: {
// 生成样式数据
stylesObject() {
let styles = {
...this.styles,
'transition-duration': this.duration / 1000 + 's'
}
let transform = ''
for (let i in styles) {
let line = this.toLine(i)
transform += line + ':' + styles[i] + ';'
}
return transform
},
// 初始化动画条件
transformStyles() {
return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject
}
},
created() {
// 动画默认配置
this.config = {
duration: this.duration,
timingFunction: 'ease',
transformOrigin: '50% 50%',
delay: 0
}
this.durationTime = this.duration
},
methods: {
/**
* ref 触发 初始化动画
*/
init(obj = {}) {
if (obj.duration) {
this.durationTime = obj.duration
}
this.animation = createAnimation(Object.assign(this.config, obj))
},
/**
* 点击组件触发回调
*/
onClick() {
this.$emit('click', {
detail: this.isShow
})
},
/**
* ref 触发 动画分组
* @param {Object} obj
*/
step(obj, config = {}) {
}
},
data() {
return {
isShow: false,
transform: '',
opacity: 1,
animationData: {},
durationTime: 300,
config: {}
}
},
watch: {
show: {
handler(newVal) {
if (newVal) {
this.open()
} else {
// 避免上来就执行 close,导致动画错乱
if (this.isShow) {
this.close()
}
}
},
immediate: true
}
},
computed: {
// 生成样式数据
stylesObject() {
let styles = {
...this.styles,
'transition-duration': this.duration / 1000 + 's'
}
let transform = ''
for (let i in styles) {
let line = this.toLine(i)
transform += line + ':' + styles[i] + ';'
}
return transform
},
// 初始化动画条件
transformStyles() {
return 'transform:' + this.transform + ';' + 'opacity:' + this.opacity + ';' + this.stylesObject
}
},
created() {
// 动画默认配置
this.config = {
duration: this.duration,
timingFunction: 'ease',
transformOrigin: '50% 50%',
delay: 0
}
this.durationTime = this.duration
},
methods: {
/**
* ref 触发 初始化动画
*/
init(obj = {}) {
if (obj.duration) {
this.durationTime = obj.duration
}
this.animation = createAnimation(Object.assign(this.config, obj))
},
/**
* 点击组件触发回调
*/
onClick() {
this.$emit('click', {
detail: this.isShow
})
},
/**
* ref 触发 动画分组
* @param {Object} obj
*/
step(obj, config = {}) {
if (!this.animation) return
for (let i in obj) {
for (let i in obj) {
try {
if(typeof obj[i] === 'object'){
this.animation[i](...obj[i])
}else{
this.animation[i](obj[i])
}
} catch (e) {
console.error(`方法 ${i} 不存在`)
}
}
}
} catch (e) {
console.error(`方法 ${i} 不存在`)
}
}
this.animation.step(config)
return this
},
/**
* ref 触发 执行动画
*/
run(fn) {
if (!this.animation) return
this.animation.run(fn)
},
// 开始过度动画
open() {
clearTimeout(this.timer)
this.transform = ''
this.isShow = true
let { opacity, transform } = this.styleInit(false)
if (typeof opacity !== 'undefined') {
this.opacity = opacity
}
this.transform = transform
// 确保动态样式已经生效后,执行动画,如果不加 nextTick ,会导致 wx 动画执行异常
this.$nextTick(() => {
// TODO 定时器保证动画完全执行,目前有些问题,后面会取消定时器
this.timer = setTimeout(() => {
this.animation = createAnimation(this.config, this)
this.tranfromInit(false).step()
this.animation.run()
this.$emit('change', {
detail: this.isShow
})
}, 20)
})
},
// 关闭过度动画
close(type) {
if (!this.animation) return
this.tranfromInit(true)
.step()
.run(() => {
this.isShow = false
this.animationData = null
this.animation = null
let { opacity, transform } = this.styleInit(false)
this.opacity = opacity || 1
this.transform = transform
this.$emit('change', {
detail: this.isShow
})
})
},
// 处理动画开始前的默认样式
styleInit(type) {
let styles = {
transform: ''
}
let buildStyle = (type, mode) => {
if (mode === 'fade') {
styles.opacity = this.animationType(type)[mode]
} else {
styles.transform += this.animationType(type)[mode] + ' '
}
}
if (typeof this.modeClass === 'string') {
buildStyle(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildStyle(type, mode)
})
}
return styles
},
// 处理内置组合动画
tranfromInit(type) {
let buildTranfrom = (type, mode) => {
let aniNum = null
if (mode === 'fade') {
aniNum = type ? 0 : 1
} else {
aniNum = type ? '-100%' : '0'
if (mode === 'zoom-in') {
aniNum = type ? 0.8 : 1
}
if (mode === 'zoom-out') {
aniNum = type ? 1.2 : 1
}
if (mode === 'slide-right') {
aniNum = type ? '100%' : '0'
}
if (mode === 'slide-bottom') {
aniNum = type ? '100%' : '0'
}
}
this.animation[this.animationMode()[mode]](aniNum)
}
if (typeof this.modeClass === 'string') {
buildTranfrom(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildTranfrom(type, mode)
})
}
return this.animation
},
animationType(type) {
return {
fade: type ? 1 : 0,
'slide-top': `translateY(${type ? '0' : '-100%'})`,
'slide-right': `translateX(${type ? '0' : '100%'})`,
'slide-bottom': `translateY(${type ? '0' : '100%'})`,
'slide-left': `translateX(${type ? '0' : '-100%'})`,
'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
}
},
// 内置动画类型与实际动画对应字典
animationMode() {
return {
fade: 'opacity',
'slide-top': 'translateY',
'slide-right': 'translateX',
'slide-bottom': 'translateY',
'slide-left': 'translateX',
'zoom-in': 'scale',
'zoom-out': 'scale'
}
},
// 驼峰转中横线
toLine(name) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
}
}
}
</script>
return this
},
/**
* ref 触发 执行动画
*/
run(fn) {
if (!this.animation) return
this.animation.run(fn)
},
// 开始过度动画
open() {
clearTimeout(this.timer)
this.transform = ''
this.isShow = true
let { opacity, transform } = this.styleInit(false)
if (typeof opacity !== 'undefined') {
this.opacity = opacity
}
this.transform = transform
// 确保动态样式已经生效后,执行动画,如果不加 nextTick ,会导致 wx 动画执行异常
this.$nextTick(() => {
// TODO 定时器保证动画完全执行,目前有些问题,后面会取消定时器
this.timer = setTimeout(() => {
this.animation = createAnimation(this.config, this)
this.tranfromInit(false).step()
this.animation.run()
this.$emit('change', {
detail: this.isShow
})
}, 20)
})
},
// 关闭过度动画
close(type) {
if (!this.animation) return
this.tranfromInit(true)
.step()
.run(() => {
this.isShow = false
this.animationData = null
this.animation = null
let { opacity, transform } = this.styleInit(false)
this.opacity = opacity || 1
this.transform = transform
this.$emit('change', {
detail: this.isShow
})
})
},
// 处理动画开始前的默认样式
styleInit(type) {
let styles = {
transform: ''
}
let buildStyle = (type, mode) => {
if (mode === 'fade') {
styles.opacity = this.animationType(type)[mode]
} else {
styles.transform += this.animationType(type)[mode] + ' '
}
}
if (typeof this.modeClass === 'string') {
buildStyle(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildStyle(type, mode)
})
}
return styles
},
// 处理内置组合动画
tranfromInit(type) {
let buildTranfrom = (type, mode) => {
let aniNum = null
if (mode === 'fade') {
aniNum = type ? 0 : 1
} else {
aniNum = type ? '-100%' : '0'
if (mode === 'zoom-in') {
aniNum = type ? 0.8 : 1
}
if (mode === 'zoom-out') {
aniNum = type ? 1.2 : 1
}
if (mode === 'slide-right') {
aniNum = type ? '100%' : '0'
}
if (mode === 'slide-bottom') {
aniNum = type ? '100%' : '0'
}
}
this.animation[this.animationMode()[mode]](aniNum)
}
if (typeof this.modeClass === 'string') {
buildTranfrom(type, this.modeClass)
} else {
this.modeClass.forEach(mode => {
buildTranfrom(type, mode)
})
}
return this.animation
},
animationType(type) {
return {
fade: type ? 1 : 0,
'slide-top': `translateY(${type ? '0' : '-100%'})`,
'slide-right': `translateX(${type ? '0' : '100%'})`,
'slide-bottom': `translateY(${type ? '0' : '100%'})`,
'slide-left': `translateX(${type ? '0' : '-100%'})`,
'zoom-in': `scaleX(${type ? 1 : 0.8}) scaleY(${type ? 1 : 0.8})`,
'zoom-out': `scaleX(${type ? 1 : 1.2}) scaleY(${type ? 1 : 1.2})`
}
},
// 内置动画类型与实际动画对应字典
animationMode() {
return {
fade: 'opacity',
'slide-top': 'translateY',
'slide-right': 'translateX',
'slide-bottom': 'translateY',
'slide-left': 'translateX',
'zoom-in': 'scale',
'zoom-out': 'scale'
}
},
// 驼峰转中横线
toLine(name) {
return name.replace(/([A-Z])/g, '-$1').toLowerCase()
}
}
}
</script>
<style></style>

View File

@@ -1,83 +1,83 @@
{
"id": "uni-transition",
"displayName": "uni-transition 过渡动画",
"version": "1.2.0",
"description": "元素的简单过渡动画",
"keywords": [
"uni-ui",
"uniui",
"动画",
"过渡",
"过渡动画"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
{
"id": "uni-transition",
"displayName": "uni-transition 过渡动画",
"version": "1.2.0",
"description": "元素的简单过渡动画",
"keywords": [
"uni-ui",
"uniui",
"动画",
"过渡",
"过渡动画"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}