初始化项目
This commit is contained in:
86
App.vue
Normal file
86
App.vue
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
onLaunch: function() {
|
||||||
|
console.log('App Launch')
|
||||||
|
},
|
||||||
|
onShow: function() {
|
||||||
|
console.log('App Show')
|
||||||
|
},
|
||||||
|
onHide: function() {
|
||||||
|
console.log('App Hide')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
/* 水平居中 */
|
||||||
|
.pack-center {
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 下拉刷新 */
|
||||||
|
.refresh{
|
||||||
|
height: 90rpx;
|
||||||
|
line-height: 90rpx;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.refresh-icon{
|
||||||
|
width: 32rpx;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-bottom: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 页面信息提醒 */
|
||||||
|
.pages-hint,
|
||||||
|
.pages-loding{
|
||||||
|
text-align: center;
|
||||||
|
color: #747788;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pages-hint image {
|
||||||
|
width: 188rpx;
|
||||||
|
height: 188rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pages-loding image {
|
||||||
|
width: 38rpx;
|
||||||
|
height: 38rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 上拉加载 */
|
||||||
|
.pagesLoding {
|
||||||
|
text-align: center;
|
||||||
|
color: gray;
|
||||||
|
line-height: 90rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagesLodingIcon {
|
||||||
|
width: 32rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin-right: 10rpx;
|
||||||
|
margin-bottom: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nowrap-multi {
|
||||||
|
display: -webkit-box;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
158
apis/index.js
Normal file
158
apis/index.js
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
*/
|
||||||
|
|
||||||
|
import store from '@/store'
|
||||||
|
|
||||||
|
// 基础配置
|
||||||
|
const config = {
|
||||||
|
apiUrl : 'http://api.gout.shangkelian.cn/api/', // 正式环境
|
||||||
|
timeout : 60000
|
||||||
|
}
|
||||||
|
|
||||||
|
let loginHintState = false
|
||||||
|
|
||||||
|
// 网络请求
|
||||||
|
const request = (parameter, hideLoding) => {
|
||||||
|
// 检查url配置
|
||||||
|
if(parameter.url === 'undefined' || parameter.url === ''){
|
||||||
|
uni.showToast({
|
||||||
|
title: '请求地址不能为空',
|
||||||
|
icon : 'none'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 注入header
|
||||||
|
config.header = {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': store.getters.getToken || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载提示
|
||||||
|
if(!hideLoding) uni.showLoading({
|
||||||
|
title: '加载中',
|
||||||
|
mask : true
|
||||||
|
});
|
||||||
|
|
||||||
|
// 请求实例
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.request({
|
||||||
|
url : config.apiUrl + parameter.url,
|
||||||
|
timeout : config.timeout,
|
||||||
|
header : config.header || {},
|
||||||
|
data : parameter.data || {},
|
||||||
|
method : parameter.method || 'GET',
|
||||||
|
success : res => {
|
||||||
|
if (res.header.Authorization){
|
||||||
|
updateToken('token', res.header.Authorization)
|
||||||
|
}
|
||||||
|
if(res.statusCode === 200){
|
||||||
|
uni.hideLoading()
|
||||||
|
const resolveData = res.data
|
||||||
|
if(resolveData.status_code === 200) {
|
||||||
|
resolve(resolveData.data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if(resolveData.status_code === 401) {
|
||||||
|
loginHint()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reject(resolveData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errToast(res.statusCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件上传
|
||||||
|
const uploading = (paths) => {
|
||||||
|
uni.showLoading({
|
||||||
|
title: '上传中',
|
||||||
|
mask : true
|
||||||
|
});
|
||||||
|
// 注入header
|
||||||
|
config.header = {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Authorization': store.getters.getToken || ''
|
||||||
|
}
|
||||||
|
// 上传图片
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
uni.uploadFile({
|
||||||
|
url : config.apiUrl + 'storage/uploads',
|
||||||
|
files : paths,
|
||||||
|
header : config.header || {},
|
||||||
|
success : res=>{
|
||||||
|
if(res.statusCode === 200){
|
||||||
|
uni.hideLoading()
|
||||||
|
let updData = JSON.parse(res.data)
|
||||||
|
if(updData.status_code === 200){
|
||||||
|
resolve(updData.data)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
reject(updData)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
errToast(res.statusCode)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理一些http请求错误提示
|
||||||
|
const errToast = (code) => {
|
||||||
|
switch (code){
|
||||||
|
case 404:
|
||||||
|
uni.showToast({
|
||||||
|
title: code + '接口不存在,请联系系统管理员',
|
||||||
|
icon : 'none'
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 405:
|
||||||
|
uni.showToast({
|
||||||
|
title: code + '请检查接口请求方式错误',
|
||||||
|
icon : 'none'
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
case 500:
|
||||||
|
uni.showToast({
|
||||||
|
title: code + '服务端错误,请检查服务器信息',
|
||||||
|
icon : 'none'
|
||||||
|
})
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新token
|
||||||
|
const updateToken = (token) => {
|
||||||
|
store.commit('setToken', token)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理登录提示
|
||||||
|
const loginHint = () => {
|
||||||
|
if( loginHintState ) return
|
||||||
|
if(!loginHintState) loginHintState = true
|
||||||
|
updateToken('')
|
||||||
|
uni.showModal({
|
||||||
|
title: '登录提示',
|
||||||
|
content: '您的登录信息已过期,请重新登录',
|
||||||
|
confirmColor: '#8b64fd',
|
||||||
|
showCancel:false,
|
||||||
|
success: res=> {
|
||||||
|
loginHintState = false
|
||||||
|
if (res.confirm) uni.reLaunch({
|
||||||
|
url: '/pages/index/index'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
request,
|
||||||
|
uploading,
|
||||||
|
config
|
||||||
|
}
|
||||||
31
apis/interfaces/auth.js
Normal file
31
apis/interfaces/auth.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
* moduleName: 鉴权
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { request } from '../index'
|
||||||
|
|
||||||
|
// 验证码登录
|
||||||
|
const smsAuth = (data) =>{
|
||||||
|
return request({
|
||||||
|
url: "user/auth/sms",
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取验证码
|
||||||
|
const getSms = (data) =>{
|
||||||
|
return request({
|
||||||
|
url: "user/auth/verify",
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
export {
|
||||||
|
smsAuth,
|
||||||
|
getSms
|
||||||
|
}
|
||||||
128
apis/interfaces/gout.js
Normal file
128
apis/interfaces/gout.js
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
* moduleName:腾风 病例
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { request } from '../index'
|
||||||
|
|
||||||
|
// 添加病例-前置
|
||||||
|
const goutCreate = () => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/create'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加病例
|
||||||
|
const goutAdd = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看病例
|
||||||
|
const goutSee = () => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加病例-图片
|
||||||
|
const goutCover = (case_id, data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/' + case_id + '/add_cover',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查看尿酸
|
||||||
|
const lastLog = () => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/last_log'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加尿酸值
|
||||||
|
const AddlastLog = (user_case_id, data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/' + user_case_id + '/logs',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尿酸记录
|
||||||
|
const ListLog = (user_case_id, data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/' + user_case_id + '/logs',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尿酸记录-详情
|
||||||
|
const DetLog = (user_case_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/logs/' + user_case_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除尿酸记录
|
||||||
|
const DelLog = (user_case_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/logs/' + user_case_id,
|
||||||
|
method: 'DELETE'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 病友记
|
||||||
|
const allLogs = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/result/all_logs',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 食物列表/嘌呤查询
|
||||||
|
const foodList = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/food',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 食物详情
|
||||||
|
const foodDet = (food_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/food/' + food_id
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 食物投票
|
||||||
|
const foodVote = (food_id, option_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'gout/food/' + food_id + '/' + option_id,
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
goutCreate,
|
||||||
|
goutAdd,
|
||||||
|
goutSee,
|
||||||
|
goutCover,
|
||||||
|
lastLog,
|
||||||
|
AddlastLog,
|
||||||
|
ListLog,
|
||||||
|
DetLog,
|
||||||
|
DelLog,
|
||||||
|
allLogs,
|
||||||
|
foodList,
|
||||||
|
foodDet,
|
||||||
|
foodVote
|
||||||
|
}
|
||||||
77
apis/interfaces/mall.js
Normal file
77
apis/interfaces/mall.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
* moduleName: 腾风首页
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { request } from '../index'
|
||||||
|
|
||||||
|
// 首页
|
||||||
|
const index = () => {
|
||||||
|
return request({
|
||||||
|
url: 'mall'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 商品详情
|
||||||
|
const goods = (goods_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/goods/' + goods_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文章详情
|
||||||
|
const artiicle = (artiicle_id) => {
|
||||||
|
return request({
|
||||||
|
url: 'cms/articles/' + artiicle_id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退货单-审核
|
||||||
|
const storeAudit = (refund_id, data) => {
|
||||||
|
return request({
|
||||||
|
url: 'manages/refunds/' + refund_id + '/audit',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提货单列表
|
||||||
|
const storeDeliver = (state) => {
|
||||||
|
return request({
|
||||||
|
url: 'manages/shipments',
|
||||||
|
data: {
|
||||||
|
state
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 领取商品
|
||||||
|
const Receive = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/buy/samples',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 省市区-获取
|
||||||
|
const create = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/addresses/create',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
index,
|
||||||
|
goods,
|
||||||
|
artiicle,
|
||||||
|
storeAudit,
|
||||||
|
storeDeliver,
|
||||||
|
Receive,
|
||||||
|
create
|
||||||
|
}
|
||||||
17
apis/interfaces/uploading.js
Normal file
17
apis/interfaces/uploading.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
* moduleName: 上传图片
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { uploading as upd } from '../index'
|
||||||
|
|
||||||
|
const uploads = (paths) => {
|
||||||
|
return upd(paths)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
uploads
|
||||||
|
}
|
||||||
72
apis/interfaces/user.js
Normal file
72
apis/interfaces/user.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
/**
|
||||||
|
* Web唐明明
|
||||||
|
* 匆匆数载恍如梦,岁月迢迢华发增。
|
||||||
|
* 碌碌无为枉半生,一朝惊醒万事空。
|
||||||
|
* moduleName:腾风 我的
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { request } from '../index'
|
||||||
|
|
||||||
|
// 用户信息
|
||||||
|
const userIndex = () => {
|
||||||
|
return request({
|
||||||
|
url: 'user/info'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传头像
|
||||||
|
const setting = (key, data) => {
|
||||||
|
return request({
|
||||||
|
url: 'user/setting/' + key,
|
||||||
|
method: 'PUT',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单列表
|
||||||
|
const orders = (data) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/orders',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单详情
|
||||||
|
const goodsDet = (order_no) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/orders/' + order_no
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 订单签收
|
||||||
|
const goodsSign = (order_no) => {
|
||||||
|
return request({
|
||||||
|
url: 'mall/orders/' + order_no + '/sign',
|
||||||
|
method: 'PUT'
|
||||||
|
}, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 我的伙伴
|
||||||
|
const relations = () => {
|
||||||
|
return request({
|
||||||
|
url: 'user/relations'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 我的推广码
|
||||||
|
const invite = () => {
|
||||||
|
return request({
|
||||||
|
url: 'user/invite'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
userIndex,
|
||||||
|
setting,
|
||||||
|
orders,
|
||||||
|
goodsDet,
|
||||||
|
goodsSign,
|
||||||
|
relations,
|
||||||
|
invite
|
||||||
|
}
|
||||||
16
index.html
Normal file
16
index.html
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
|
||||||
|
<title></title>
|
||||||
|
<!--preload-links-->
|
||||||
|
<!--app-context-->
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app">
|
||||||
|
<!--app-html-->
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
18
js_sdk/junyi-h5-copy/junyi-h5-copy/junyi-h5-copy.js
Normal file
18
js_sdk/junyi-h5-copy/junyi-h5-copy/junyi-h5-copy.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export default function h5Copy(content) {
|
||||||
|
|
||||||
|
if (!document.queryCommandSupported('copy')) {
|
||||||
|
// 不支持
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let textarea = document.createElement("textarea")
|
||||||
|
textarea.value = content
|
||||||
|
textarea.readOnly = "readOnly"
|
||||||
|
document.body.appendChild(textarea)
|
||||||
|
textarea.select() // 选择对象
|
||||||
|
textarea.setSelectionRange(0, content.length) //核心
|
||||||
|
let result = document.execCommand("copy") // 执行浏览器复制命令
|
||||||
|
textarea.remove()
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
31
main.js
Normal file
31
main.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import App from './App'
|
||||||
|
|
||||||
|
// #ifndef VUE3
|
||||||
|
import Vue from 'vue';
|
||||||
|
import { router, RouterMount } from './router';
|
||||||
|
import store from './store';
|
||||||
|
import uView from "uview-ui";
|
||||||
|
Vue.use(uView);
|
||||||
|
Vue.use(router)
|
||||||
|
Vue.config.productionTip = false
|
||||||
|
Vue.prototype.$store = store
|
||||||
|
App.mpType = 'app'
|
||||||
|
const app = new Vue({
|
||||||
|
...App
|
||||||
|
})
|
||||||
|
app.$mount()
|
||||||
|
// #endif
|
||||||
|
// #ifdef H5
|
||||||
|
RouterMount(app,router,'#app')
|
||||||
|
// #endif
|
||||||
|
// #ifdef VUE3
|
||||||
|
import {
|
||||||
|
createSSRApp
|
||||||
|
} from 'vue'
|
||||||
|
export function createApp() {
|
||||||
|
const app = createSSRApp(App)
|
||||||
|
return {
|
||||||
|
app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// #endif
|
||||||
78
manifest.json
Normal file
78
manifest.json
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
{
|
||||||
|
"name" : "medical",
|
||||||
|
"appid" : "__UNI__F02BFB1",
|
||||||
|
"description" : "",
|
||||||
|
"versionName" : "1.0.0",
|
||||||
|
"versionCode" : "100",
|
||||||
|
"transformPx" : false,
|
||||||
|
/* 5+App特有相关 */
|
||||||
|
"app-plus" : {
|
||||||
|
"usingComponents" : true,
|
||||||
|
"nvueStyleCompiler" : "uni-app",
|
||||||
|
"compilerVersion" : 3,
|
||||||
|
"splashscreen" : {
|
||||||
|
"alwaysShowBeforeRender" : true,
|
||||||
|
"waiting" : true,
|
||||||
|
"autoclose" : true,
|
||||||
|
"delay" : 0
|
||||||
|
},
|
||||||
|
/* 模块配置 */
|
||||||
|
"modules" : {},
|
||||||
|
/* 应用发布信息 */
|
||||||
|
"distribute" : {
|
||||||
|
/* android打包配置 */
|
||||||
|
"android" : {
|
||||||
|
"permissions" : [
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.VIBRATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
|
||||||
|
"<uses-feature android:name=\"android.hardware.camera\"/>",
|
||||||
|
"<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
/* ios打包配置 */
|
||||||
|
"ios" : {},
|
||||||
|
/* SDK配置 */
|
||||||
|
"sdkConfigs" : {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/* 快应用特有相关 */
|
||||||
|
"quickapp" : {},
|
||||||
|
/* 小程序特有相关 */
|
||||||
|
"mp-weixin" : {
|
||||||
|
"appid" : "",
|
||||||
|
"setting" : {
|
||||||
|
"urlCheck" : false
|
||||||
|
},
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-alipay" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-baidu" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"mp-toutiao" : {
|
||||||
|
"usingComponents" : true
|
||||||
|
},
|
||||||
|
"uniStatistics" : {
|
||||||
|
"enable" : false
|
||||||
|
},
|
||||||
|
"vueVersion" : "2",
|
||||||
|
"h5" : {
|
||||||
|
"router" : {
|
||||||
|
"mode" : "history"
|
||||||
|
},
|
||||||
|
"title" : "痛风"
|
||||||
|
}
|
||||||
|
}
|
||||||
108
node_modules/uni-read-pages/README.md
generated
vendored
Normal file
108
node_modules/uni-read-pages/README.md
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# uni-read-pages
|
||||||
|
|
||||||
|
   
|
||||||
|
|
||||||
|
通过 [vue.config.js](https://cli.vuejs.org/zh/config/) 配合此库,可以随心所欲的读取 `pages.json` 下的所有配置
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
您可以使用 `Yarn` 或 `npm` 安装该软件包(选择一个):
|
||||||
|
|
||||||
|
##### Yarn
|
||||||
|
|
||||||
|
```sh
|
||||||
|
yarn add uni-read-pages
|
||||||
|
```
|
||||||
|
##### npm
|
||||||
|
|
||||||
|
```sh
|
||||||
|
npm install uni-read-pages
|
||||||
|
```
|
||||||
|
## 开始
|
||||||
|
配置 `vue.config.js` 通过 `webpack` 注入全局变量 [查看文档](https://www.webpackjs.com/plugins/define-plugin/)
|
||||||
|
|
||||||
|
#### 配置 `vue.config.js`
|
||||||
|
```js
|
||||||
|
//vue.config.js
|
||||||
|
const TransformPages = require('uni-read-pages')
|
||||||
|
const tfPages = new TransformPages()
|
||||||
|
module.exports = {
|
||||||
|
configureWebpack: {
|
||||||
|
plugins: [
|
||||||
|
new tfPages.webpack.DefinePlugin({
|
||||||
|
ROUTES: JSON.stringify(tfPages.routes)
|
||||||
|
})
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
借助`webpack.DefinePlugin` 轻松注入全局变量。`ROUTES` 及可全局使用
|
||||||
|
|
||||||
|
#### 使用
|
||||||
|
```js
|
||||||
|
// xxx.vue
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
title: 'Hello'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad() {
|
||||||
|
console.log(ROUTES)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
## API
|
||||||
|
#### options
|
||||||
|
```js
|
||||||
|
//默认值
|
||||||
|
const CONFIG={
|
||||||
|
cli:false, //当前是否为脚手架初始化的项目
|
||||||
|
includes:['path','aliasPath','name'] //需要获取包涵的字段
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Instance method
|
||||||
|
|
||||||
|
* **getPagesRoutes**
|
||||||
|
* 通过读取 `pages.json` 文件 生成直接可用的routes
|
||||||
|
|
||||||
|
* **parsePages(pageCallback, subPageCallback)**
|
||||||
|
* 单条page对象解析
|
||||||
|
|
||||||
|
* **resolvePath(dir)**
|
||||||
|
* 解析绝对路径
|
||||||
|
|
||||||
|
#### Instance attr
|
||||||
|
|
||||||
|
* **CONFIG**
|
||||||
|
* 当前配置项
|
||||||
|
|
||||||
|
* **webpack**
|
||||||
|
* 当前工程下需要用到 `webpack`
|
||||||
|
|
||||||
|
* **uniPagesJSON**
|
||||||
|
* 当前 `uni-app` 内置对象,可以通过此属性调用一些内置方法
|
||||||
|
|
||||||
|
* **routes**
|
||||||
|
* 通过 **includes** 解析后得到的路由表 **可直接使用**
|
||||||
|
|
||||||
|
#### getter
|
||||||
|
|
||||||
|
* **pagesJson**
|
||||||
|
* 获取所有 `pages.json` 下的内容 返回 `json`
|
||||||
|
|
||||||
|
|
||||||
|
#### uniPagesJSON method
|
||||||
|
|
||||||
|
* getMainEntry()
|
||||||
|
* getNVueMainEntry()
|
||||||
|
* parsePages (pagesJson, pageCallback, subPageCallback)
|
||||||
|
* parseEntry (pagesJson)
|
||||||
|
* getPagesJson()
|
||||||
|
* parsePagesJson (content, loader)
|
||||||
|
|
||||||
|
#### uniPagesJSON attr
|
||||||
|
* pagesJsonJsFileName //默认值 pages.js
|
||||||
83
node_modules/uni-read-pages/index.js
generated
vendored
Normal file
83
node_modules/uni-read-pages/index.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const CONFIG = {
|
||||||
|
includes: ['path', 'aliasPath', 'name']
|
||||||
|
}
|
||||||
|
const rootPath = path.resolve(process.cwd(), 'node_modules');
|
||||||
|
|
||||||
|
/** 解析绝对路径
|
||||||
|
* @param {Object} dir
|
||||||
|
*/
|
||||||
|
function resolvePath(dir) {
|
||||||
|
return path.resolve(rootPath, dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransformPages {
|
||||||
|
constructor(config) {
|
||||||
|
config = {
|
||||||
|
...CONFIG,
|
||||||
|
...config
|
||||||
|
};
|
||||||
|
this.CONFIG = config;
|
||||||
|
this.webpack = require(resolvePath('webpack'));
|
||||||
|
this.uniPagesJSON = require(resolvePath('@dcloudio/uni-cli-shared/lib/pages.js'));
|
||||||
|
this.routes = this.getPagesRoutes().concat(this.getNotMpRoutes());
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 获取所有pages.json下的内容 返回json
|
||||||
|
*/
|
||||||
|
get pagesJson() {
|
||||||
|
return this.uniPagesJSON.getPagesJson();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 通过读取pages.json文件 生成直接可用的routes
|
||||||
|
*/
|
||||||
|
getPagesRoutes(pages = this.pagesJson.pages, rootPath = null) {
|
||||||
|
const routes = [];
|
||||||
|
for (let i = 0; i < pages.length; i++) {
|
||||||
|
const item = pages[i];
|
||||||
|
const route = {};
|
||||||
|
for (let j = 0; j < this.CONFIG.includes.length; j++) {
|
||||||
|
const key = this.CONFIG.includes[j];
|
||||||
|
let value = item[key];
|
||||||
|
if (key === 'path') {
|
||||||
|
value = rootPath ? `/${rootPath}/${value}` : `/${value}`
|
||||||
|
}
|
||||||
|
if (key === 'aliasPath' && i == 0 && rootPath == null) {
|
||||||
|
route[key] = route[key] || '/'
|
||||||
|
} else if (value !== undefined) {
|
||||||
|
route[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
routes.push(route);
|
||||||
|
}
|
||||||
|
return routes;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 解析小程序分包路径
|
||||||
|
*/
|
||||||
|
getNotMpRoutes() {
|
||||||
|
const {
|
||||||
|
subPackages
|
||||||
|
} = this.pagesJson;
|
||||||
|
let routes = [];
|
||||||
|
if (subPackages == null || subPackages.length == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
for (let i = 0; i < subPackages.length; i++) {
|
||||||
|
const subPages = subPackages[i].pages;
|
||||||
|
const root = subPackages[i].root;
|
||||||
|
const subRoutes = this.getPagesRoutes(subPages, root);
|
||||||
|
routes = routes.concat(subRoutes)
|
||||||
|
}
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 单条page对象解析
|
||||||
|
* @param {Object} pageCallback
|
||||||
|
* @param {Object} subPageCallback
|
||||||
|
*/
|
||||||
|
parsePages(pageCallback, subPageCallback) {
|
||||||
|
this.uniPagesJSON.parsePages(this.pagesJson, pageCallback, subPageCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = TransformPages
|
||||||
51
node_modules/uni-read-pages/package.json
generated
vendored
Normal file
51
node_modules/uni-read-pages/package.json
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
{
|
||||||
|
"_from": "uni-read-pages",
|
||||||
|
"_id": "uni-read-pages@1.0.5",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-GkrrZ0LX0vn9R5k6RKEi0Ez3Q3e2vUpjXQ8Z6/K/d28KudI9ajqgt8WEjQFlG5EPm1K6uTArN8LlqmZTEixDUA==",
|
||||||
|
"_location": "/uni-read-pages",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "tag",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "uni-read-pages",
|
||||||
|
"name": "uni-read-pages",
|
||||||
|
"escapedName": "uni-read-pages",
|
||||||
|
"rawSpec": "",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "latest"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"#USER",
|
||||||
|
"/"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/uni-read-pages/-/uni-read-pages-1.0.5.tgz",
|
||||||
|
"_shasum": "452c8dcaa8977bbaef600909be926c8d9704387c",
|
||||||
|
"_spec": "uni-read-pages",
|
||||||
|
"_where": "/Users/WebTmm/Desktop/medical/medical",
|
||||||
|
"author": "",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/SilurianYang/uni-read-pages/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "read `pages.json` file to generate the routes table",
|
||||||
|
"directories": {
|
||||||
|
"example": "examples"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/SilurianYang/uni-read-pages#readme",
|
||||||
|
"keywords": [],
|
||||||
|
"license": "ISC",
|
||||||
|
"main": "index.js",
|
||||||
|
"name": "uni-read-pages",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/SilurianYang/uni-read-pages.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "webpack --progress --config webpack/webpack.prod.js",
|
||||||
|
"dev": "webpack --watch --progress --config webpack/webpack.dev.js",
|
||||||
|
"postinstall": "node -e \"console.log('\\x1b[91m','\\n\\n uni-simple-router 垫脚片,欢迎下载!\\n \\n 开源不易,需要鼓励。去给 uni-read-pages 项目 点个 star 吧 \\n\\n')\""
|
||||||
|
},
|
||||||
|
"version": "1.0.5"
|
||||||
|
}
|
||||||
6
node_modules/uni-simple-router/.eslintignore
generated
vendored
Normal file
6
node_modules/uni-simple-router/.eslintignore
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
dist
|
||||||
|
/node_modules
|
||||||
|
/webpack
|
||||||
|
/src/global.d.ts
|
||||||
|
/test
|
||||||
|
/jest.config.js
|
||||||
257
node_modules/uni-simple-router/.eslintrc.js
generated
vendored
Normal file
257
node_modules/uni-simple-router/.eslintrc.js
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
node: true,
|
||||||
|
es6: true
|
||||||
|
},
|
||||||
|
globals: {
|
||||||
|
uni: true,
|
||||||
|
plus: true,
|
||||||
|
getCurrentPages: true,
|
||||||
|
getApp: true,
|
||||||
|
__uniConfig: true,
|
||||||
|
__uniRoutes: true,
|
||||||
|
$npm_package_name: true
|
||||||
|
},
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
extends: ['eslint:recommended'],
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/consistent-type-definitions': [
|
||||||
|
'error',
|
||||||
|
'interface'
|
||||||
|
],
|
||||||
|
'accessor-pairs': 2,
|
||||||
|
'arrow-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
before: true,
|
||||||
|
after: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'block-spacing': [2, 'always'],
|
||||||
|
'brace-style': [
|
||||||
|
2,
|
||||||
|
'1tbs',
|
||||||
|
{
|
||||||
|
allowSingleLine: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
camelcase: [
|
||||||
|
0,
|
||||||
|
{
|
||||||
|
properties: 'always'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'comma-dangle': [2, 'never'],
|
||||||
|
'comma-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
before: false,
|
||||||
|
after: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'comma-style': [2, 'last'],
|
||||||
|
'constructor-super': 2,
|
||||||
|
curly: [2, 'multi-line'],
|
||||||
|
'dot-location': [2, 'property'],
|
||||||
|
'eol-last': 2,
|
||||||
|
eqeqeq: ['error', 'always', {null: 'ignore'}],
|
||||||
|
'generator-star-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
before: true,
|
||||||
|
after: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'handle-callback-err': [2, '^(err|error)$'],
|
||||||
|
indent: ['error', 4],
|
||||||
|
'jsx-quotes': [2, 'prefer-single'],
|
||||||
|
'key-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
beforeColon: false,
|
||||||
|
afterColon: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'keyword-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
before: true,
|
||||||
|
after: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'new-cap': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
newIsCap: true,
|
||||||
|
capIsNew: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'new-parens': 2,
|
||||||
|
'no-array-constructor': 2,
|
||||||
|
'no-caller': 2,
|
||||||
|
'no-console': 'off',
|
||||||
|
'no-class-assign': 2,
|
||||||
|
'no-cond-assign': 2,
|
||||||
|
'no-const-assign': 2,
|
||||||
|
'no-control-regex': 0,
|
||||||
|
'no-delete-var': 2,
|
||||||
|
'no-dupe-args': 2,
|
||||||
|
'no-dupe-class-members': 2,
|
||||||
|
'no-dupe-keys': 2,
|
||||||
|
'no-duplicate-case': 2,
|
||||||
|
'no-empty-character-class': 2,
|
||||||
|
'no-empty-pattern': 2,
|
||||||
|
'no-eval': 2,
|
||||||
|
'no-ex-assign': 2,
|
||||||
|
'no-extend-native': 2,
|
||||||
|
'no-extra-bind': 2,
|
||||||
|
'no-extra-boolean-cast': 2,
|
||||||
|
'no-extra-parens': [2, 'functions'],
|
||||||
|
'no-fallthrough': 2,
|
||||||
|
'no-floating-decimal': 2,
|
||||||
|
'no-func-assign': 2,
|
||||||
|
'no-implied-eval': 2,
|
||||||
|
'no-inner-declarations': [2, 'functions'],
|
||||||
|
'no-invalid-regexp': 2,
|
||||||
|
'no-irregular-whitespace': 2,
|
||||||
|
'no-iterator': 2,
|
||||||
|
'no-label-var': 2,
|
||||||
|
'no-labels': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
allowLoop: false,
|
||||||
|
allowSwitch: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-lone-blocks': 2,
|
||||||
|
'no-mixed-spaces-and-tabs': 2,
|
||||||
|
'no-multi-spaces': 2,
|
||||||
|
'no-multi-str': 2,
|
||||||
|
'no-multiple-empty-lines': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
max: 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-native-reassign': 2,
|
||||||
|
'no-negated-in-lhs': 2,
|
||||||
|
'no-new-object': 2,
|
||||||
|
'no-new-require': 2,
|
||||||
|
'no-new-symbol': 2,
|
||||||
|
'no-new-wrappers': 2,
|
||||||
|
'no-obj-calls': 2,
|
||||||
|
'no-octal': 2,
|
||||||
|
'no-octal-escape': 2,
|
||||||
|
'no-path-concat': 2,
|
||||||
|
'no-proto': 2,
|
||||||
|
'no-redeclare': 2,
|
||||||
|
'no-regex-spaces': 2,
|
||||||
|
'no-return-assign': [2, 'except-parens'],
|
||||||
|
'no-self-assign': 2,
|
||||||
|
'no-self-compare': 2,
|
||||||
|
'no-sequences': 2,
|
||||||
|
'no-shadow-restricted-names': 2,
|
||||||
|
'no-spaced-func': 2,
|
||||||
|
'no-sparse-arrays': 2,
|
||||||
|
'no-this-before-super': 2,
|
||||||
|
'no-throw-literal': 2,
|
||||||
|
'no-trailing-spaces': 2,
|
||||||
|
'no-undef': 2,
|
||||||
|
'no-undef-init': 2,
|
||||||
|
'no-unexpected-multiline': 2,
|
||||||
|
'no-unmodified-loop-condition': 2,
|
||||||
|
'no-unneeded-ternary': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
defaultAssignment: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-unreachable': 2,
|
||||||
|
'no-unsafe-finally': 2,
|
||||||
|
'no-unused-vars': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
vars: 'all',
|
||||||
|
args: 'none'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-useless-call': 2,
|
||||||
|
'no-useless-computed-key': 2,
|
||||||
|
'no-useless-constructor': 2,
|
||||||
|
'no-useless-escape': 0,
|
||||||
|
'no-whitespace-before-property': 2,
|
||||||
|
'no-with': 2,
|
||||||
|
'one-var': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
initialized: 'never'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'operator-linebreak': [
|
||||||
|
2,
|
||||||
|
'after',
|
||||||
|
{
|
||||||
|
overrides: {
|
||||||
|
'?': 'before',
|
||||||
|
':': 'before'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'padded-blocks': [2, 'never'],
|
||||||
|
quotes: [
|
||||||
|
2,
|
||||||
|
'single',
|
||||||
|
{
|
||||||
|
avoidEscape: true,
|
||||||
|
allowTemplateLiterals: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
semi: 'off',
|
||||||
|
'semi-spacing': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
before: false,
|
||||||
|
after: true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'space-before-blocks': [2, 'always'],
|
||||||
|
'space-before-function-paren': [2, 'never'],
|
||||||
|
'space-in-parens': [2, 'never'],
|
||||||
|
'space-infix-ops': 2,
|
||||||
|
'space-unary-ops': [
|
||||||
|
2,
|
||||||
|
{
|
||||||
|
words: true,
|
||||||
|
nonwords: false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'spaced-comment': [
|
||||||
|
2,
|
||||||
|
'always',
|
||||||
|
{
|
||||||
|
markers: [
|
||||||
|
'global',
|
||||||
|
'globals',
|
||||||
|
'eslint',
|
||||||
|
'eslint-disable',
|
||||||
|
'*package',
|
||||||
|
'!',
|
||||||
|
','
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'template-curly-spacing': [2, 'never'],
|
||||||
|
'use-isnan': 2,
|
||||||
|
'valid-typeof': 2,
|
||||||
|
'wrap-iife': [2, 'any'],
|
||||||
|
'yield-star-spacing': [2, 'both'],
|
||||||
|
yoda: [2, 'never'],
|
||||||
|
'prefer-const': 2,
|
||||||
|
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||||
|
'object-curly-spacing': 'off',
|
||||||
|
'array-bracket-spacing': [2, 'never']
|
||||||
|
}
|
||||||
|
};
|
||||||
39
node_modules/uni-simple-router/.github/ISSUE_TEMPLATE/bug_report.md
generated
vendored
Normal file
39
node_modules/uni-simple-router/.github/ISSUE_TEMPLATE/bug_report.md
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
---
|
||||||
|
name: 报告问题(Bug report)
|
||||||
|
about: 详细描述你遇到的问题并寻求社区帮助
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**问题描述**
|
||||||
|
[问题描述:尽可能简洁清晰地把问题描述清楚]
|
||||||
|
|
||||||
|
**复现步骤**
|
||||||
|
[复现问题的步骤]
|
||||||
|
1. 启动 '...'
|
||||||
|
2. 点击 '....'
|
||||||
|
3. 查看
|
||||||
|
|
||||||
|
[或者可以直接贴源代码]
|
||||||
|
|
||||||
|
**预期结果**
|
||||||
|
[使用简洁清晰的语言描述你希望生效的预期结果]
|
||||||
|
|
||||||
|
**实际结果**
|
||||||
|
[这里请贴上你的报错截图或文字]
|
||||||
|
|
||||||
|
|
||||||
|
**系统信息:**
|
||||||
|
- 发行平台: [如 微信小程序、H5平台、5+ App等]
|
||||||
|
- 操作系统 [如 iOS 12.1.2、Android 7.0]
|
||||||
|
- HBuilderX版本 [如使用HBuilderX,则需提供 HBuilderX 版本号]
|
||||||
|
- 项目创建方法 [如使用Vue-cli创建/HBuilderX]
|
||||||
|
- 设备信息 [如 iPhone8 Plus]
|
||||||
|
- uni-simple-router版本 [如 v1.5.4]
|
||||||
|
|
||||||
|
|
||||||
|
**补充信息**
|
||||||
|
[可选]
|
||||||
|
[根据你的分析,出现这个问题的原因可能在哪里?]
|
||||||
21
node_modules/uni-simple-router/.github/ISSUE_TEMPLATE/feature_request.md
generated
vendored
Normal file
21
node_modules/uni-simple-router/.github/ISSUE_TEMPLATE/feature_request.md
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
---
|
||||||
|
name: 建议新功能(Feature Request)
|
||||||
|
about: 对 uni-simple-router 提出改善建议
|
||||||
|
title: ''
|
||||||
|
labels: ''
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**新功能描述**
|
||||||
|
简洁描述你希望补充完善的增强功能
|
||||||
|
|
||||||
|
**现状及问题**
|
||||||
|
[当前现状及由此导致的不便]
|
||||||
|
|
||||||
|
**尝试方案**
|
||||||
|
[如果你有尝试绕开或其它解决方案,在这里描述你的建议方案]
|
||||||
|
|
||||||
|
**补充信息**
|
||||||
|
[其它你认为有参考价值的信息]
|
||||||
|
|
||||||
76
node_modules/uni-simple-router/CODE_OF_CONDUCT.md
generated
vendored
Normal file
76
node_modules/uni-simple-router/CODE_OF_CONDUCT.md
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
|
contributors and maintainers pledge to making participation in our project and
|
||||||
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||||
|
level of experience, education, socio-economic status, nationality, personal
|
||||||
|
appearance, race, religion, or sexual identity and orientation.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to creating a positive environment
|
||||||
|
include:
|
||||||
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at 1606726660@qq.com. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see
|
||||||
|
https://www.contributor-covenant.org/faq
|
||||||
21
node_modules/uni-simple-router/LICENSE
generated
vendored
Normal file
21
node_modules/uni-simple-router/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 hhyang
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
49
node_modules/uni-simple-router/README.md
generated
vendored
Normal file
49
node_modules/uni-simple-router/README.md
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# uni-simple-router
|
||||||
|
|
||||||
|
> 一个更为简洁的[Vue-router](https://router.vuejs.org/zh/),专为 [uni-app](https://uniapp.dcloud.io/) 量身打造
|
||||||
|
|
||||||
|
## 介绍
|
||||||
|
|
||||||
|
`uni-simple-router` 是专为 [uni-app](https://uniapp.dcloud.io/) 打造的路由器。它与 [uni-app](https://uniapp.dcloud.io/) 核心深度集成,使使用 [uni-app](https://uniapp.dcloud.io/) 轻松构建单页应用程序变得轻而易举。功能包括:
|
||||||
|
|
||||||
|
* `H5端` 能完全使用 `vue-router` 进行开发。
|
||||||
|
|
||||||
|
* 模块化,基于组件的路由器配置。
|
||||||
|
|
||||||
|
* 路由参数,查询,通配符。
|
||||||
|
|
||||||
|
* `H5端` 查看由 `uni-simple-router` 过渡系统提供动力的过渡效果。
|
||||||
|
|
||||||
|
* 更细粒度的导航控制。
|
||||||
|
|
||||||
|
* `H端`自动控制活动的CSS类链接。
|
||||||
|
|
||||||
|
* 通配小程序端、APP端、H5端。
|
||||||
|
|
||||||
|
|
||||||
|
开始使用 [查看文档](http://hhyang.cn),或 [使用示例](https://github.com/SilurianYang/uni-simple-router/tree/master/examples)(请参见下面的示例)。
|
||||||
|
|
||||||
|
## 问题
|
||||||
|
在提交问题的之前,请确保阅读 [“问题报告清单”](https://github.com/SilurianYang/uni-simple-router/issues/new?assignees=&labels=&template=bug_report.md&title=) 。不符合准则的问题可能会立即被解决。
|
||||||
|
|
||||||
|
## 贡献
|
||||||
|
提出拉取请求之前,请务必先阅读 [查看文档](http://hhyang.cn)(请参见下面的示例)。。
|
||||||
|
|
||||||
|
## 变更日志
|
||||||
|
[发行说明](https://github.com/SilurianYang/uni-simple-router/releases) 中记录了每个发行版的详细信息更改。
|
||||||
|
|
||||||
|
## 特别感谢
|
||||||
|
|
||||||
|
特别感谢 [markrgba](https://github.com/markrgba) 一直以来对文档和相关测试的维护。
|
||||||
|
|
||||||
|
## 技术交流
|
||||||
|
|
||||||
|
<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=0f4d7f38e5d15dd49bf7c3032c80ed3f54ecfa3dd800053d6ae145c869f9eb47"><img border="0" src="http://pub.idqqimg.com/wpa/images/group.png" alt="uni-app 插件" title="uni-app 插件"></a>
|
||||||
|
|
||||||
|
|
||||||
|
## 成品预览
|
||||||
|
|
||||||
|
<div style="display: -webkit-box;display: flex; flex-direction: column;align-items: center;">
|
||||||
|
<p style="color: #3eaf7c;font-size:18px">uni-simple-router@2.0+ts+uni-app</p>
|
||||||
|
<img src="https://hhyang.cn/images/ad1.jpg" width="200" height="200">
|
||||||
|
</div>
|
||||||
38
node_modules/uni-simple-router/RFC.md
generated
vendored
Normal file
38
node_modules/uni-simple-router/RFC.md
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
```flow
|
||||||
|
|
||||||
|
st=>start: 开始跳转
|
||||||
|
e=>end: 跳转结束
|
||||||
|
platform=>operation: 平台选择
|
||||||
|
H5=>condition: H5
|
||||||
|
APP=>condition: APP
|
||||||
|
applets=>condition: 小程序
|
||||||
|
routerBeforeEach=>operation: routerBeforeEach
|
||||||
|
lock=>condition: 跳转加锁
|
||||||
|
|
||||||
|
runH5=>operation: H5
|
||||||
|
runAPP=>parallel: APP
|
||||||
|
runapplets=>parallel: 小程序
|
||||||
|
|
||||||
|
beforeRouteLeave=>condition: beforeRouteLeave
|
||||||
|
beforeEach=>condition: beforeEach
|
||||||
|
beforeEnter=>condition: beforeEnter
|
||||||
|
afterEach=>operation: afterEach
|
||||||
|
runJump=>condition: 执行跳转成功或者失败
|
||||||
|
stopJump=>operation: next(false) 停止跳转
|
||||||
|
errorJump=>operation: 跳转失败
|
||||||
|
routerErrorEach=>operation: routerErrorEach
|
||||||
|
routerAfterEach=>operation: routerAfterEach
|
||||||
|
|
||||||
|
st->platform(right)->applets(yes)->routerBeforeEach
|
||||||
|
applets(no)->APP(yes)->routerBeforeEach
|
||||||
|
APP(no)->H5(yes)->routerBeforeEach
|
||||||
|
routerBeforeEach->lock(yes)->runAPP(path1)->runapplets(path1)->beforeRouteLeave
|
||||||
|
lock(no)->runH5->beforeRouteLeave(no)->stopJump->routerErrorEach
|
||||||
|
beforeRouteLeave(yes)->beforeEach(no)->stopJump->routerErrorEach
|
||||||
|
beforeEach(yes)->beforeEnter(no)->stopJump->routerErrorEach
|
||||||
|
beforeEnter(yes)->runJump(no)->errorJump->routerErrorEach
|
||||||
|
runJump(yes)->afterEach->routerAfterEach
|
||||||
|
routerAfterEach->e
|
||||||
|
routerErrorEach->e
|
||||||
|
|
||||||
|
```
|
||||||
50
node_modules/uni-simple-router/api-extractor.json
generated
vendored
Normal file
50
node_modules/uni-simple-router/api-extractor.json
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// this the shared base config for all packages.
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
|
||||||
|
|
||||||
|
"mainEntryPointFilePath": "./dist/src/index.d.ts",
|
||||||
|
|
||||||
|
"apiReport": {
|
||||||
|
"enabled": true,
|
||||||
|
"reportFolder": "./temp/"
|
||||||
|
},
|
||||||
|
|
||||||
|
"docModel": {
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"dtsRollup": {
|
||||||
|
"enabled": true,
|
||||||
|
"untrimmedFilePath": "./dist/<unscopedPackageName>.d.ts"
|
||||||
|
},
|
||||||
|
|
||||||
|
"tsdocMetadata": {
|
||||||
|
"enabled": false
|
||||||
|
},
|
||||||
|
|
||||||
|
"messages": {
|
||||||
|
"compilerMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"extractorMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning",
|
||||||
|
"addToApiReportFile": true
|
||||||
|
},
|
||||||
|
|
||||||
|
"ae-missing-release-tag": {
|
||||||
|
"logLevel": "none"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"tsdocMessageReporting": {
|
||||||
|
"default": {
|
||||||
|
"logLevel": "warning"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
79
node_modules/uni-simple-router/dist/link.vue
generated
vendored
Normal file
79
node_modules/uni-simple-router/dist/link.vue
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<view @click="gotoPage()"><slot></slot></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const navType = {
|
||||||
|
push: 'push',
|
||||||
|
replace: 'replace',
|
||||||
|
replaceAll: 'replaceAll',
|
||||||
|
pushTab: 'pushTab',
|
||||||
|
back:'back'
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: [String, Object],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
stopNavto: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
navType: {
|
||||||
|
type: String,
|
||||||
|
default: 'push',
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
append: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatNav(text) {
|
||||||
|
if (text != null && text.constructor === String) {
|
||||||
|
text = text.replace(/\'/g, '');
|
||||||
|
text = text.replace(/(\w+)(?=:)/g, function (val) {
|
||||||
|
return `"${val}"`;
|
||||||
|
});
|
||||||
|
text = text.replace(/:\s*([^,{}\s"]+)/g, function (val) {
|
||||||
|
const arr = val.split(':');
|
||||||
|
return `:"${arr[1].trim()}"`;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
text = JSON.parse(text);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
if (this.append) {
|
||||||
|
let pathArr = this.$Route.path.split('/');
|
||||||
|
pathArr.splice(pathArr.length - this.level, this.level);
|
||||||
|
pathArr = pathArr.join('/');
|
||||||
|
if (text.constructor === Object) {
|
||||||
|
if (text.path) {
|
||||||
|
text.path = pathArr + text.path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = pathArr + text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
gotoPage() {
|
||||||
|
if (this.stopNavto) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const type = navType[this.navType];
|
||||||
|
if (type == null) {
|
||||||
|
return console.error(` "navType" unknown type \n\n value:${Object.values(navType).join('、')}`);
|
||||||
|
}
|
||||||
|
const navInfo = this.formatNav(this.to);
|
||||||
|
|
||||||
|
this.$Router[type](navInfo);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
312
node_modules/uni-simple-router/dist/uni-simple-router.d.ts
generated
vendored
Normal file
312
node_modules/uni-simple-router/dist/uni-simple-router.d.ts
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
|
||||||
|
export declare interface AppConfig {
|
||||||
|
registerLoadingPage?: boolean;
|
||||||
|
loadingPageStyle?: () => object;
|
||||||
|
loadingPageHook?: (view: any) => void;
|
||||||
|
launchedHook?: () => void;
|
||||||
|
animation?: startAnimationRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface appletConfig {
|
||||||
|
animationDuration?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type backTypeRule = 'backbutton' | 'navigateBack';
|
||||||
|
|
||||||
|
export declare function createRouter(params: InstantiateConfig): Router;
|
||||||
|
|
||||||
|
export declare interface debuggerArrayConfig {
|
||||||
|
error?: boolean;
|
||||||
|
warn?: boolean;
|
||||||
|
log?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type debuggerConfig = boolean | debuggerArrayConfig;
|
||||||
|
|
||||||
|
export declare interface endAnimationRule {
|
||||||
|
animationType?: endAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type endAnimationType = 'slide-out-right' | 'slide-out-left' | 'slide-out-top' | 'slide-out-bottom' | 'pop-out' | 'fade-out' | 'zoom-in' | 'zoom-fade-in' | 'none';
|
||||||
|
|
||||||
|
export declare type guardHookRule = (to: totalNextRoute, from: totalNextRoute, next: (rule?: navtoRule | false) => void) => void;
|
||||||
|
|
||||||
|
export declare interface H5Config {
|
||||||
|
paramsToQuery?: boolean;
|
||||||
|
vueRouterDev?: boolean;
|
||||||
|
vueNext?: boolean;
|
||||||
|
mode?: string;
|
||||||
|
base?: string;
|
||||||
|
linkActiveClass?: string;
|
||||||
|
linkExactActiveClass?: string;
|
||||||
|
scrollBehavior?: Function;
|
||||||
|
fallback?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface h5NextRule {
|
||||||
|
fullPath?: string | undefined;
|
||||||
|
hash?: string | undefined;
|
||||||
|
matched?: Array<object>;
|
||||||
|
meta?: object;
|
||||||
|
name?: undefined | string;
|
||||||
|
type?: undefined | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type hookListRule = Array<(router: Router, to: totalNextRoute, from: totalNextRoute, toRoute: RoutesRule, next: Function) => void>;
|
||||||
|
|
||||||
|
export declare interface hookObjectRule {
|
||||||
|
options: Array<any>;
|
||||||
|
hook: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare enum hookToggle {
|
||||||
|
'beforeHooks' = "beforeEach",
|
||||||
|
'afterHooks' = "afterEach",
|
||||||
|
'enterHooks' = "beforeEnter"
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface InstantiateConfig {
|
||||||
|
[key: string]: any;
|
||||||
|
keepUniOriginNav?: boolean;
|
||||||
|
platform: platformRule;
|
||||||
|
h5?: H5Config;
|
||||||
|
APP?: AppConfig;
|
||||||
|
applet?: appletConfig;
|
||||||
|
debugger?: debuggerConfig;
|
||||||
|
routerBeforeEach?: (to: navtoRule, from: navtoRule, next: (rule?: navtoRule | false) => void) => void;
|
||||||
|
routerAfterEach?: (to: navtoRule, from: navtoRule, next?: Function) => void;
|
||||||
|
routerErrorEach?: (error: navErrorRule, router: Router) => void;
|
||||||
|
resolveQuery?: (jsonQuery: objectAny) => objectAny;
|
||||||
|
parseQuery?: (jsonQuery: objectAny) => objectAny;
|
||||||
|
detectBeforeLock?: (router: Router, to: string | number | totalNextRoute | navRoute, navType: NAVTYPE) => void;
|
||||||
|
routes: RoutesRule[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface LifeCycleConfig {
|
||||||
|
beforeHooks: hookListRule;
|
||||||
|
afterHooks: hookListRule;
|
||||||
|
routerBeforeHooks: hookListRule;
|
||||||
|
routerAfterHooks: hookListRule;
|
||||||
|
routerErrorHooks: Array<(error: navErrorRule, router: Router) => void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface navErrorRule {
|
||||||
|
type: navRuleStatus;
|
||||||
|
msg: string;
|
||||||
|
to?: totalNextRoute;
|
||||||
|
from?: totalNextRoute;
|
||||||
|
nextTo?: any;
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type navMethodRule = Promise<void | undefined | navRuleStatus>;
|
||||||
|
|
||||||
|
export declare interface navRoute extends h5NextRule, navtoRule {
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type navRuleStatus = 0 | 1 | 2 | 3;
|
||||||
|
|
||||||
|
export declare interface navtoRule {
|
||||||
|
NAVTYPE?: NAVTYPE;
|
||||||
|
path?: string;
|
||||||
|
name?: string | undefined;
|
||||||
|
query?: objectAny;
|
||||||
|
params?: objectAny;
|
||||||
|
animationType?: startAnimationType | endAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
events?: objectAny;
|
||||||
|
success?: Function;
|
||||||
|
fail?: Function;
|
||||||
|
complete?: Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type NAVTYPE = 'push' | 'replace' | 'replaceAll' | 'pushTab' | 'back';
|
||||||
|
|
||||||
|
export declare enum navtypeToggle {
|
||||||
|
'push' = "navigateTo",
|
||||||
|
'replace' = "redirectTo",
|
||||||
|
'replaceAll' = "reLaunch",
|
||||||
|
'pushTab' = "switchTab",
|
||||||
|
'back' = "navigateBack"
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type objectAny = {
|
||||||
|
[propName: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export declare interface originMixins extends uniNavApiRule {
|
||||||
|
BACKTYPE: '' | backTypeRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type pageTypeRule = 'app' | 'page' | 'component';
|
||||||
|
|
||||||
|
export declare type platformRule = 'h5' | 'app-plus' | 'app-lets' | 'mp-weixin' | 'mp-baidu' | 'mp-alipay' | 'mp-toutiao' | 'mp-qq' | 'mp-360';
|
||||||
|
|
||||||
|
export declare type PromiseResolve = (value?: void | PromiseLike<void> | undefined) => void;
|
||||||
|
|
||||||
|
export declare type proxyDepsRule = {
|
||||||
|
resetIndex: Array<number>;
|
||||||
|
hooks: {
|
||||||
|
[key: number]: {
|
||||||
|
proxyHook: () => void;
|
||||||
|
callHook: (enterPath: string) => void;
|
||||||
|
resetHook: () => void;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
options: {
|
||||||
|
[key: number]: Array<any>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export declare type proxyHookName = 'beforeHooks' | 'afterHooks';
|
||||||
|
|
||||||
|
export declare type reloadNavRule = totalNextRoute | false | undefined | string;
|
||||||
|
|
||||||
|
export declare type reNavMethodRule = 'navigateTo' | 'redirectTo' | 'reLaunch' | 'switchTab';
|
||||||
|
|
||||||
|
export declare type reNotNavMethodRule = 'navigateBack';
|
||||||
|
|
||||||
|
export declare enum rewriteMethodToggle {
|
||||||
|
'navigateTo' = "push",
|
||||||
|
'navigate' = "push",
|
||||||
|
'redirectTo' = "replace",
|
||||||
|
'reLaunch' = "replaceAll",
|
||||||
|
'switchTab' = "pushTab",
|
||||||
|
'navigateBack' = "back"
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface Router {
|
||||||
|
[key: string]: any;
|
||||||
|
readonly lifeCycle: LifeCycleConfig;
|
||||||
|
readonly options: InstantiateConfig;
|
||||||
|
$lockStatus: boolean;
|
||||||
|
$route: object | null;
|
||||||
|
enterPath: string;
|
||||||
|
Vue: any;
|
||||||
|
appMain: {
|
||||||
|
NAVTYPE: reNavMethodRule | reNotNavMethodRule;
|
||||||
|
path: string;
|
||||||
|
} | {};
|
||||||
|
proxyHookDeps: proxyDepsRule;
|
||||||
|
routesMap: routesMapRule | {};
|
||||||
|
mount: Array<{
|
||||||
|
app: any;
|
||||||
|
el: string;
|
||||||
|
}>;
|
||||||
|
install(Vue: any): void;
|
||||||
|
push(to: totalNextRoute | navRoute | string, from?: totalNextRoute): void;
|
||||||
|
replace(to: totalNextRoute | navRoute | string, from?: totalNextRoute): void;
|
||||||
|
replaceAll(to: totalNextRoute | navRoute | string, from?: totalNextRoute): void;
|
||||||
|
pushTab(to: totalNextRoute | navRoute | string, from?: totalNextRoute): void;
|
||||||
|
back(level: number | undefined, origin?: uniBackRule | uniBackApiRule): void;
|
||||||
|
forceGuardEach(navType: NAVTYPE | undefined, forceNav: boolean): void;
|
||||||
|
beforeEach(userGuard: guardHookRule): void;
|
||||||
|
afterEach(userGuard: (to: totalNextRoute, from: totalNextRoute) => void): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare function RouterMount(Vim: any, router: Router, el?: string | undefined): void | never;
|
||||||
|
|
||||||
|
export declare interface routeRule {
|
||||||
|
name: string | undefined;
|
||||||
|
meta: objectAny;
|
||||||
|
path: string;
|
||||||
|
query: objectAny;
|
||||||
|
params: objectAny;
|
||||||
|
fullPath: string;
|
||||||
|
NAVTYPE: NAVTYPE | '';
|
||||||
|
BACKTYPE?: backTypeRule | '';
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type routesMapKeysRule = 'finallyPathList' | 'finallyPathMap' | 'aliasPathMap' | 'pathMap' | 'nameMap' | 'vueRouteMap';
|
||||||
|
|
||||||
|
export declare interface routesMapRule {
|
||||||
|
[key: string]: any;
|
||||||
|
finallyPathList: Array<string>;
|
||||||
|
finallyPathMap: RoutesRule;
|
||||||
|
aliasPathMap: RoutesRule;
|
||||||
|
pathMap: RoutesRule;
|
||||||
|
nameMap: RoutesRule;
|
||||||
|
vueRouteMap: objectAny;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface RoutesRule {
|
||||||
|
path: string;
|
||||||
|
component?: object;
|
||||||
|
name?: string;
|
||||||
|
components?: object;
|
||||||
|
redirect?: string | Function;
|
||||||
|
props?: boolean | object | Function;
|
||||||
|
aliasPath?: string;
|
||||||
|
alias?: string | Array<string>;
|
||||||
|
children?: Array<RoutesRule>;
|
||||||
|
beforeEnter?: guardHookRule;
|
||||||
|
meta?: any;
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare function runtimeQuit(title?: string | undefined): void;
|
||||||
|
|
||||||
|
export declare interface startAnimationRule {
|
||||||
|
animationType?: startAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type startAnimationType = 'slide-in-right' | 'slide-in-left' | 'slide-in-top' | 'slide-in-bottom' | 'pop-in' | 'fade-in' | 'zoom-out' | 'zoom-fade-out' | 'none';
|
||||||
|
|
||||||
|
export declare interface totalNextRoute extends h5NextRule, navtoRule {
|
||||||
|
path: string;
|
||||||
|
delta?: number;
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface uniBackApiRule {
|
||||||
|
delta?: number;
|
||||||
|
animationDuration?: number;
|
||||||
|
animationType?: endAnimationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface uniBackRule {
|
||||||
|
from: backTypeRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare interface uniNavApiRule {
|
||||||
|
url: string;
|
||||||
|
openType?: 'appLaunch';
|
||||||
|
query?: objectAny;
|
||||||
|
path?: string;
|
||||||
|
delta?: number;
|
||||||
|
detail?: {
|
||||||
|
[propName: string]: any;
|
||||||
|
};
|
||||||
|
animationType?: startAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
events?: {
|
||||||
|
[propName: string]: any;
|
||||||
|
};
|
||||||
|
success?: Function;
|
||||||
|
fail?: Function;
|
||||||
|
complete?: Function;
|
||||||
|
animation?: {
|
||||||
|
animationType?: startAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type vueHookNameRule = 'onLaunch' | 'onShow' | 'onHide' | 'onError' | 'onInit' | 'onLoad' | 'onReady' | 'onUnload' | 'onResize' | 'created' | 'beforeMount' | 'mounted' | 'beforeDestroy' | 'destroyed';
|
||||||
|
|
||||||
|
export declare type vueOptionRule = {
|
||||||
|
[propName in vueHookNameRule]: Array<Function> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
export { }
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
interface Vue {
|
||||||
|
$Router: Router;
|
||||||
|
$Route: routeRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
1
node_modules/uni-simple-router/dist/uni-simple-router.js
generated
vendored
Normal file
1
node_modules/uni-simple-router/dist/uni-simple-router.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
107
node_modules/uni-simple-router/github.sh
generated
vendored
Normal file
107
node_modules/uni-simple-router/github.sh
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# author hhyang
|
||||||
|
# home https://github.com/SilurianYang
|
||||||
|
|
||||||
|
printf "\n -------------- Ctrl+D可以退出程序 --------------- \n\n"
|
||||||
|
|
||||||
|
select name in "auto" "status" "add" "commit" "push" "pull" "branch" "checkout" "*"; do
|
||||||
|
case "$name" in
|
||||||
|
# 自动同步文件
|
||||||
|
"auto")
|
||||||
|
cp -avx ./examples/node_modules/uni-simple-router/* ./npm-package
|
||||||
|
rm -rf ./npm-package/package-lock.json
|
||||||
|
cp -avx ./README.md ./npm-package
|
||||||
|
cp -avx ./package.json ./npm-package
|
||||||
|
cp -avx ./npm-package/* ./src
|
||||||
|
rm -rf ./src/README.md
|
||||||
|
rm -rf ./src/package.json
|
||||||
|
|
||||||
|
printf "\n -------------- 自动化构建目录完毕 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 查询status
|
||||||
|
"status")
|
||||||
|
git status
|
||||||
|
printf "\n -------------- 查询完毕 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 添加文件 .或* 全部文件 可自定义文件路径
|
||||||
|
"add")
|
||||||
|
while read -p "请输入更多提交命令 【默认全部.】 :" add; do
|
||||||
|
if [[ "$add" == "" ]]; then
|
||||||
|
eval "git add ."
|
||||||
|
else
|
||||||
|
eval "git add ${add}"
|
||||||
|
fi
|
||||||
|
printf "\n -------------- 添加完成 --------------- \n\n"
|
||||||
|
break
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 提交文件
|
||||||
|
"commit")
|
||||||
|
while read -p "请输入提交信息:" readme; do
|
||||||
|
if [[ "$readme" != "" ]]; then
|
||||||
|
eval "git commit -m '${readme}'"
|
||||||
|
printf "\n -------------- 提交本地完成 --------------- \n\n"
|
||||||
|
break
|
||||||
|
else
|
||||||
|
printf "\n警告====> 提交信息不能为空! \n \n"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 推送到服务端
|
||||||
|
"push")
|
||||||
|
read -p "请输入提交的分支(不输入默认主分支 [master] ):" branch
|
||||||
|
printf "\n\n -------------- 正在推送github,请稍后.... --------------- \n\n"
|
||||||
|
if [[ "$branch" == "" ]]; then
|
||||||
|
git push
|
||||||
|
else
|
||||||
|
eval "git push origin ${branch}"
|
||||||
|
fi
|
||||||
|
printf "\n -------------- 推送github完成 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 拉取最新代码
|
||||||
|
"pull")
|
||||||
|
printf "\n\n -------------- 正在拉取,请稍后.... --------------- \n\n"
|
||||||
|
git pull
|
||||||
|
printf "\n -------------- 正在拉取完成 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
|
||||||
|
# 切换分支操作
|
||||||
|
"branch")
|
||||||
|
read -p "请输入添加更多指令 【分支】 :" branchs
|
||||||
|
if [[ "$branchs" == "" ]]; then
|
||||||
|
printf "\n分支列表如下:\n\n"
|
||||||
|
git branch
|
||||||
|
else
|
||||||
|
eval "git branch ${branchs}"
|
||||||
|
fi
|
||||||
|
printf "\n -------------- 分支操作完毕 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
#
|
||||||
|
"checkout")
|
||||||
|
read -p "请输入添加更多指令 【默认切换到master】 :" out
|
||||||
|
if [[ "$out" == "" ]]; then
|
||||||
|
git checkout master
|
||||||
|
else
|
||||||
|
eval "git checkout ${out}"
|
||||||
|
fi
|
||||||
|
printf "\n -------------- 执行完毕 --------------- \n\n"
|
||||||
|
;;
|
||||||
|
# 自定义指令
|
||||||
|
*)
|
||||||
|
while read -p "请输入自定义命令 【输入:q退出】:" code; do
|
||||||
|
if [[ "$code" == ":q" ]];then
|
||||||
|
printf "\n"
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
printf "\n\n -------------- 正在执行,请稍后.... --------------- \n\n"
|
||||||
|
eval "$code"
|
||||||
|
printf "\n -------------- 执行完毕 --------------- \n\n"
|
||||||
|
done
|
||||||
|
esac
|
||||||
|
done
|
||||||
5
node_modules/uni-simple-router/jest.config.js
generated
vendored
Normal file
5
node_modules/uni-simple-router/jest.config.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
testEnvironment: 'node',
|
||||||
|
moduleDirectories:['node_modules','src']
|
||||||
|
};
|
||||||
62
node_modules/uni-simple-router/package.json
generated
vendored
Normal file
62
node_modules/uni-simple-router/package.json
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
{
|
||||||
|
"_from": "uni-simple-router",
|
||||||
|
"_id": "uni-simple-router@2.0.7",
|
||||||
|
"_inBundle": false,
|
||||||
|
"_integrity": "sha512-8FKv5dw7Eoonm0gkO8udprrxzin0fNUI0+AvIphFkFRH5ZmP5ZWJ2pvnWzb2NiiqQSECTSU5VSB7HhvOSwD5eA==",
|
||||||
|
"_location": "/uni-simple-router",
|
||||||
|
"_phantomChildren": {},
|
||||||
|
"_requested": {
|
||||||
|
"type": "tag",
|
||||||
|
"registry": true,
|
||||||
|
"raw": "uni-simple-router",
|
||||||
|
"name": "uni-simple-router",
|
||||||
|
"escapedName": "uni-simple-router",
|
||||||
|
"rawSpec": "",
|
||||||
|
"saveSpec": null,
|
||||||
|
"fetchSpec": "latest"
|
||||||
|
},
|
||||||
|
"_requiredBy": [
|
||||||
|
"#USER",
|
||||||
|
"/"
|
||||||
|
],
|
||||||
|
"_resolved": "https://registry.npmjs.org/uni-simple-router/-/uni-simple-router-2.0.7.tgz",
|
||||||
|
"_shasum": "04e0b5be6cd733a1ecb9d35a3dbe82f27f48204e",
|
||||||
|
"_spec": "uni-simple-router",
|
||||||
|
"_where": "/Users/WebTmm/Desktop/medical/medical",
|
||||||
|
"author": {
|
||||||
|
"name": "hhyang"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/SilurianYang/uni-simple-router/issues"
|
||||||
|
},
|
||||||
|
"bundleDependencies": false,
|
||||||
|
"deprecated": false,
|
||||||
|
"description": "> 一个更为简洁的[Vue-router](https://router.vuejs.org/zh/),专为 [uni-app](https://uniapp.dcloud.io/) 量身打造",
|
||||||
|
"homepage": "https://github.com/SilurianYang/uni-simple-router#readme",
|
||||||
|
"keywords": [
|
||||||
|
"router",
|
||||||
|
"uni-app-router",
|
||||||
|
"interceptor",
|
||||||
|
"uni-app",
|
||||||
|
"uniapp"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "dist/uni-simple-router.js",
|
||||||
|
"name": "uni-simple-router",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/SilurianYang/uni-simple-router.git"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "node ./publish/build.js",
|
||||||
|
"dev": "webpack --watch --progress --config webpack/webpack.dev.js",
|
||||||
|
"dist": "webpack --progress --config webpack/webpack.prod.js",
|
||||||
|
"dist:dts": "api-extractor run --local --verbose",
|
||||||
|
"lint": "eslint --ext .js,.ts src",
|
||||||
|
"lintFix": "eslint --ext .js,.ts src --fix",
|
||||||
|
"publish": "node ./publish/index.js",
|
||||||
|
"test": "jest test/query-toggle.spec.ts"
|
||||||
|
},
|
||||||
|
"types": "dist/uni-simple-router.d.ts",
|
||||||
|
"version": "2.0.7"
|
||||||
|
}
|
||||||
16
node_modules/uni-simple-router/progress.md
generated
vendored
Normal file
16
node_modules/uni-simple-router/progress.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
## Fixes bug
|
||||||
|
* `小程序` 端 `onLoad`、`onShow` 执行不标准的BUG。(#206,#224,#291)
|
||||||
|
* `小程序` 端 启动页必须写 `onLoad` 才会执行的BUG。
|
||||||
|
* `APP` 端 tab 拦截后无法自动还原选中区域现在已修复。
|
||||||
|
* H5端设置 `aliasPath` 后,无法使用 `aliasPath` 跨端跳转 (#302)
|
||||||
|
* 重写代理生命周期逻辑、保证执行各端执行顺序 (#312)
|
||||||
|
|
||||||
|
## Revise
|
||||||
|
* 参数可以直接传递 `null`。但是需要注意:**在非深度对象传参的情况下,小程序会将 `null` 解析为字符串`undefined`**
|
||||||
|
* 多端情况下自定义启动参数不仅限制于 `query` 传递深度参数,任何组合都可以 (#307,#301)
|
||||||
|
* 去除 `keyword` 白名单字段
|
||||||
|
* 调整小程序启动页面生命周期的执行,让在小程序下的生命周期能更贴近App、H5
|
||||||
|
* `routerErrorEach` 新增回调参数、包括:`NAVTYPE`、`uniActualData`、`level`
|
||||||
|
|
||||||
|
## Known Issues
|
||||||
|
* `APP` 端启动页为tab时,拦截到其他页面后底部tabbar 还依然存在,请避免把原生 `tabbar` 页设置成启动页。你可以在 `beforeEach` 中使用 next 到tabbar页效果一致
|
||||||
76
node_modules/uni-simple-router/src/H5/buildRouter.ts
generated
vendored
Normal file
76
node_modules/uni-simple-router/src/H5/buildRouter.ts
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import {RoutesRule, Router, routesMapRule, totalNextRoute, hookToggle, navtoRule} from '../options/base';
|
||||||
|
import {H5Config} from '../options/config';
|
||||||
|
import {warn} from '../helpers/warn'
|
||||||
|
import {getDataType, getRoutePath} from '../helpers/utils'
|
||||||
|
import { onTriggerEachHook } from '../public/hooks';
|
||||||
|
|
||||||
|
export function buildVueRoutes(router: Router, vueRouteMap:RoutesRule):RoutesRule {
|
||||||
|
const {pathMap, finallyPathList} = (router.routesMap as routesMapRule);
|
||||||
|
const vueRoutePathList:Array<string> = Object.keys(vueRouteMap);
|
||||||
|
for (let i = 0; i < vueRoutePathList.length; i++) {
|
||||||
|
const path = vueRoutePathList[i];
|
||||||
|
const myRoute:RoutesRule = pathMap[path];
|
||||||
|
const vueRoute:RoutesRule = vueRouteMap[path];
|
||||||
|
if (!myRoute) {
|
||||||
|
warn(`${path} 路由地址在路由表中未找到,确定是否传递漏啦`, router, true);
|
||||||
|
} else {
|
||||||
|
const {finallyPath} = getRoutePath(myRoute, router);
|
||||||
|
if (finallyPath instanceof Array) {
|
||||||
|
throw new Error(`非 vueRouterDev 模式下,alias、aliasPath、path 无法提供数组类型! ${JSON.stringify(myRoute)}`);
|
||||||
|
}
|
||||||
|
if (myRoute.name != null) {
|
||||||
|
vueRoute.name = myRoute.name;
|
||||||
|
}
|
||||||
|
const vuePath = vueRoute['path'];
|
||||||
|
const vueAlias = vueRoute['alias'];
|
||||||
|
delete vueRoute['alias'];
|
||||||
|
vueRoute['path'] = (finallyPath as string);
|
||||||
|
if (vuePath === '/' && vueAlias != null) {
|
||||||
|
vueRoute['alias'] = vueAlias;
|
||||||
|
vueRoute['path'] = vuePath;
|
||||||
|
}
|
||||||
|
const beforeEnter = myRoute.beforeEnter;
|
||||||
|
if (beforeEnter) {
|
||||||
|
vueRoute['beforeEnter'] = function(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from: totalNextRoute,
|
||||||
|
next:(rule?: navtoRule|false)=>void,
|
||||||
|
):void{
|
||||||
|
onTriggerEachHook(to, from, router, hookToggle['enterHooks'], next)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (finallyPathList.includes('*')) {
|
||||||
|
vueRouteMap['*'] = pathMap['*']
|
||||||
|
}
|
||||||
|
return vueRouteMap
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildVueRouter(router:Router, vueRouter:any, vueRouteMap:RoutesRule|RoutesRule[]) :void |never {
|
||||||
|
let routes:RoutesRule[] = [];
|
||||||
|
if (getDataType<RoutesRule|RoutesRule[]>(vueRouteMap) === '[object Array]') {
|
||||||
|
routes = (vueRouteMap as RoutesRule[]);
|
||||||
|
} else {
|
||||||
|
routes = Object.values(vueRouteMap);
|
||||||
|
}
|
||||||
|
const {scrollBehavior, fallback} = router.options.h5 as H5Config;
|
||||||
|
const oldScrollBehavior = vueRouter.options.scrollBehavior;
|
||||||
|
vueRouter.options.scrollBehavior = function proxyScrollBehavior(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from:totalNextRoute,
|
||||||
|
savedPosition:any
|
||||||
|
) {
|
||||||
|
oldScrollBehavior && oldScrollBehavior(to, from, savedPosition);
|
||||||
|
return (scrollBehavior as Function)(to, from, savedPosition)
|
||||||
|
}
|
||||||
|
vueRouter.fallback = fallback;
|
||||||
|
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
|
||||||
|
const newVueRouter:any = new vueRouter.constructor({
|
||||||
|
...router.options.h5,
|
||||||
|
base: vueRouter.options.base,
|
||||||
|
mode: vueRouter.options.mode,
|
||||||
|
routes
|
||||||
|
});
|
||||||
|
vueRouter.matcher = newVueRouter.matcher;
|
||||||
|
}
|
||||||
71
node_modules/uni-simple-router/src/H5/proxyHook.ts
generated
vendored
Normal file
71
node_modules/uni-simple-router/src/H5/proxyHook.ts
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import {Router, proxyHookName, totalNextRoute, navtoRule} from '../options/base';
|
||||||
|
|
||||||
|
export class MyArray extends Array {
|
||||||
|
constructor(
|
||||||
|
private router:Router,
|
||||||
|
private vueEachArray:Array<Function>,
|
||||||
|
private myEachHook:Function,
|
||||||
|
private hookName:'beforeHooks'| 'afterHooks',
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
Object.setPrototypeOf(this, MyArray.prototype)
|
||||||
|
}
|
||||||
|
push(v:any):any {
|
||||||
|
this.vueEachArray.push(v);
|
||||||
|
const index = this.length;
|
||||||
|
this[this.length] = (to: totalNextRoute, from: totalNextRoute, next:(rule?: navtoRule|false)=>void) => {
|
||||||
|
if (index > 0) {
|
||||||
|
this.vueEachArray[index](to, from, () => {
|
||||||
|
next && next()
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.myEachHook(to, from, (nextTo?:navtoRule|false) => {
|
||||||
|
// Fixe https://github.com/SilurianYang/uni-simple-router/issues/241 2021年3月6日22:15:27
|
||||||
|
// 目前不调用uni-app的守卫函数,因为会丢失页面栈信息
|
||||||
|
if (nextTo === false) {
|
||||||
|
next(false);
|
||||||
|
} else {
|
||||||
|
this.vueEachArray[index](to, from, (uniNextTo?:navtoRule|false) => {
|
||||||
|
next(nextTo);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, this.router, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function proxyEachHook(router:Router, vueRouter:any):void {
|
||||||
|
const hookList:Array<'beforeHooks'| 'afterHooks'> = ['beforeHooks', 'afterHooks'];
|
||||||
|
for (let i = 0; i < hookList.length; i++) {
|
||||||
|
const hookName = hookList[i];
|
||||||
|
const myEachHook = router.lifeCycle[(hookName as proxyHookName)][0];
|
||||||
|
if (myEachHook) {
|
||||||
|
const vueEachArray:Array<Function> = vueRouter[hookName];
|
||||||
|
vueRouter[hookName] = new MyArray(router, vueEachArray, myEachHook, hookName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function proxyH5Mount(router:Router):void {
|
||||||
|
if (router.mount.length === 0) {
|
||||||
|
if (router.options.h5?.vueRouterDev) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const uAgent = navigator.userAgent;
|
||||||
|
const isIos = !!uAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/)
|
||||||
|
if (isIos) {
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/109
|
||||||
|
setTimeout(() => {
|
||||||
|
const element = document.getElementsByTagName('uni-page');
|
||||||
|
if (element.length > 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
window.location.reload();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const [{app}] = router.mount;
|
||||||
|
app.$mount();
|
||||||
|
router.mount = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
75
node_modules/uni-simple-router/src/app/appPatch.ts
generated
vendored
Normal file
75
node_modules/uni-simple-router/src/app/appPatch.ts
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import { objectAny, Router, totalNextRoute } from '../options/base';
|
||||||
|
import { AppConfig } from '../options/config';
|
||||||
|
|
||||||
|
let quitBefore:number|null = null;
|
||||||
|
let TABBAR:objectAny|null = null;
|
||||||
|
|
||||||
|
export function registerLoddingPage(
|
||||||
|
router:Router,
|
||||||
|
):void{
|
||||||
|
if (router.options.registerLoadingPage) {
|
||||||
|
const { loadingPageHook, loadingPageStyle } = router.options.APP as AppConfig; // 获取app所有配置
|
||||||
|
const view = new plus.nativeObj.View('router-loadding', {
|
||||||
|
top: '0px',
|
||||||
|
left: '0px',
|
||||||
|
height: '100%',
|
||||||
|
width: '100%',
|
||||||
|
...(loadingPageStyle as Function)()
|
||||||
|
});
|
||||||
|
(loadingPageHook as Function)(view); // 触发等待页面生命周期
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runtimeQuit(
|
||||||
|
title:string|undefined = '再按一次退出应用'
|
||||||
|
):void{
|
||||||
|
const nowTime = +new Date();
|
||||||
|
if (!quitBefore) {
|
||||||
|
quitBefore = nowTime;
|
||||||
|
uni.showToast({
|
||||||
|
title,
|
||||||
|
icon: 'none',
|
||||||
|
position: 'bottom',
|
||||||
|
duration: 1000
|
||||||
|
});
|
||||||
|
setTimeout(() => { quitBefore = null }, 1000);
|
||||||
|
} else {
|
||||||
|
if (nowTime - quitBefore < 1000) {
|
||||||
|
plus.runtime.quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tabIndexSelect(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from:totalNextRoute
|
||||||
|
):boolean {
|
||||||
|
if (!(__uniConfig.tabBar && Array.isArray(__uniConfig.tabBar.list))) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const tabBarList = __uniConfig.tabBar.list;
|
||||||
|
const routes:Array<totalNextRoute> = [];
|
||||||
|
let activeIndex:number = 0;
|
||||||
|
for (let i = 0; i < tabBarList.length; i++) {
|
||||||
|
const route:totalNextRoute = tabBarList[i];
|
||||||
|
if ('/' + route.pagePath === to.path || '/' + route.pagePath === from.path) {
|
||||||
|
if (route.pagePath === from.path) {
|
||||||
|
activeIndex = i;
|
||||||
|
}
|
||||||
|
routes.push(route);
|
||||||
|
}
|
||||||
|
if (routes.length === 2) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (routes.length !== 2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (TABBAR == null) {
|
||||||
|
TABBAR = uni.requireNativePlugin('uni-tabview')
|
||||||
|
}
|
||||||
|
(TABBAR as objectAny).switchSelect({
|
||||||
|
index: activeIndex
|
||||||
|
})
|
||||||
|
return true
|
||||||
|
}
|
||||||
18
node_modules/uni-simple-router/src/applets/appletPatch.ts
generated
vendored
Normal file
18
node_modules/uni-simple-router/src/applets/appletPatch.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { Router} from '../options/base';
|
||||||
|
|
||||||
|
export function getEnterPath(
|
||||||
|
vueVim:any,
|
||||||
|
router:Router,
|
||||||
|
) :string {
|
||||||
|
switch (router.options.platform) {
|
||||||
|
case 'mp-alipay':
|
||||||
|
case 'mp-weixin':
|
||||||
|
case 'mp-toutiao':
|
||||||
|
case 'mp-qq':
|
||||||
|
return vueVim.$options.mpInstance.route;
|
||||||
|
case 'mp-baidu':
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/251
|
||||||
|
return vueVim.$options.mpInstance.is || vueVim.$options.mpInstance.pageinstance.route;
|
||||||
|
}
|
||||||
|
return vueVim.$options.mpInstance.route; // 这是暂时的 因为除了以上的小程序 其他没测试 先这样写
|
||||||
|
}
|
||||||
79
node_modules/uni-simple-router/src/component/link.vue
generated
vendored
Normal file
79
node_modules/uni-simple-router/src/component/link.vue
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<view @click="gotoPage()"><slot></slot></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const navType = {
|
||||||
|
push: 'push',
|
||||||
|
replace: 'replace',
|
||||||
|
replaceAll: 'replaceAll',
|
||||||
|
pushTab: 'pushTab',
|
||||||
|
back:'back'
|
||||||
|
};
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: [String, Object],
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
stopNavto: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
navType: {
|
||||||
|
type: String,
|
||||||
|
default: 'push',
|
||||||
|
},
|
||||||
|
level: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
},
|
||||||
|
append: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
formatNav(text) {
|
||||||
|
if (text != null && text.constructor === String) {
|
||||||
|
text = text.replace(/\'/g, '');
|
||||||
|
text = text.replace(/(\w+)(?=:)/g, function (val) {
|
||||||
|
return `"${val}"`;
|
||||||
|
});
|
||||||
|
text = text.replace(/:\s*([^,{}\s"]+)/g, function (val) {
|
||||||
|
const arr = val.split(':');
|
||||||
|
return `:"${arr[1].trim()}"`;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
text = JSON.parse(text);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
if (this.append) {
|
||||||
|
let pathArr = this.$Route.path.split('/');
|
||||||
|
pathArr.splice(pathArr.length - this.level, this.level);
|
||||||
|
pathArr = pathArr.join('/');
|
||||||
|
if (text.constructor === Object) {
|
||||||
|
if (text.path) {
|
||||||
|
text.path = pathArr + text.path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text = pathArr + text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
gotoPage() {
|
||||||
|
if (this.stopNavto) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const type = navType[this.navType];
|
||||||
|
if (type == null) {
|
||||||
|
return console.error(` "navType" unknown type \n\n value:${Object.values(navType).join('、')}`);
|
||||||
|
}
|
||||||
|
const navInfo = this.formatNav(this.to);
|
||||||
|
|
||||||
|
this.$Router[type](navInfo);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
7
node_modules/uni-simple-router/src/global.d.ts
generated
vendored
Normal file
7
node_modules/uni-simple-router/src/global.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
declare var uni:any;
|
||||||
|
declare var plus:any;
|
||||||
|
declare var __uniConfig:any;
|
||||||
|
declare var __uniRoutes:any;
|
||||||
|
declare function getCurrentPages(isAll:boolean|undefined=false):any;
|
||||||
|
declare function getApp(args?:{allowDefault: true}):any;
|
||||||
|
declare var $npm_package_name:string;
|
||||||
78
node_modules/uni-simple-router/src/helpers/config.ts
generated
vendored
Normal file
78
node_modules/uni-simple-router/src/helpers/config.ts
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import {err} from './warn'
|
||||||
|
import { InstantiateConfig, LifeCycleConfig} from '../options/config'
|
||||||
|
import { vueHookNameRule, proxyDepsRule } from '../options/base';
|
||||||
|
|
||||||
|
export const mpPlatformReg = '(^mp-weixin$)|(^mp-baidu$)|(^mp-alipay$)|(^mp-toutiao$)|(^mp-qq$)|(^mp-360$)' // 小程序下不能直接导出正则 需要重新组装成正则 不然bug一推 诡异
|
||||||
|
|
||||||
|
export const baseConfig:InstantiateConfig = {
|
||||||
|
h5: {
|
||||||
|
paramsToQuery: false,
|
||||||
|
vueRouterDev: false,
|
||||||
|
vueNext: false,
|
||||||
|
mode: 'hash',
|
||||||
|
base: '/',
|
||||||
|
linkActiveClass: 'router-link-active',
|
||||||
|
linkExactActiveClass: 'router-link-exact-active',
|
||||||
|
scrollBehavior: (to:any, from:any, savedPostion:Function) => ({ x: 0, y: 0 }),
|
||||||
|
fallback: true
|
||||||
|
},
|
||||||
|
APP: {
|
||||||
|
registerLoadingPage: true,
|
||||||
|
loadingPageStyle: () => JSON.parse('{"backgroundColor":"#FFF"}'),
|
||||||
|
loadingPageHook: (view:any) => { view.show(); },
|
||||||
|
launchedHook: () => { plus.navigator.closeSplashscreen(); },
|
||||||
|
animation: {}
|
||||||
|
},
|
||||||
|
applet: {
|
||||||
|
animationDuration: 300
|
||||||
|
},
|
||||||
|
platform: 'h5',
|
||||||
|
keepUniOriginNav: false,
|
||||||
|
debugger: false,
|
||||||
|
routerBeforeEach: (to, from, next) => { next() },
|
||||||
|
routerAfterEach: (to, from) => {},
|
||||||
|
routerErrorEach: (error, router) => { router.$lockStatus = false; err(error, router, true); },
|
||||||
|
detectBeforeLock: (router, to, navType) => {},
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/choose-location'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/open-location'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/preview-image'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const lifeCycle:LifeCycleConfig = {
|
||||||
|
beforeHooks: [],
|
||||||
|
afterHooks: [],
|
||||||
|
routerBeforeHooks: [],
|
||||||
|
routerAfterHooks: [],
|
||||||
|
routerErrorHooks: []
|
||||||
|
};
|
||||||
|
|
||||||
|
export const proxyHookDeps:proxyDepsRule = {
|
||||||
|
resetIndex: [], // 还原时执行的生命周期的索引
|
||||||
|
hooks: {},
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const proxyHookName:Array<vueHookNameRule> = [
|
||||||
|
'onLaunch',
|
||||||
|
'onShow',
|
||||||
|
'onHide',
|
||||||
|
'onError',
|
||||||
|
'onInit',
|
||||||
|
'onLoad',
|
||||||
|
'onReady',
|
||||||
|
'onUnload',
|
||||||
|
'onResize',
|
||||||
|
'created',
|
||||||
|
'beforeMount',
|
||||||
|
'mounted',
|
||||||
|
'beforeDestroy',
|
||||||
|
'destroyed'
|
||||||
|
]
|
||||||
47
node_modules/uni-simple-router/src/helpers/createRouteMap.ts
generated
vendored
Normal file
47
node_modules/uni-simple-router/src/helpers/createRouteMap.ts
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import {RoutesRule, Router, routesMapRule} from '../options/base';
|
||||||
|
import {H5Config} from '../options/config';
|
||||||
|
import {warn} from './warn'
|
||||||
|
import {getRoutePath} from './utils'
|
||||||
|
|
||||||
|
export function createRouteMap(
|
||||||
|
router: Router,
|
||||||
|
routes: RoutesRule[],
|
||||||
|
): routesMapRule|never {
|
||||||
|
const routesMap:routesMapRule = {
|
||||||
|
finallyPathList: [],
|
||||||
|
finallyPathMap: Object.create(null),
|
||||||
|
aliasPathMap: Object.create(null),
|
||||||
|
pathMap: Object.create(null),
|
||||||
|
vueRouteMap: Object.create(null),
|
||||||
|
nameMap: Object.create(null)
|
||||||
|
}
|
||||||
|
routes.forEach(route => {
|
||||||
|
const { finallyPath, aliasPath, path} = getRoutePath(route, router);
|
||||||
|
if (path == null) {
|
||||||
|
throw new Error(`请提供一个完整的路由对象,包括以绝对路径开始的 ‘path’ 字符串 ${JSON.stringify(route)}`);
|
||||||
|
}
|
||||||
|
if (finallyPath instanceof Array) {
|
||||||
|
if (!(router.options.h5 as H5Config).vueRouterDev && router.options.platform === 'h5') {
|
||||||
|
throw new Error(`非 vueRouterDev 模式下,route.alias 目前无法提供数组类型! ${JSON.stringify(route)}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const strFinallyPath = (finallyPath as string);
|
||||||
|
const strAliasPath = (aliasPath as string);
|
||||||
|
if (router.options.platform !== 'h5') {
|
||||||
|
if (strFinallyPath.indexOf('/') !== 0 && path !== '*') {
|
||||||
|
warn(`当前路由对象下,route:${JSON.stringify(route)} 是否缺少了前缀 ‘/’`, router, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!routesMap.finallyPathMap[strFinallyPath]) {
|
||||||
|
routesMap.finallyPathMap[strFinallyPath] = route;
|
||||||
|
routesMap.aliasPathMap[strAliasPath] = route;
|
||||||
|
routesMap.pathMap[path] = route;
|
||||||
|
routesMap.finallyPathList.push(strFinallyPath);
|
||||||
|
if (route.name != null) {
|
||||||
|
routesMap.nameMap[route.name] = route;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return routesMap;
|
||||||
|
}
|
||||||
36
node_modules/uni-simple-router/src/helpers/lifeCycle.ts
generated
vendored
Normal file
36
node_modules/uni-simple-router/src/helpers/lifeCycle.ts
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { navtoRule, navErrorRule, Router, proxyHookName, guardHookRule, totalNextRoute, hookToggle} from '../options/base';
|
||||||
|
import { LifeCycleConfig, InstantiateConfig} from '../options/config';
|
||||||
|
import {onTriggerEachHook} from '../public/hooks'
|
||||||
|
|
||||||
|
export function registerHook(list:Array<Function>, fn:Function):void {
|
||||||
|
list[0] = fn;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerRouterHooks<T extends LifeCycleConfig>(cycleHooks:T, options:InstantiateConfig):T {
|
||||||
|
registerHook(cycleHooks.routerBeforeHooks, function(to:totalNextRoute, from: totalNextRoute, next:(rule?: navtoRule|false)=>void):void {
|
||||||
|
(options.routerBeforeEach as Function)(to, from, next);
|
||||||
|
})
|
||||||
|
registerHook(cycleHooks.routerAfterHooks, function(to:totalNextRoute, from: totalNextRoute):void {
|
||||||
|
(options.routerAfterEach as Function)(to, from);
|
||||||
|
})
|
||||||
|
registerHook(cycleHooks.routerErrorHooks, function(error:navErrorRule, router:Router):void {
|
||||||
|
(options.routerErrorEach as Function)(error, router);
|
||||||
|
})
|
||||||
|
return cycleHooks;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerEachHooks(router:Router, hookType:proxyHookName, userGuard:guardHookRule) {
|
||||||
|
registerHook(router.lifeCycle[hookType], function(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from: totalNextRoute,
|
||||||
|
next:(rule?: navtoRule|false)=>void,
|
||||||
|
router:Router,
|
||||||
|
auto:boolean,
|
||||||
|
):void {
|
||||||
|
if (auto) { // h5端 vue-router自动触发 非自己调用触发
|
||||||
|
onTriggerEachHook(to, from, router, hookToggle[hookType], next)
|
||||||
|
} else {
|
||||||
|
userGuard(to, from, next)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
109
node_modules/uni-simple-router/src/helpers/mixins.ts
generated
vendored
Normal file
109
node_modules/uni-simple-router/src/helpers/mixins.ts
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { Router, routesMapRule, RoutesRule, pageTypeRule} from '../options/base';
|
||||||
|
import {createRouteMap} from '../helpers/createRouteMap'
|
||||||
|
import {buildVueRoutes, buildVueRouter} from '../H5/buildRouter'
|
||||||
|
import {proxyEachHook} from '../H5/proxyHook'
|
||||||
|
import {registerLoddingPage} from '../app/appPatch';
|
||||||
|
import { proxyPageHook } from '../public/page';
|
||||||
|
import { forceGuardEach } from '../public/methods';
|
||||||
|
import { assertParentChild, voidFun } from './utils';
|
||||||
|
import { getEnterPath } from '../applets/appletPatch';
|
||||||
|
import { mpPlatformReg } from './config';
|
||||||
|
|
||||||
|
let registerRouter:boolean = false;
|
||||||
|
let onloadProxyOk:boolean = false;
|
||||||
|
|
||||||
|
const appletProxy:{
|
||||||
|
app:boolean;
|
||||||
|
page:string;
|
||||||
|
} = {
|
||||||
|
app: false,
|
||||||
|
page: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMixins(Vue:any, router: Router):{
|
||||||
|
beforeCreate(this: any): void;
|
||||||
|
} | {
|
||||||
|
beforeCreate(): void;
|
||||||
|
} | {
|
||||||
|
onLaunch(): void;
|
||||||
|
} {
|
||||||
|
let platform = router.options.platform;
|
||||||
|
if (new RegExp(mpPlatformReg, 'g').test(platform)) {
|
||||||
|
platform = 'app-lets';
|
||||||
|
}
|
||||||
|
const toggleHooks = {
|
||||||
|
h5: {
|
||||||
|
beforeCreate(this: any): void {
|
||||||
|
if (this.$options.router) {
|
||||||
|
router.$route = this.$options.router; // 挂载vue-router到路由对象下
|
||||||
|
let vueRouteMap:RoutesRule[]|RoutesRule = [];
|
||||||
|
if (router.options.h5?.vueRouterDev) {
|
||||||
|
vueRouteMap = router.options.routes;
|
||||||
|
} else {
|
||||||
|
vueRouteMap = createRouteMap(router, this.$options.router.options.routes).finallyPathMap;
|
||||||
|
(router.routesMap as routesMapRule).vueRouteMap = vueRouteMap;
|
||||||
|
buildVueRoutes(router, vueRouteMap);
|
||||||
|
}
|
||||||
|
buildVueRouter(router, this.$options.router, vueRouteMap);
|
||||||
|
proxyEachHook(router, this.$options.router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'app-plus': {
|
||||||
|
beforeCreate(this: any): void {
|
||||||
|
if (!registerRouter) {
|
||||||
|
registerRouter = true;
|
||||||
|
proxyPageHook(this, router, 'app');
|
||||||
|
registerLoddingPage(router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'app-lets': {
|
||||||
|
beforeCreate(this: any): void {
|
||||||
|
// 保证这个函数不会被重写
|
||||||
|
const pluginMark = $npm_package_name;
|
||||||
|
voidFun(pluginMark);
|
||||||
|
|
||||||
|
let isProxy:boolean = true;
|
||||||
|
const pageType:pageTypeRule = this.$options.mpType;
|
||||||
|
|
||||||
|
if (onloadProxyOk) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageType === 'component') {
|
||||||
|
isProxy = assertParentChild(appletProxy['page'], this);
|
||||||
|
} else {
|
||||||
|
if (pageType === 'page') {
|
||||||
|
appletProxy[pageType] = getEnterPath(this, router);
|
||||||
|
router.enterPath = appletProxy[pageType]; // 我不确定在不同端是否都是同样的变现?可能有的为非绝对路径?
|
||||||
|
} else {
|
||||||
|
appletProxy[pageType] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isProxy) {
|
||||||
|
proxyPageHook(this, router, pageType);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(this: any):void{
|
||||||
|
// 保证这个函数不会被重写,否则必须在启动页写onLoad
|
||||||
|
const pluginMark = $npm_package_name;
|
||||||
|
voidFun(pluginMark);
|
||||||
|
|
||||||
|
if (!onloadProxyOk && assertParentChild(appletProxy['page'], this)) {
|
||||||
|
onloadProxyOk = true;
|
||||||
|
forceGuardEach(router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return toggleHooks[(platform as 'h5'|'app-plus'|'app-lets')];
|
||||||
|
}
|
||||||
|
export function initMixins(Vue: any, router: Router) {
|
||||||
|
const routesMap = createRouteMap(router, router.options.routes);
|
||||||
|
router.routesMap = routesMap; // 挂载自身路由表到路由对象下
|
||||||
|
// Vue.util.defineReactive(router, '_Route', createRoute(router, 19970806))
|
||||||
|
Vue.mixin({
|
||||||
|
...getMixins(Vue, router)
|
||||||
|
});
|
||||||
|
}
|
||||||
452
node_modules/uni-simple-router/src/helpers/utils.ts
generated
vendored
Normal file
452
node_modules/uni-simple-router/src/helpers/utils.ts
generated
vendored
Normal file
@@ -0,0 +1,452 @@
|
|||||||
|
import {H5Config, InstantiateConfig} from '../options/config';
|
||||||
|
import {RoutesRule, routesMapRule, routesMapKeysRule, Router, totalNextRoute, objectAny, navErrorRule, NAVTYPE, navRoute, uniBackApiRule, uniBackRule} from '../options/base';
|
||||||
|
import {baseConfig} from '../helpers/config';
|
||||||
|
import {ERRORHOOK} from '../public/hooks'
|
||||||
|
import {warnLock} from '../helpers/warn'
|
||||||
|
import { createRoute, navjump } from '../public/methods';
|
||||||
|
const Regexp = require('path-to-regexp');
|
||||||
|
|
||||||
|
export function voidFun(...args:any):void{}
|
||||||
|
|
||||||
|
export function def(
|
||||||
|
defObject:objectAny,
|
||||||
|
key:string,
|
||||||
|
getValue:Function
|
||||||
|
) {
|
||||||
|
Object.defineProperty(defObject, key, {
|
||||||
|
get() {
|
||||||
|
return getValue();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function timeOut(time:number):Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve();
|
||||||
|
}, time)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mergeConfig<T extends InstantiateConfig>(baseConfig: T, userConfig: T): T {
|
||||||
|
const config: {[key: string]: any} = Object.create(null);
|
||||||
|
const baseConfigKeys: Array<string> = Object.keys(baseConfig).concat(['resolveQuery', 'parseQuery']);
|
||||||
|
for (let i = 0; i < baseConfigKeys.length; i += 1) {
|
||||||
|
const key = baseConfigKeys[i];
|
||||||
|
if (userConfig[key] != null) {
|
||||||
|
if (userConfig[key].constructor === Object) {
|
||||||
|
config[key] = {
|
||||||
|
...baseConfig[key],
|
||||||
|
...userConfig[key]
|
||||||
|
};
|
||||||
|
} else if (key === 'routes') {
|
||||||
|
config[key] = [
|
||||||
|
...baseConfig[key],
|
||||||
|
...userConfig[key]
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
config[key] = userConfig[key];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
config[key] = baseConfig[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return config as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function notDeepClearNull<T>(object:T):T {
|
||||||
|
for (const key in object) {
|
||||||
|
if (object[key] == null) {
|
||||||
|
delete object[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRoutePath(route: RoutesRule, router:Router): {
|
||||||
|
finallyPath: string | string[];
|
||||||
|
aliasPath: string;
|
||||||
|
path: string;
|
||||||
|
alias: string | string[] | undefined;
|
||||||
|
} {
|
||||||
|
let finallyPath = route.aliasPath || route.alias || route.path;
|
||||||
|
if (router.options.platform !== 'h5') {
|
||||||
|
finallyPath = route.path
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
finallyPath,
|
||||||
|
aliasPath: route.aliasPath || route.path,
|
||||||
|
path: route.path,
|
||||||
|
alias: route.alias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertNewOptions<T extends InstantiateConfig>(
|
||||||
|
options: T
|
||||||
|
): T | never {
|
||||||
|
const {platform, routes} = options;
|
||||||
|
if (platform == null) {
|
||||||
|
throw new Error(`你在实例化路由时必须传递 'platform'`);
|
||||||
|
}
|
||||||
|
if (routes == null || routes.length === 0) {
|
||||||
|
throw new Error(`你在实例化路由时必须传递 routes 为空,这是无意义的。`);
|
||||||
|
}
|
||||||
|
if (options.platform === 'h5') {
|
||||||
|
if (options.h5?.vueRouterDev) {
|
||||||
|
baseConfig.routes = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const mergeOptions = mergeConfig<T>(baseConfig as T, options);
|
||||||
|
return mergeOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getWildcardRule(
|
||||||
|
router:Router,
|
||||||
|
msg?:navErrorRule
|
||||||
|
):RoutesRule|never {
|
||||||
|
const routesMap = (router.routesMap as routesMapRule);
|
||||||
|
const route = routesMap.finallyPathMap['*'];
|
||||||
|
if (route) { // 有写通配符
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
if (msg) {
|
||||||
|
ERRORHOOK[0](msg, router);
|
||||||
|
}
|
||||||
|
throw new Error(`当前路由表匹配规则已全部匹配完成,未找到满足的匹配规则。你可以使用 '*' 通配符捕捉最后的异常`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function notRouteTo404(
|
||||||
|
router:Router,
|
||||||
|
toRoute:RoutesRule|{
|
||||||
|
redirect:any;
|
||||||
|
path:string
|
||||||
|
},
|
||||||
|
parseToRule:totalNextRoute,
|
||||||
|
navType:NAVTYPE
|
||||||
|
):RoutesRule|totalNextRoute|never {
|
||||||
|
if (toRoute.path !== '*') { // 不是通配符 正常匹配成功
|
||||||
|
return (toRoute as RoutesRule);
|
||||||
|
}
|
||||||
|
|
||||||
|
const redirect = toRoute.redirect;
|
||||||
|
|
||||||
|
if (typeof redirect === 'undefined') {
|
||||||
|
throw new Error(` * 通配符必须配合 redirect 使用。redirect: string | Location | Function`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let newRoute = redirect;
|
||||||
|
if (typeof newRoute === 'function') {
|
||||||
|
newRoute = newRoute(parseToRule) as totalNextRoute;
|
||||||
|
}
|
||||||
|
const redirectRule = navjump(newRoute as totalNextRoute, router, navType, undefined, undefined, undefined, false);
|
||||||
|
return (redirectRule as totalNextRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function routesForMapRoute(
|
||||||
|
router: Router,
|
||||||
|
path: string,
|
||||||
|
mapArrayKey:Array<routesMapKeysRule>,
|
||||||
|
deepFind:boolean|undefined = false
|
||||||
|
):RoutesRule|never {
|
||||||
|
if (router.options.h5?.vueRouterDev) {
|
||||||
|
return {path}
|
||||||
|
}
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/252
|
||||||
|
const startPath = path.split('?')[0];
|
||||||
|
let wildcard = '';
|
||||||
|
const routesMap = (router.routesMap as routesMapRule);
|
||||||
|
for (let i = 0; i < mapArrayKey.length; i++) {
|
||||||
|
const mapKey = mapArrayKey[i];
|
||||||
|
const mapList = routesMap[mapKey];
|
||||||
|
for (const [key, value] of Object.entries(mapList)) {
|
||||||
|
if (key === '*') {
|
||||||
|
if (wildcard === '') {
|
||||||
|
wildcard = '*'
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const route:string|RoutesRule = value;
|
||||||
|
let rule:string = key;
|
||||||
|
if (getDataType<Array<string>|objectAny>(mapList) === '[object Array]') {
|
||||||
|
rule = (route as string);
|
||||||
|
}
|
||||||
|
const pathRule:RegExp = Regexp(rule);
|
||||||
|
const result = pathRule.exec(startPath);
|
||||||
|
if (result != null) {
|
||||||
|
if (getDataType<string|RoutesRule>(route) === '[object String]') {
|
||||||
|
return routesMap.finallyPathMap[(route as string)];
|
||||||
|
}
|
||||||
|
return (route as RoutesRule);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/302 2021-8-4 16:38:44
|
||||||
|
if (deepFind) {
|
||||||
|
return ({} as RoutesRule);
|
||||||
|
}
|
||||||
|
if (routesMap['aliasPathMap']) {
|
||||||
|
const results = routesForMapRoute(router, path, ['aliasPathMap'], true);
|
||||||
|
if (Object.keys(results).length > 0) {
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (wildcard !== '') {
|
||||||
|
return getWildcardRule(router);
|
||||||
|
}
|
||||||
|
throw new Error(`${path} 路径无法在路由表中找到!检查跳转路径及路由表`);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getDataType<T>(data:T):string {
|
||||||
|
return Object.prototype.toString.call(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function copyData<T>(object:T): T {
|
||||||
|
return JSON.parse(JSON.stringify(object))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getUniCachePage<T extends objectAny>(pageIndex?:number):T|[] {
|
||||||
|
const pages:T = getCurrentPages();
|
||||||
|
if (pageIndex == null) {
|
||||||
|
return pages
|
||||||
|
}
|
||||||
|
if (pages.length === 0) {
|
||||||
|
return pages;
|
||||||
|
}
|
||||||
|
const page = pages.reverse()[pageIndex];
|
||||||
|
if (page == null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
return page;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function urlToJson(url :string):{
|
||||||
|
path:string;
|
||||||
|
query:objectAny
|
||||||
|
} {
|
||||||
|
const query:objectAny = {};
|
||||||
|
const [path, params] = url.split('?');
|
||||||
|
if (params != null) {
|
||||||
|
const parr = params.split('&');
|
||||||
|
for (const i of parr) {
|
||||||
|
const arr = i.split('=');
|
||||||
|
query[arr[0]] = arr[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
path,
|
||||||
|
query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function forMatNextToFrom<T extends totalNextRoute>(
|
||||||
|
router:Router,
|
||||||
|
to:T,
|
||||||
|
from:T
|
||||||
|
):{
|
||||||
|
matTo:T;
|
||||||
|
matFrom: T;
|
||||||
|
} {
|
||||||
|
let [matTo, matFrom] = [to, from];
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
const {vueNext, vueRouterDev} = (router.options.h5 as H5Config);
|
||||||
|
if (!vueNext && !vueRouterDev) {
|
||||||
|
matTo = createRoute(router, undefined, matTo) as T;
|
||||||
|
matFrom = createRoute(router, undefined, matFrom) as T;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
matTo = createRoute(router, undefined, deepClone<T>(matTo)) as T;
|
||||||
|
matFrom = createRoute(router, undefined, deepClone<T>(matFrom)) as T;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
matTo: matTo,
|
||||||
|
matFrom: matFrom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function paramsToQuery(
|
||||||
|
router:Router,
|
||||||
|
toRule:totalNextRoute|string
|
||||||
|
):totalNextRoute|string {
|
||||||
|
if (router.options.platform === 'h5' && !router.options.h5?.paramsToQuery) {
|
||||||
|
return toRule;
|
||||||
|
}
|
||||||
|
if (getDataType<totalNextRoute|string>(toRule) === '[object Object]') {
|
||||||
|
const {name, params, ...moreToRule} = (toRule as totalNextRoute);
|
||||||
|
let paramsQuery = params;
|
||||||
|
if (router.options.platform !== 'h5' && paramsQuery == null) {
|
||||||
|
paramsQuery = {};
|
||||||
|
}
|
||||||
|
if (name != null && paramsQuery != null) {
|
||||||
|
let route = (router.routesMap as routesMapRule).nameMap[name];
|
||||||
|
if (route == null) {
|
||||||
|
route = getWildcardRule(router, { type: 2, msg: `命名路由为:${name} 的路由,无法在路由表中找到!`, toRule});
|
||||||
|
}
|
||||||
|
const {finallyPath} = getRoutePath(route, router);
|
||||||
|
if (finallyPath.includes(':')) { // 动态路由无法使用 paramsToQuery
|
||||||
|
ERRORHOOK[0]({ type: 2, msg: `动态路由:${finallyPath} 无法使用 paramsToQuery!`, toRule}, router);
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...moreToRule,
|
||||||
|
path: finallyPath as string,
|
||||||
|
query: paramsQuery
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toRule
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertDeepObject(object:objectAny):boolean {
|
||||||
|
let arrMark = null;
|
||||||
|
try {
|
||||||
|
arrMark = JSON.stringify(object).match(/\{|\[|\}|\]/g);
|
||||||
|
} catch (error) {
|
||||||
|
warnLock(`传递的参数解析对象失败。` + error)
|
||||||
|
}
|
||||||
|
if (arrMark == null) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (arrMark.length > 3) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function baseClone<
|
||||||
|
T extends {
|
||||||
|
[key:string]:any
|
||||||
|
}, K extends keyof T
|
||||||
|
>(
|
||||||
|
source:T,
|
||||||
|
target:Array<any>|objectAny
|
||||||
|
):Array<any>|objectAny|null {
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/292
|
||||||
|
// 小程序会将null解析为字符串 undefined 建议不要在参数中传递 null
|
||||||
|
if (source == null) {
|
||||||
|
target = source;
|
||||||
|
} else {
|
||||||
|
for (const key of Object.keys(source)) {
|
||||||
|
const dyKey = key as T[K];
|
||||||
|
if (source[key] === source) continue
|
||||||
|
if (typeof source[key] === 'object') {
|
||||||
|
target[dyKey] = getDataType<T>(source[key]) === '[object Array]' ? ([] as Array<any>) : ({} as objectAny)
|
||||||
|
target[dyKey] = baseClone(source[key], target[dyKey])
|
||||||
|
} else {
|
||||||
|
target[dyKey] = source[key]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deepClone<T>(source:T):T {
|
||||||
|
const __ob__ = getDataType<T>(source) === '[object Array]' ? ([] as Array<any>) : ({} as objectAny);
|
||||||
|
baseClone(source, __ob__)
|
||||||
|
return __ob__ as T
|
||||||
|
}
|
||||||
|
|
||||||
|
export function lockDetectWarn(
|
||||||
|
router:Router,
|
||||||
|
to:string|number|totalNextRoute|navRoute,
|
||||||
|
navType:NAVTYPE,
|
||||||
|
next:Function,
|
||||||
|
uniActualData:uniBackApiRule|uniBackRule|undefined = {},
|
||||||
|
passiveType?:'beforeHooks'| 'afterHooks'
|
||||||
|
):void{
|
||||||
|
if (passiveType === 'afterHooks') {
|
||||||
|
next();
|
||||||
|
} else {
|
||||||
|
const {detectBeforeLock} = router.options;
|
||||||
|
detectBeforeLock && detectBeforeLock(router, to, navType);
|
||||||
|
if (router.$lockStatus) {
|
||||||
|
(router.options.routerErrorEach as (error: navErrorRule, router:Router) => void)({
|
||||||
|
type: 2,
|
||||||
|
msg: '当前页面正在处于跳转状态,请稍后再进行跳转....',
|
||||||
|
NAVTYPE: navType,
|
||||||
|
uniActualData
|
||||||
|
}, router);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function assertParentChild(
|
||||||
|
parentPath:string,
|
||||||
|
vueVim:any,
|
||||||
|
):boolean {
|
||||||
|
while (vueVim.$parent != null) {
|
||||||
|
const mpPage = vueVim.$parent.$mp;
|
||||||
|
if (mpPage.page && mpPage.page.is === parentPath) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
vueVim = vueVim.$parent;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (vueVim.$mp.page.is === parentPath || vueVim.$mp.page.route === parentPath) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAbsolutePath(
|
||||||
|
path:string,
|
||||||
|
router:Router
|
||||||
|
):string|never {
|
||||||
|
const reg = /^\/?([^\?\s]+)(\?.+)?$/;
|
||||||
|
const trimPath = path.trim();
|
||||||
|
if (!reg.test(trimPath)) {
|
||||||
|
throw new Error(`【${path}】 路径错误,请提供完整的路径(10001)。`);
|
||||||
|
}
|
||||||
|
const paramsArray = trimPath.match(reg);
|
||||||
|
if (paramsArray == null) {
|
||||||
|
throw new Error(`【${path}】 路径错误,请提供完整的路径(10002)。`);
|
||||||
|
}
|
||||||
|
const query:string = paramsArray[2] || '';
|
||||||
|
if (/^\.\/[^\.]+/.test(trimPath)) { // 当前路径下
|
||||||
|
const navPath:string = router.currentRoute.path + path;
|
||||||
|
return navPath.replace(/[^\/]+\.\//, '');
|
||||||
|
}
|
||||||
|
const relative = paramsArray[1].replace(/\//g, `\\/`).replace(/\.\./g, `[^\\/]+`).replace(/\./g, '\\.');
|
||||||
|
const relativeReg = new RegExp(`^\\/${relative}$`);
|
||||||
|
const route = router.options.routes.filter(it => relativeReg.test(it.path));
|
||||||
|
if (route.length !== 1) {
|
||||||
|
throw new Error(`【${path}】 路径错误,尝试转成绝对路径失败,请手动转成绝对路径(10003)。`);
|
||||||
|
}
|
||||||
|
return route[0].path + query;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deepDecodeQuery(
|
||||||
|
query:objectAny
|
||||||
|
):objectAny {
|
||||||
|
const formatQuery:objectAny = getDataType<objectAny>(query) === '[object Array]' ? [] : {};
|
||||||
|
const keys = Object.keys(query);
|
||||||
|
for (let i = 0; i < keys.length; i++) {
|
||||||
|
const key = keys[i];
|
||||||
|
const it = query[key];
|
||||||
|
if (typeof it === 'string') {
|
||||||
|
try {
|
||||||
|
let json = JSON.parse(decodeURIComponent(it));
|
||||||
|
if (typeof json !== 'object') {
|
||||||
|
json = it;
|
||||||
|
}
|
||||||
|
formatQuery[key] = json;
|
||||||
|
} catch (error) {
|
||||||
|
try {
|
||||||
|
formatQuery[key] = decodeURIComponent(it)
|
||||||
|
} catch (error) {
|
||||||
|
formatQuery[key] = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeof it === 'object') {
|
||||||
|
const childQuery = deepDecodeQuery(it);
|
||||||
|
formatQuery[key] = childQuery
|
||||||
|
} else {
|
||||||
|
formatQuery[key] = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formatQuery
|
||||||
|
}
|
||||||
37
node_modules/uni-simple-router/src/helpers/warn.ts
generated
vendored
Normal file
37
node_modules/uni-simple-router/src/helpers/warn.ts
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
import {debuggerConfig, debuggerArrayConfig} from '../options/config'
|
||||||
|
import {Router} from '../options/base'
|
||||||
|
|
||||||
|
type callType='error'|'warn'|'log';
|
||||||
|
|
||||||
|
export function isLog(type:callType, dev:debuggerConfig, errText:any, enforce:boolean = false):boolean {
|
||||||
|
if (!enforce) {
|
||||||
|
const isObject = dev.toString() === '[object Object]';
|
||||||
|
if (dev === false) {
|
||||||
|
return false
|
||||||
|
} else if (isObject) {
|
||||||
|
if ((dev as debuggerArrayConfig)[type] === false) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console[type](errText);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
export function err(errText:any, router:Router, enforce?:boolean):void {
|
||||||
|
const dev = (router.options.debugger as debuggerConfig);
|
||||||
|
isLog('error', dev, errText, enforce);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function warn(errText:any, router:Router, enforce?:boolean):void {
|
||||||
|
const dev = (router.options.debugger as debuggerConfig);
|
||||||
|
isLog('warn', dev, errText, enforce);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function log(errText:any, router:Router, enforce?:boolean):void {
|
||||||
|
const dev = (router.options.debugger as debuggerConfig);
|
||||||
|
isLog('log', dev, errText, enforce);
|
||||||
|
}
|
||||||
|
export function warnLock(errText:any):void {
|
||||||
|
console.warn(errText);
|
||||||
|
}
|
||||||
11
node_modules/uni-simple-router/src/index.ts
generated
vendored
Normal file
11
node_modules/uni-simple-router/src/index.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
export * from './options/base'
|
||||||
|
export * from './options/config'
|
||||||
|
|
||||||
|
export {
|
||||||
|
runtimeQuit
|
||||||
|
} from './app/appPatch'
|
||||||
|
|
||||||
|
export {
|
||||||
|
RouterMount,
|
||||||
|
createRouter
|
||||||
|
} from './public/router'
|
||||||
245
node_modules/uni-simple-router/src/options/base.ts
generated
vendored
Normal file
245
node_modules/uni-simple-router/src/options/base.ts
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
|||||||
|
import {InstantiateConfig, LifeCycleConfig} from '../options/config';
|
||||||
|
|
||||||
|
export enum hookToggle{
|
||||||
|
'beforeHooks'='beforeEach',
|
||||||
|
'afterHooks'='afterEach',
|
||||||
|
'enterHooks'='beforeEnter'
|
||||||
|
}
|
||||||
|
export enum navtypeToggle{
|
||||||
|
'push'='navigateTo',
|
||||||
|
'replace'='redirectTo',
|
||||||
|
'replaceAll'='reLaunch',
|
||||||
|
'pushTab'='switchTab',
|
||||||
|
'back'='navigateBack'
|
||||||
|
}
|
||||||
|
export enum rewriteMethodToggle{
|
||||||
|
'navigateTo'='push',
|
||||||
|
'navigate'='push',
|
||||||
|
'redirectTo'='replace',
|
||||||
|
'reLaunch'='replaceAll',
|
||||||
|
'switchTab'='pushTab',
|
||||||
|
'navigateBack'='back',
|
||||||
|
}
|
||||||
|
export type proxyDepsRule={
|
||||||
|
resetIndex:Array<number>;
|
||||||
|
hooks: {
|
||||||
|
[key: number]:{
|
||||||
|
proxyHook:()=>void;
|
||||||
|
callHook:(enterPath:string)=>void;
|
||||||
|
resetHook: ()=>void
|
||||||
|
}
|
||||||
|
};
|
||||||
|
options: {[key: number]: Array<any>;};
|
||||||
|
};
|
||||||
|
export type backTypeRule='backbutton'|'navigateBack'
|
||||||
|
export type pageTypeRule='app'|'page'|'component';
|
||||||
|
export type vueHookNameRule='onLaunch'|'onShow'|'onHide'|'onError'|'onInit'|'onLoad'|'onReady'|'onUnload'|'onResize'|'created'|'beforeMount'|'mounted'|'beforeDestroy'|'destroyed'
|
||||||
|
export type reNavMethodRule='navigateTo'|'redirectTo'|'reLaunch'|'switchTab';
|
||||||
|
export type reNotNavMethodRule='navigateBack';
|
||||||
|
export type reloadNavRule=totalNextRoute | false | undefined|string;
|
||||||
|
export type hookListRule=Array<(router:Router, to:totalNextRoute, from: totalNextRoute, toRoute:RoutesRule,next:Function)=>void>
|
||||||
|
export type guardHookRule=(to: totalNextRoute, from: totalNextRoute, next:(rule?: navtoRule|false)=>void)=>void;
|
||||||
|
export type navRuleStatus= 0|1|2|3; //0: next(false) 1:next(unknownType) 2:加锁状态,禁止跳转 3:在获取页面栈的时候,页面栈不够level获取
|
||||||
|
export type proxyHookName='beforeHooks'|'afterHooks';
|
||||||
|
export type navMethodRule = Promise<void | undefined | navRuleStatus>;
|
||||||
|
export type objectAny={[propName: string]: any;};
|
||||||
|
export type NAVTYPE = 'push' | 'replace' | 'replaceAll' | 'pushTab'|'back';
|
||||||
|
export type startAnimationType =
|
||||||
|
| 'slide-in-right'
|
||||||
|
| 'slide-in-left'
|
||||||
|
| 'slide-in-top'
|
||||||
|
| 'slide-in-bottom'
|
||||||
|
| 'pop-in'
|
||||||
|
| 'fade-in'
|
||||||
|
| 'zoom-out'
|
||||||
|
| 'zoom-fade-out'
|
||||||
|
| 'none';
|
||||||
|
export type endAnimationType =
|
||||||
|
| 'slide-out-right'
|
||||||
|
| 'slide-out-left'
|
||||||
|
| 'slide-out-top'
|
||||||
|
| 'slide-out-bottom'
|
||||||
|
| 'pop-out'
|
||||||
|
| 'fade-out'
|
||||||
|
| 'zoom-in'
|
||||||
|
| 'zoom-fade-in'
|
||||||
|
| 'none';
|
||||||
|
|
||||||
|
export type vueOptionRule = {
|
||||||
|
[propName in vueHookNameRule]: Array<Function> | undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 跳转api时,传递的跳转规则
|
||||||
|
export interface navtoRule {
|
||||||
|
NAVTYPE?: NAVTYPE; // 跳转类型 v1.1.0+
|
||||||
|
path?: string; // 跳转路径 绝对路径
|
||||||
|
name?: string | undefined; // 跳转路径名称
|
||||||
|
query?: objectAny; // 跳转使用path时 query包含需要传递的参数
|
||||||
|
params?: objectAny; // 跳转使用name时 params包含需要传递的参数
|
||||||
|
animationType?: startAnimationType|endAnimationType;
|
||||||
|
animationDuration?: number;
|
||||||
|
events?: objectAny;
|
||||||
|
success?: Function;
|
||||||
|
fail?: Function;
|
||||||
|
complete?: Function;
|
||||||
|
}
|
||||||
|
// h5 next管道函数中传递的from及to对象
|
||||||
|
export interface h5NextRule {
|
||||||
|
fullPath?: string | undefined;
|
||||||
|
hash?: string | undefined;
|
||||||
|
matched?: Array<object>;
|
||||||
|
meta?: object;
|
||||||
|
name?: undefined | string;
|
||||||
|
type?: undefined | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface totalNextRoute extends h5NextRule, navtoRule {
|
||||||
|
path:string;
|
||||||
|
delta?:number;
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
export interface navRoute extends h5NextRule, navtoRule {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始切换窗口动画 app端可用
|
||||||
|
export interface startAnimationRule {
|
||||||
|
animationType?: startAnimationType; // 窗口关闭的动画效果
|
||||||
|
animationDuration?: number; // 窗口关闭动画的持续时间
|
||||||
|
}
|
||||||
|
// 关闭窗口时的动画 app端可用
|
||||||
|
export interface endAnimationRule {
|
||||||
|
animationType?: endAnimationType; // 窗口关闭的动画效果
|
||||||
|
animationDuration?: number; // 窗口关闭动画的持续时间
|
||||||
|
}
|
||||||
|
export interface hookObjectRule {
|
||||||
|
options:Array<any>;
|
||||||
|
hook:Function;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 执行路由跳转失败或者 next(false) 时走的规则
|
||||||
|
export interface navErrorRule {
|
||||||
|
type: navRuleStatus;
|
||||||
|
msg: string;
|
||||||
|
to?:totalNextRoute;
|
||||||
|
from?:totalNextRoute;
|
||||||
|
nextTo?:any;
|
||||||
|
[propName:string]:any;
|
||||||
|
}
|
||||||
|
// uni原生api跳转时的规则
|
||||||
|
export interface uniNavApiRule {
|
||||||
|
url: string;
|
||||||
|
openType?:'appLaunch',
|
||||||
|
query?:objectAny;
|
||||||
|
path?:string;
|
||||||
|
delta?:number;
|
||||||
|
detail?:{[propName:string]:any};
|
||||||
|
animationType?:startAnimationType;
|
||||||
|
animationDuration?:number;
|
||||||
|
events?:{[propName:string]:any};
|
||||||
|
success?:Function;
|
||||||
|
fail?:Function;
|
||||||
|
complete?:Function;
|
||||||
|
animation?:{
|
||||||
|
animationType?:startAnimationType;
|
||||||
|
animationDuration?:number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface originMixins extends uniNavApiRule{
|
||||||
|
BACKTYPE:''|backTypeRule
|
||||||
|
}
|
||||||
|
|
||||||
|
// uni-app 原始返回api 回调参数
|
||||||
|
export interface uniBackRule{
|
||||||
|
from:backTypeRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface uniBackApiRule{
|
||||||
|
delta?: number;
|
||||||
|
animationDuration?: number;
|
||||||
|
animationType?:endAnimationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type routesMapKeysRule=
|
||||||
|
'finallyPathList'|
|
||||||
|
'finallyPathMap'|
|
||||||
|
'aliasPathMap'|
|
||||||
|
'pathMap'|
|
||||||
|
'nameMap'|
|
||||||
|
'vueRouteMap';
|
||||||
|
|
||||||
|
export interface routesMapRule{
|
||||||
|
[key:string]:any;
|
||||||
|
finallyPathList: Array<string>;
|
||||||
|
finallyPathMap:RoutesRule;
|
||||||
|
aliasPathMap: RoutesRule;
|
||||||
|
pathMap: RoutesRule;
|
||||||
|
nameMap:RoutesRule,
|
||||||
|
vueRouteMap:objectAny
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface routeRule{
|
||||||
|
name:string|undefined;
|
||||||
|
meta:objectAny;
|
||||||
|
path:string;
|
||||||
|
query:objectAny;
|
||||||
|
params:objectAny;
|
||||||
|
fullPath:string;
|
||||||
|
NAVTYPE:NAVTYPE|'';
|
||||||
|
BACKTYPE?:backTypeRule|''; // v2.0.5 +
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface RoutesRule {
|
||||||
|
path: string; // pages.json中的path 必须加上 '/' 开头
|
||||||
|
component?: object; // H5端可用
|
||||||
|
name?: string; // 命名路由
|
||||||
|
components?: object; // 命名视图组件,H5端可用
|
||||||
|
redirect?: string | Function; // H5端可用
|
||||||
|
props?: boolean | object | Function; // H5端可用
|
||||||
|
aliasPath?: string; // h5端 设置一个别名路径来替换 uni-app的默认路径
|
||||||
|
alias?: string | Array<string>; // H5端可用
|
||||||
|
children?: Array<RoutesRule>; // 嵌套路由,H5端可用
|
||||||
|
beforeEnter?:guardHookRule; // 路由元守卫
|
||||||
|
meta?: any; // 其他格外参数
|
||||||
|
[propName: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Router {
|
||||||
|
[key:string]:any;
|
||||||
|
readonly lifeCycle: LifeCycleConfig;
|
||||||
|
readonly options: InstantiateConfig;
|
||||||
|
$lockStatus:boolean;
|
||||||
|
$route: object | null;
|
||||||
|
enterPath:string;
|
||||||
|
Vue:any;
|
||||||
|
appMain:{
|
||||||
|
NAVTYPE:reNavMethodRule|reNotNavMethodRule,
|
||||||
|
path:string
|
||||||
|
}|{};
|
||||||
|
proxyHookDeps: proxyDepsRule;
|
||||||
|
routesMap: routesMapRule|{};
|
||||||
|
mount: Array<{app: any; el: string}>;
|
||||||
|
install(Vue: any): void;
|
||||||
|
push(to: totalNextRoute|navRoute | string,from?:totalNextRoute): void; // 动态的导航到一个新 URL 保留浏览历史
|
||||||
|
replace(to: totalNextRoute|navRoute | string,from?:totalNextRoute): void; // 动态的导航到一个新 URL 关闭当前页面,跳转到的某个页面。
|
||||||
|
replaceAll(to: totalNextRoute|navRoute | string,from?:totalNextRoute): void; // 动态的导航到一个新 URL 关闭所有页面,打开到应用内的某个页面
|
||||||
|
pushTab(to: totalNextRoute|navRoute | string,from?:totalNextRoute): void; // 动态的导航到一个新 url 关闭所有页面,打开到应用内的某个tab
|
||||||
|
back(level:number|undefined,origin?:uniBackRule|uniBackApiRule):void;
|
||||||
|
forceGuardEach(navType:NAVTYPE|undefined,forceNav:boolean):void; //强制触发当前守卫
|
||||||
|
beforeEach(userGuard:guardHookRule): void; // 添加全局前置路由守卫
|
||||||
|
afterEach(userGuard:(to: totalNextRoute, from: totalNextRoute)=>void): void; // 添加全局后置路由守卫
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export type PromiseResolve=(value?: void | PromiseLike<void> | undefined) => void;
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
|
declare module 'vue/types/vue' {
|
||||||
|
interface Vue {
|
||||||
|
$Router: Router;
|
||||||
|
$Route: routeRule;
|
||||||
|
}
|
||||||
|
}
|
||||||
57
node_modules/uni-simple-router/src/options/config.ts
generated
vendored
Normal file
57
node_modules/uni-simple-router/src/options/config.ts
generated
vendored
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import {startAnimationRule, hookListRule, RoutesRule, navtoRule, navErrorRule, Router, objectAny, NAVTYPE, totalNextRoute, navRoute} from './base';
|
||||||
|
|
||||||
|
export type debuggerConfig=boolean|debuggerArrayConfig;
|
||||||
|
export type platformRule='h5'|'app-plus'|'app-lets'|'mp-weixin'|'mp-baidu'|'mp-alipay'|'mp-toutiao'|'mp-qq'|'mp-360';
|
||||||
|
|
||||||
|
export interface H5Config {
|
||||||
|
paramsToQuery?: boolean; // h5端上通过params传参时规则是vue-router 刷新会丢失 开启此开关将变成?连接的方式
|
||||||
|
vueRouterDev?: boolean; // 完全使用采用vue-router的开发模式
|
||||||
|
vueNext?: boolean; // 在next管道函数中是否获取vueRouter next的原本参数
|
||||||
|
mode?: string;
|
||||||
|
base?: string;
|
||||||
|
linkActiveClass?: string;
|
||||||
|
linkExactActiveClass?: string;
|
||||||
|
scrollBehavior?: Function;
|
||||||
|
fallback?: boolean;
|
||||||
|
}
|
||||||
|
export interface AppConfig {
|
||||||
|
registerLoadingPage?:boolean; // 是否注册过渡加载页 +v2.0.6
|
||||||
|
loadingPageStyle?: () => object; // 当前等待页面的样式 必须返回一个json
|
||||||
|
loadingPageHook?: (view:any)=>void; // 刚刚打开页面处于等待状态,会触发此函数
|
||||||
|
launchedHook?:()=>void; // 首次启动app完成
|
||||||
|
animation?: startAnimationRule; // 页面切换动画
|
||||||
|
}
|
||||||
|
export interface appletConfig {
|
||||||
|
animationDuration?:number; // 页面切换时间,有助于路由锁精准解锁
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface debuggerArrayConfig{
|
||||||
|
error?:boolean;
|
||||||
|
warn?:boolean;
|
||||||
|
log?:boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InstantiateConfig {
|
||||||
|
[key:string]:any;
|
||||||
|
keepUniOriginNav?:boolean; // 重写uni-app的跳转方法;关闭后使用uni-app的原始方法跳转和插件api跳转等同
|
||||||
|
platform:platformRule; // 当前运行平台
|
||||||
|
h5?: H5Config;
|
||||||
|
APP?: AppConfig;
|
||||||
|
applet?:appletConfig;
|
||||||
|
debugger?: debuggerConfig; // 是否处于开发阶段 设置为true则打印日志
|
||||||
|
routerBeforeEach?: (to:navtoRule, from:navtoRule, next:(rule?: navtoRule|false)=>void) => void; // router 前置路由函数 每次触发跳转前先会触发此函数
|
||||||
|
routerAfterEach?: (to:navtoRule, from:navtoRule, next?: Function) => void; // router 后置路由函数 每次触发跳转后会触发此函数
|
||||||
|
routerErrorEach?: (error: navErrorRule, router:Router) => void;
|
||||||
|
resolveQuery?:(jsonQuery:objectAny)=>objectAny; // 跳转之前把参数传递给此函数、返回最终的数据!有此函数不走默认方法
|
||||||
|
parseQuery?:(jsonQuery:objectAny)=>objectAny; // 读取值之前把参数传递给此函数,返回最终的数据!有此函数不走默认方法
|
||||||
|
detectBeforeLock?:(router:Router, to:string|number|totalNextRoute|navRoute, navType:NAVTYPE)=>void; // 在检测路由锁之前触发的函数
|
||||||
|
routes: RoutesRule[];
|
||||||
|
}
|
||||||
|
export interface LifeCycleConfig{
|
||||||
|
beforeHooks: hookListRule;
|
||||||
|
afterHooks: hookListRule;
|
||||||
|
routerBeforeHooks: hookListRule;
|
||||||
|
routerAfterHooks: hookListRule;
|
||||||
|
routerErrorHooks: Array<(error:navErrorRule, router:Router)=>void>;
|
||||||
|
}
|
||||||
|
|
||||||
177
node_modules/uni-simple-router/src/public/hooks.ts
generated
vendored
Normal file
177
node_modules/uni-simple-router/src/public/hooks.ts
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
import {
|
||||||
|
Router,
|
||||||
|
hookListRule,
|
||||||
|
navtoRule,
|
||||||
|
reloadNavRule,
|
||||||
|
totalNextRoute,
|
||||||
|
hookToggle,
|
||||||
|
NAVTYPE,
|
||||||
|
navErrorRule,
|
||||||
|
objectAny
|
||||||
|
} from '../options/base';
|
||||||
|
import {
|
||||||
|
routesForMapRoute,
|
||||||
|
getDataType,
|
||||||
|
forMatNextToFrom,
|
||||||
|
getUniCachePage,
|
||||||
|
voidFun
|
||||||
|
} from '../helpers/utils'
|
||||||
|
import { navjump } from './methods';
|
||||||
|
import { proxyH5Mount } from '../H5/proxyHook';
|
||||||
|
import { tabIndexSelect } from '../app/appPatch';
|
||||||
|
|
||||||
|
export const ERRORHOOK:Array<(error:navErrorRule, router:Router)=>void> = [
|
||||||
|
(error, router) => router.lifeCycle.routerErrorHooks[0](error, router)
|
||||||
|
]
|
||||||
|
export const HOOKLIST: hookListRule = [
|
||||||
|
(router, to, from, toRoute, next) => callHook(router.lifeCycle.routerBeforeHooks[0], to, from, router, next),
|
||||||
|
(router, to, from, toRoute, next) => callBeforeRouteLeave(router, to, from, next),
|
||||||
|
(router, to, from, toRoute, next) => callHook(router.lifeCycle.beforeHooks[0], to, from, router, next),
|
||||||
|
(router, to, from, toRoute, next) => callHook(toRoute.beforeEnter, to, from, router, next),
|
||||||
|
(router, to, from, toRoute, next) => callHook(router.lifeCycle.afterHooks[0], to, from, router, next, false),
|
||||||
|
(router, to, from, toRoute, next) => {
|
||||||
|
router.$lockStatus = false;
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
proxyH5Mount(router);
|
||||||
|
}
|
||||||
|
return callHook(router.lifeCycle.routerAfterHooks[0], to, from, router, next, false)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
export function callBeforeRouteLeave(
|
||||||
|
router:Router,
|
||||||
|
to:totalNextRoute,
|
||||||
|
from:totalNextRoute,
|
||||||
|
resolve:Function
|
||||||
|
):void {
|
||||||
|
const page = getUniCachePage<objectAny>(0);
|
||||||
|
let beforeRouteLeave;
|
||||||
|
if (Object.keys(page).length > 0) {
|
||||||
|
let leaveHooks:Array<Function>|undefined|Function;
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
leaveHooks = (page as objectAny).$options.beforeRouteLeave;
|
||||||
|
} else {
|
||||||
|
if ((page as objectAny).$vm != null) {
|
||||||
|
leaveHooks = (page as objectAny).$vm.$options.beforeRouteLeave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (getDataType<Array<Function>>((leaveHooks as Array<Function>))) {
|
||||||
|
case '[object Array]': // h5端表现
|
||||||
|
beforeRouteLeave = (leaveHooks as Array<Function>)[0];
|
||||||
|
beforeRouteLeave = beforeRouteLeave.bind(page)
|
||||||
|
break;
|
||||||
|
case '[object Function]': // 目前app端表现
|
||||||
|
beforeRouteLeave = (leaveHooks as Function).bind((page as objectAny).$vm);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return callHook(beforeRouteLeave, to, from, router, resolve);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function callHook(
|
||||||
|
hook:Function|undefined,
|
||||||
|
to:totalNextRoute,
|
||||||
|
from: totalNextRoute,
|
||||||
|
router:Router,
|
||||||
|
resolve:Function,
|
||||||
|
hookAwait:boolean|undefined = true
|
||||||
|
):void {
|
||||||
|
if (hook != null && hook instanceof Function) {
|
||||||
|
if (hookAwait === true) {
|
||||||
|
hook(to, from, resolve, router, false);
|
||||||
|
} else {
|
||||||
|
hook(to, from, () => {}, router, false);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function onTriggerEachHook(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from: totalNextRoute,
|
||||||
|
router:Router,
|
||||||
|
hookType:hookToggle,
|
||||||
|
next:(rule?: navtoRule|false)=>void,
|
||||||
|
):void {
|
||||||
|
let callHookList:hookListRule = [];
|
||||||
|
switch (hookType) {
|
||||||
|
case 'beforeEach':
|
||||||
|
callHookList = HOOKLIST.slice(0, 3);
|
||||||
|
break;
|
||||||
|
case 'afterEach':
|
||||||
|
callHookList = HOOKLIST.slice(4);
|
||||||
|
break
|
||||||
|
case 'beforeEnter':
|
||||||
|
callHookList = HOOKLIST.slice(3, 4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
transitionTo(router, to, from, 'push', callHookList, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transitionTo(
|
||||||
|
router:Router,
|
||||||
|
to:totalNextRoute,
|
||||||
|
from: totalNextRoute,
|
||||||
|
navType:NAVTYPE,
|
||||||
|
callHookList:hookListRule,
|
||||||
|
hookCB:Function
|
||||||
|
) :void{
|
||||||
|
const {matTo, matFrom} = forMatNextToFrom<totalNextRoute>(router, to, from);
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
loopCallHook(callHookList, 0, hookCB, router, matTo, matFrom, navType);
|
||||||
|
} else {
|
||||||
|
loopCallHook(callHookList.slice(0, 4), 0, () => {
|
||||||
|
hookCB(() => { // 非H5端等他跳转完才触发最后两个生命周期
|
||||||
|
loopCallHook(callHookList.slice(4), 0, voidFun, router, matTo, matFrom, navType);
|
||||||
|
});
|
||||||
|
}, router, matTo, matFrom, navType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loopCallHook(
|
||||||
|
hooks:hookListRule,
|
||||||
|
index:number,
|
||||||
|
next:Function,
|
||||||
|
router:Router,
|
||||||
|
matTo:totalNextRoute,
|
||||||
|
matFrom: totalNextRoute,
|
||||||
|
navType:NAVTYPE,
|
||||||
|
): void|Function {
|
||||||
|
const toRoute = routesForMapRoute(router, matTo.path, ['finallyPathMap', 'pathMap']);
|
||||||
|
if (hooks.length - 1 < index) {
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
const hook = hooks[index];
|
||||||
|
const errHook = ERRORHOOK[0];
|
||||||
|
hook(router, matTo, matFrom, toRoute, (nextTo:reloadNavRule) => {
|
||||||
|
if (router.options.platform === 'app-plus') {
|
||||||
|
if (nextTo === false || (typeof nextTo === 'string' || typeof nextTo === 'object')) {
|
||||||
|
tabIndexSelect(matTo, matFrom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextTo === false) {
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
next(false);
|
||||||
|
}
|
||||||
|
errHook({ type: 0, msg: '管道函数传递 false 导航被终止!', matTo, matFrom, nextTo }, router)
|
||||||
|
} else if (typeof nextTo === 'string' || typeof nextTo === 'object') {
|
||||||
|
let newNavType = navType;
|
||||||
|
let newNextTo = nextTo;
|
||||||
|
if (typeof nextTo === 'object') {
|
||||||
|
const {NAVTYPE: type, ...moreTo} = nextTo;
|
||||||
|
newNextTo = moreTo;
|
||||||
|
if (type != null) {
|
||||||
|
newNavType = type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
navjump(newNextTo, router, newNavType, {from: matFrom, next})
|
||||||
|
} else if (nextTo == null) {
|
||||||
|
index++;
|
||||||
|
loopCallHook(hooks, index, next, router, matTo, matFrom, navType)
|
||||||
|
} else {
|
||||||
|
errHook({ type: 1, msg: '管道函数传递未知类型,无法被识别。导航被终止!', matTo, matFrom, nextTo }, router)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
258
node_modules/uni-simple-router/src/public/methods.ts
generated
vendored
Normal file
258
node_modules/uni-simple-router/src/public/methods.ts
generated
vendored
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
import {
|
||||||
|
NAVTYPE,
|
||||||
|
Router,
|
||||||
|
totalNextRoute,
|
||||||
|
objectAny,
|
||||||
|
routeRule,
|
||||||
|
reNavMethodRule,
|
||||||
|
rewriteMethodToggle,
|
||||||
|
navtypeToggle,
|
||||||
|
navErrorRule,
|
||||||
|
uniBackApiRule,
|
||||||
|
uniBackRule,
|
||||||
|
navRoute
|
||||||
|
} from '../options/base'
|
||||||
|
import {
|
||||||
|
queryPageToMap,
|
||||||
|
resolveQuery,
|
||||||
|
parseQuery
|
||||||
|
} from './query'
|
||||||
|
import {
|
||||||
|
voidFun,
|
||||||
|
paramsToQuery,
|
||||||
|
getUniCachePage,
|
||||||
|
routesForMapRoute,
|
||||||
|
copyData,
|
||||||
|
lockDetectWarn,
|
||||||
|
getDataType,
|
||||||
|
notRouteTo404,
|
||||||
|
deepDecodeQuery
|
||||||
|
} from '../helpers/utils'
|
||||||
|
import { transitionTo } from './hooks';
|
||||||
|
import {createFullPath, createToFrom} from '../public/page'
|
||||||
|
import {HOOKLIST} from './hooks'
|
||||||
|
|
||||||
|
export function lockNavjump(
|
||||||
|
to:string|totalNextRoute|navRoute,
|
||||||
|
router:Router,
|
||||||
|
navType:NAVTYPE,
|
||||||
|
forceNav?:boolean,
|
||||||
|
animation?:uniBackApiRule|uniBackRule
|
||||||
|
):void{
|
||||||
|
lockDetectWarn(router, to, navType, () => {
|
||||||
|
if (router.options.platform !== 'h5') {
|
||||||
|
router.$lockStatus = true;
|
||||||
|
}
|
||||||
|
navjump(to as totalNextRoute, router, navType, undefined, forceNav, animation);
|
||||||
|
}, animation);
|
||||||
|
}
|
||||||
|
export function navjump(
|
||||||
|
to:string|totalNextRoute,
|
||||||
|
router:Router,
|
||||||
|
navType:NAVTYPE,
|
||||||
|
nextCall?:{
|
||||||
|
from:totalNextRoute;
|
||||||
|
next:Function;
|
||||||
|
},
|
||||||
|
forceNav?:boolean,
|
||||||
|
animation?:uniBackApiRule|uniBackRule,
|
||||||
|
callHook:boolean|undefined = true
|
||||||
|
) :void|never|totalNextRoute {
|
||||||
|
if (navType === 'back') {
|
||||||
|
let level:number = 1;
|
||||||
|
if (typeof to === 'string') {
|
||||||
|
level = +to;
|
||||||
|
} else {
|
||||||
|
level = to.delta || 1;
|
||||||
|
}
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
(router.$route as any).go(-level);
|
||||||
|
|
||||||
|
// Fixe https://github.com/SilurianYang/uni-simple-router/issues/266 2021年6月3日11:14:38
|
||||||
|
// @ts-ignore
|
||||||
|
const success = (animation || {success: voidFun}).success || voidFun;
|
||||||
|
// @ts-ignore
|
||||||
|
const complete = (animation || {complete: voidFun}).complete || voidFun;
|
||||||
|
success({errMsg: 'navigateBack:ok'});
|
||||||
|
complete({errMsg: 'navigateBack:ok'});
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
to = backOptionsBuild(router, level, animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const {rule} = queryPageToMap(to, router);
|
||||||
|
rule.type = navtypeToggle[navType];
|
||||||
|
const toRule = paramsToQuery(router, rule);
|
||||||
|
let parseToRule = resolveQuery(toRule as totalNextRoute, router);
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
if (navType !== 'push') {
|
||||||
|
navType = 'replace';
|
||||||
|
}
|
||||||
|
if (nextCall != null) { // next 管道函数拦截时 直接next即可
|
||||||
|
nextCall.next({
|
||||||
|
replace: navType !== 'push',
|
||||||
|
...parseToRule
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Fixe https://github.com/SilurianYang/uni-simple-router/issues/240 2021年3月7日14:45:36
|
||||||
|
if (navType === 'push' && Reflect.has(parseToRule, 'events')) {
|
||||||
|
if (Reflect.has(parseToRule, 'name')) {
|
||||||
|
throw new Error(`在h5端上使用 'push'、'navigateTo' 跳转时,如果包含 events 不允许使用 name 跳转,因为 name 实现了动态路由。请更换为 path 或者 url 跳转!`);
|
||||||
|
} else {
|
||||||
|
uni['navigateTo'](parseToRule, true, voidFun, forceNav);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
(router.$route as any)[navType](parseToRule, (parseToRule as totalNextRoute).success || voidFun, (parseToRule as totalNextRoute).fail || voidFun)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let from:totalNextRoute = {path: ''};
|
||||||
|
if (nextCall == null) {
|
||||||
|
let toRoute = routesForMapRoute(router, parseToRule.path, ['finallyPathMap', 'pathMap']);
|
||||||
|
toRoute = notRouteTo404(router, toRoute, parseToRule, navType);
|
||||||
|
parseToRule = { ...toRoute, ...{params: {}}, ...parseToRule, ...{path: toRoute.path} }
|
||||||
|
from = createToFrom(parseToRule, router);
|
||||||
|
} else {
|
||||||
|
from = nextCall.from;
|
||||||
|
}
|
||||||
|
createFullPath(parseToRule, from);
|
||||||
|
if (callHook === false) {
|
||||||
|
return parseToRule;
|
||||||
|
}
|
||||||
|
transitionTo(router, parseToRule, from, navType, HOOKLIST, function(
|
||||||
|
callOkCb:Function
|
||||||
|
):void {
|
||||||
|
uni[navtypeToggle[navType]](parseToRule, true, callOkCb, forceNav);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function backOptionsBuild(
|
||||||
|
router:Router,
|
||||||
|
level:number,
|
||||||
|
animation:uniBackApiRule|uniBackRule|undefined = {},
|
||||||
|
):totalNextRoute {
|
||||||
|
const toRule = createRoute(router, level, undefined, {NAVTYPE: 'back', ...animation});
|
||||||
|
const navjumpRule:totalNextRoute = {
|
||||||
|
...animation,
|
||||||
|
path: toRule.path,
|
||||||
|
query: toRule.query,
|
||||||
|
delta: level
|
||||||
|
}
|
||||||
|
if (getDataType<any>(animation) === '[object Object]') {
|
||||||
|
const {animationDuration, animationType} = (animation as uniBackApiRule)
|
||||||
|
if (animationDuration != null) {
|
||||||
|
navjumpRule.animationDuration = animationDuration;
|
||||||
|
}
|
||||||
|
if (animationType != null) {
|
||||||
|
navjumpRule.animationType = animationType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {from} = (animation as uniBackRule)
|
||||||
|
if (from != null) {
|
||||||
|
navjumpRule.BACKTYPE = from;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return navjumpRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function forceGuardEach(
|
||||||
|
router:Router,
|
||||||
|
navType:NAVTYPE|undefined = 'replaceAll',
|
||||||
|
forceNav:undefined|boolean = false
|
||||||
|
):void|never {
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
throw new Error(`在h5端上使用:forceGuardEach 是无意义的,目前 forceGuardEach 仅支持在非h5端上使用`);
|
||||||
|
}
|
||||||
|
const currentPage = getUniCachePage<objectAny>(0);
|
||||||
|
if (Object.keys(currentPage).length === 0) {
|
||||||
|
(router.options.routerErrorEach as (error: navErrorRule, router:Router) => void)({
|
||||||
|
type: 3,
|
||||||
|
NAVTYPE: navType,
|
||||||
|
uniActualData: {},
|
||||||
|
level: 0,
|
||||||
|
msg: `不存在的页面栈,请确保有足够的页面可用,当前 level:0`
|
||||||
|
}, router);
|
||||||
|
}
|
||||||
|
const {route, options} = currentPage as objectAny;
|
||||||
|
lockNavjump({
|
||||||
|
path: `/${route}`,
|
||||||
|
query: deepDecodeQuery(options || {})
|
||||||
|
}, router, navType, forceNav);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRoute(
|
||||||
|
router:Router,
|
||||||
|
level:number|undefined = 0,
|
||||||
|
orignRule?:totalNextRoute,
|
||||||
|
uniActualData:objectAny|undefined = {},
|
||||||
|
):routeRule|never {
|
||||||
|
const route:routeRule = {
|
||||||
|
name: '',
|
||||||
|
meta: {},
|
||||||
|
path: '',
|
||||||
|
fullPath: '',
|
||||||
|
NAVTYPE: '',
|
||||||
|
query: {},
|
||||||
|
params: {},
|
||||||
|
BACKTYPE: (orignRule || {BACKTYPE: ''}).BACKTYPE || '' // v2.0.5 +
|
||||||
|
};
|
||||||
|
|
||||||
|
if (level === 19970806) { // 首次构建响应式 页面不存在 直接返回
|
||||||
|
return route
|
||||||
|
}
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
let vueRoute:totalNextRoute = {path: ''};
|
||||||
|
if (orignRule != null) {
|
||||||
|
vueRoute = orignRule;
|
||||||
|
} else {
|
||||||
|
vueRoute = (router.$route as objectAny).currentRoute;
|
||||||
|
}
|
||||||
|
const matRouteParams = copyData(vueRoute.params as objectAny);
|
||||||
|
delete matRouteParams.__id__;
|
||||||
|
const toQuery = parseQuery({...matRouteParams, ...copyData(vueRoute.query as objectAny)}, router);
|
||||||
|
vueRoute = {...vueRoute, query: toQuery}
|
||||||
|
route.path = vueRoute.path;
|
||||||
|
route.fullPath = vueRoute.fullPath || '';
|
||||||
|
route.query = deepDecodeQuery(vueRoute.query || {});
|
||||||
|
route.NAVTYPE = rewriteMethodToggle[vueRoute.type as reNavMethodRule || 'reLaunch'];
|
||||||
|
} else {
|
||||||
|
let appPage:objectAny = {};
|
||||||
|
if (orignRule != null) {
|
||||||
|
appPage = {...orignRule, openType: orignRule.type};
|
||||||
|
} else {
|
||||||
|
const page = getUniCachePage<objectAny>(level);
|
||||||
|
if (Object.keys(page).length === 0) {
|
||||||
|
const {NAVTYPE: _NAVTYPE, ..._args} = uniActualData;
|
||||||
|
const errorMsg:string = `不存在的页面栈,请确保有足够的页面可用,当前 level:${level}`;
|
||||||
|
(router.options.routerErrorEach as (error: navErrorRule, router:Router) => void)({
|
||||||
|
type: 3,
|
||||||
|
msg: errorMsg,
|
||||||
|
NAVTYPE: _NAVTYPE,
|
||||||
|
level,
|
||||||
|
uniActualData: _args
|
||||||
|
}, router);
|
||||||
|
throw new Error(errorMsg);
|
||||||
|
}
|
||||||
|
// Fixes: https://github.com/SilurianYang/uni-simple-router/issues/196
|
||||||
|
const pageOptions:objectAny = (page as objectAny).options || {};
|
||||||
|
appPage = {
|
||||||
|
...(page as objectAny).$page || {},
|
||||||
|
query: deepDecodeQuery(pageOptions),
|
||||||
|
fullPath: decodeURIComponent(((page as objectAny).$page || {}).fullPath || '/' + (page as objectAny).route)
|
||||||
|
}
|
||||||
|
if (router.options.platform !== 'app-plus') {
|
||||||
|
appPage.path = `/${(page as objectAny).route}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const openType:reNavMethodRule|'navigateBack' = appPage.openType;
|
||||||
|
route.query = appPage.query;
|
||||||
|
route.path = appPage.path;
|
||||||
|
route.fullPath = appPage.fullPath;
|
||||||
|
route.NAVTYPE = rewriteMethodToggle[openType || 'reLaunch'];
|
||||||
|
}
|
||||||
|
const tableRoute = routesForMapRoute(router, route.path, ['finallyPathMap', 'pathMap'])
|
||||||
|
const perfectRoute = { ...route, ...tableRoute};
|
||||||
|
perfectRoute.query = parseQuery(perfectRoute.query, router);
|
||||||
|
return perfectRoute;
|
||||||
|
}
|
||||||
103
node_modules/uni-simple-router/src/public/page.ts
generated
vendored
Normal file
103
node_modules/uni-simple-router/src/public/page.ts
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
import { proxyHookName } from '../helpers/config';
|
||||||
|
import { getDataType, getUniCachePage, deepClone} from '../helpers/utils';
|
||||||
|
import { objectAny, pageTypeRule, Router, totalNextRoute, vueOptionRule } from '../options/base';
|
||||||
|
import {createRoute} from './methods'
|
||||||
|
import { stringifyQuery } from './query';
|
||||||
|
|
||||||
|
export function createToFrom(
|
||||||
|
to:totalNextRoute,
|
||||||
|
router:Router,
|
||||||
|
):totalNextRoute {
|
||||||
|
let fromRoute:totalNextRoute = {path: ''};
|
||||||
|
const page = getUniCachePage<Array<any>|objectAny>(0);
|
||||||
|
if (getDataType<Array<any>|objectAny>(page) === '[object Array]') {
|
||||||
|
fromRoute = deepClone<totalNextRoute>(to)
|
||||||
|
} else {
|
||||||
|
fromRoute = createRoute(router) as totalNextRoute;
|
||||||
|
}
|
||||||
|
return fromRoute;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createFullPath(
|
||||||
|
to:totalNextRoute,
|
||||||
|
from:totalNextRoute
|
||||||
|
):void{
|
||||||
|
if (to.fullPath == null) {
|
||||||
|
const strQuery = stringifyQuery(to.query as objectAny);
|
||||||
|
to.fullPath = to.path + strQuery;
|
||||||
|
}
|
||||||
|
if (from.fullPath == null) {
|
||||||
|
const strQuery = stringifyQuery(from.query as objectAny);
|
||||||
|
from.fullPath = from.path + strQuery;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function proxyPageHook(
|
||||||
|
vueVim:any,
|
||||||
|
router:Router,
|
||||||
|
pageType:pageTypeRule
|
||||||
|
):void {
|
||||||
|
const hookDeps = router.proxyHookDeps;
|
||||||
|
const pageHook:vueOptionRule = vueVim.$options;
|
||||||
|
for (let i = 0; i < proxyHookName.length; i++) {
|
||||||
|
const hookName = proxyHookName[i];
|
||||||
|
const hookList = pageHook[hookName];
|
||||||
|
if (hookList) {
|
||||||
|
for (let k = 0; k < hookList.length; k++) {
|
||||||
|
const originHook = hookList[k];
|
||||||
|
if (originHook.toString().includes($npm_package_name)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const resetIndex = Object.keys(hookDeps.hooks).length + 1
|
||||||
|
const proxyHook = (...args:Array<any>):void => {
|
||||||
|
hookDeps.resetIndex.push(resetIndex);
|
||||||
|
hookDeps.options[resetIndex] = args;
|
||||||
|
}
|
||||||
|
const [resetHook] = hookList.splice(k, 1, proxyHook);
|
||||||
|
hookDeps.hooks[resetIndex] = {
|
||||||
|
proxyHook,
|
||||||
|
callHook: (enterPath:string) :void => {
|
||||||
|
if (router.enterPath.replace(/^\//, '') !== enterPath.replace(/^\//, '') && pageType !== 'app') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const options = hookDeps.options[resetIndex];
|
||||||
|
resetHook.apply(vueVim, options);
|
||||||
|
},
|
||||||
|
resetHook: () :void => {
|
||||||
|
hookList.splice(k, 1, resetHook)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function resetAndCallPageHook(
|
||||||
|
router:Router,
|
||||||
|
enterPath:string,
|
||||||
|
reset:boolean|undefined = true
|
||||||
|
):void{
|
||||||
|
// Fixe: https://github.com/SilurianYang/uni-simple-router/issues/206
|
||||||
|
const pathInfo = enterPath.trim().match(/^(\/?[^\?\s]+)(\?[\s\S]*$)?$/);
|
||||||
|
if (pathInfo == null) {
|
||||||
|
throw new Error(`还原hook失败。请检查 【${enterPath}】 路径是否正确。`);
|
||||||
|
}
|
||||||
|
enterPath = pathInfo[1];
|
||||||
|
const proxyHookDeps = router.proxyHookDeps;
|
||||||
|
const resetHooksArray = proxyHookDeps.resetIndex
|
||||||
|
for (let i = 0; i < resetHooksArray.length; i++) {
|
||||||
|
const index = resetHooksArray[i];
|
||||||
|
const {callHook} = proxyHookDeps.hooks[index];
|
||||||
|
callHook(enterPath);
|
||||||
|
}
|
||||||
|
if (reset) {
|
||||||
|
resetPageHook(router);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function resetPageHook(
|
||||||
|
router:Router
|
||||||
|
) {
|
||||||
|
const proxyHookDeps = router.proxyHookDeps;
|
||||||
|
for (const [, {resetHook}] of Object.entries(proxyHookDeps.hooks)) {
|
||||||
|
resetHook();
|
||||||
|
}
|
||||||
|
}
|
||||||
200
node_modules/uni-simple-router/src/public/query.ts
generated
vendored
Normal file
200
node_modules/uni-simple-router/src/public/query.ts
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
import {
|
||||||
|
objectAny,
|
||||||
|
Router,
|
||||||
|
routesMapRule,
|
||||||
|
RoutesRule,
|
||||||
|
totalNextRoute
|
||||||
|
} from '../options/base';
|
||||||
|
import {
|
||||||
|
getDataType,
|
||||||
|
urlToJson,
|
||||||
|
routesForMapRoute,
|
||||||
|
getRoutePath,
|
||||||
|
assertDeepObject,
|
||||||
|
copyData,
|
||||||
|
getWildcardRule,
|
||||||
|
deepDecodeQuery
|
||||||
|
} from '../helpers/utils'
|
||||||
|
import {ERRORHOOK} from './hooks'
|
||||||
|
import {warn} from '../helpers/warn'
|
||||||
|
|
||||||
|
const encodeReserveRE = /[!'()*]/g
|
||||||
|
const encodeReserveReplacer = (c:string) => '%' + c.charCodeAt(0).toString(16)
|
||||||
|
const commaRE = /%2C/g
|
||||||
|
|
||||||
|
const encode = (str:string) =>
|
||||||
|
encodeURIComponent(str)
|
||||||
|
.replace(encodeReserveRE, encodeReserveReplacer)
|
||||||
|
.replace(commaRE, ',')
|
||||||
|
|
||||||
|
export function queryPageToMap(
|
||||||
|
toRule:string|totalNextRoute,
|
||||||
|
router:Router
|
||||||
|
) :{
|
||||||
|
rule:totalNextRoute;
|
||||||
|
route:RoutesRule,
|
||||||
|
query:objectAny
|
||||||
|
} {
|
||||||
|
let query:objectAny = {};
|
||||||
|
let route:RoutesRule|string = '';
|
||||||
|
let successCb = (toRule as totalNextRoute).success;
|
||||||
|
let failCb = (toRule as totalNextRoute).fail;
|
||||||
|
if (getDataType<string|totalNextRoute>(toRule) === '[object Object]') {
|
||||||
|
const objNavRule = (toRule as totalNextRoute);
|
||||||
|
if (objNavRule.path != null) {
|
||||||
|
const {path, query: newQuery} = urlToJson(objNavRule.path);
|
||||||
|
route = routesForMapRoute(router, path, ['finallyPathList', 'pathMap']);
|
||||||
|
query = {...newQuery, ...((toRule as totalNextRoute).query || {})};
|
||||||
|
objNavRule.path = path;
|
||||||
|
objNavRule.query = query;
|
||||||
|
delete (toRule as totalNextRoute).params;
|
||||||
|
} else if (objNavRule.name != null) {
|
||||||
|
route = (router.routesMap as routesMapRule).nameMap[objNavRule.name];
|
||||||
|
if (route == null) {
|
||||||
|
route = getWildcardRule(router, { type: 2, msg: `命名路由为:${objNavRule.name} 的路由,无法在路由表中找到!`, toRule});
|
||||||
|
} else {
|
||||||
|
query = (toRule as totalNextRoute).params || {};
|
||||||
|
delete (toRule as totalNextRoute).query;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
route = getWildcardRule(router, { type: 2, msg: `${toRule} 解析失败,请检测当前路由表下是否有包含。`, toRule});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
toRule = urlToJson((toRule as string)) as totalNextRoute;
|
||||||
|
route = routesForMapRoute(router, toRule.path, ['finallyPathList', 'pathMap'])
|
||||||
|
query = toRule.query as objectAny;
|
||||||
|
}
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
const {finallyPath} = getRoutePath(route as RoutesRule, router);
|
||||||
|
if (finallyPath.includes(':') && (toRule as totalNextRoute).name == null) {
|
||||||
|
ERRORHOOK[0]({ type: 2, msg: `当有设置 alias或者aliasPath 为动态路由时,不允许使用 path 跳转。请使用 name 跳转!`, route}, router)
|
||||||
|
}
|
||||||
|
const completeCb = (toRule as totalNextRoute).complete;
|
||||||
|
const cacheSuccess = (toRule as totalNextRoute).success;
|
||||||
|
const cacheFail = (toRule as totalNextRoute).fail;
|
||||||
|
if (getDataType<Function|undefined>(completeCb) === '[object Function]') {
|
||||||
|
const publicCb = function(this:any, args:Array<any>, callHook:Function|undefined):void {
|
||||||
|
if (getDataType<Function|undefined>(callHook) === '[object Function]') {
|
||||||
|
(callHook as Function).apply(this, args);
|
||||||
|
}
|
||||||
|
(completeCb as Function).apply(this, args);
|
||||||
|
}
|
||||||
|
successCb = function(this:any, ...args:any):void{
|
||||||
|
publicCb.call(this, args, cacheSuccess);
|
||||||
|
};
|
||||||
|
failCb = function(this:any, ...args:any):void{
|
||||||
|
publicCb.call(this, args, cacheFail);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rule = (toRule as totalNextRoute);
|
||||||
|
if (getDataType<Function|undefined>(rule.success) === '[object Function]') {
|
||||||
|
rule.success = successCb;
|
||||||
|
}
|
||||||
|
if (getDataType<Function|undefined>(rule.fail) === '[object Function]') {
|
||||||
|
rule.fail = failCb;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
rule,
|
||||||
|
route: (route as RoutesRule),
|
||||||
|
query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveQuery(
|
||||||
|
toRule:totalNextRoute,
|
||||||
|
router:Router
|
||||||
|
):totalNextRoute {
|
||||||
|
let queryKey:'params'|'query' = 'query';
|
||||||
|
if (toRule.params as objectAny != null) {
|
||||||
|
queryKey = 'params';
|
||||||
|
}
|
||||||
|
if (toRule.query as objectAny != null) {
|
||||||
|
queryKey = 'query';
|
||||||
|
}
|
||||||
|
const query = copyData(toRule[queryKey] || {});
|
||||||
|
const {resolveQuery: userResolveQuery} = router.options;
|
||||||
|
if (userResolveQuery) {
|
||||||
|
const jsonQuery = userResolveQuery(query);
|
||||||
|
if (getDataType<objectAny>(jsonQuery) !== '[object Object]') {
|
||||||
|
warn('请按格式返回参数: resolveQuery?:(jsonQuery:{[propName: string]: any;})=>{[propName: string]: any;}', router)
|
||||||
|
} else {
|
||||||
|
toRule[queryKey] = jsonQuery;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const deepObj = assertDeepObject(query as objectAny);
|
||||||
|
if (!deepObj) {
|
||||||
|
return toRule;
|
||||||
|
}
|
||||||
|
const encode = JSON.stringify(query);
|
||||||
|
toRule[queryKey] = {
|
||||||
|
query: encode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return toRule
|
||||||
|
}
|
||||||
|
|
||||||
|
export function parseQuery(
|
||||||
|
query:objectAny,
|
||||||
|
router:Router,
|
||||||
|
):objectAny {
|
||||||
|
const {parseQuery: userParseQuery} = router.options;
|
||||||
|
if (userParseQuery) {
|
||||||
|
query = userParseQuery(copyData(query));
|
||||||
|
if (getDataType<objectAny>(query) !== '[object Object]') {
|
||||||
|
warn('请按格式返回参数: parseQuery?:(jsonQuery:{[propName: string]: any;})=>{[propName: string]: any;}', router)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Reflect.get(query, 'query')) { // 验证一下是不是深度对象
|
||||||
|
let deepQuery = Reflect.get(query, 'query');
|
||||||
|
if (typeof deepQuery === 'string') {
|
||||||
|
try {
|
||||||
|
deepQuery = JSON.parse(deepQuery);
|
||||||
|
} catch (error) {
|
||||||
|
warn('尝试解析深度对象失败,按原样输出。' + error, router)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (typeof deepQuery === 'object') {
|
||||||
|
return deepDecodeQuery(deepQuery);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
export function stringifyQuery(obj:objectAny): string {
|
||||||
|
const res = obj
|
||||||
|
? Object.keys(obj)
|
||||||
|
.map(key => {
|
||||||
|
const val = obj[key]
|
||||||
|
|
||||||
|
if (val === undefined) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val === null) {
|
||||||
|
return encode(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(val)) {
|
||||||
|
const result:Array<any> = []
|
||||||
|
val.forEach(val2 => {
|
||||||
|
if (val2 === undefined) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (val2 === null) {
|
||||||
|
result.push(encode(key))
|
||||||
|
} else {
|
||||||
|
result.push(encode(key) + '=' + encode(val2))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result.join('&')
|
||||||
|
}
|
||||||
|
|
||||||
|
return encode(key) + '=' + encode(val)
|
||||||
|
})
|
||||||
|
.filter(x => x.length > 0)
|
||||||
|
.join('&')
|
||||||
|
: null
|
||||||
|
return res ? `?${res}` : ''
|
||||||
|
}
|
||||||
158
node_modules/uni-simple-router/src/public/rewrite.ts
generated
vendored
Normal file
158
node_modules/uni-simple-router/src/public/rewrite.ts
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
import {
|
||||||
|
uniNavApiRule,
|
||||||
|
reNavMethodRule,
|
||||||
|
reNotNavMethodRule,
|
||||||
|
Router,
|
||||||
|
rewriteMethodToggle,
|
||||||
|
uniBackRule,
|
||||||
|
uniBackApiRule,
|
||||||
|
navtoRule,
|
||||||
|
totalNextRoute,
|
||||||
|
originMixins,
|
||||||
|
objectAny
|
||||||
|
} from '../options/base'
|
||||||
|
|
||||||
|
import {
|
||||||
|
routesForMapRoute,
|
||||||
|
getRoutePath,
|
||||||
|
getDataType,
|
||||||
|
notDeepClearNull,
|
||||||
|
resolveAbsolutePath,
|
||||||
|
getUniCachePage,
|
||||||
|
timeOut
|
||||||
|
} from '../helpers/utils'
|
||||||
|
|
||||||
|
import {
|
||||||
|
warn
|
||||||
|
} from '../helpers/warn'
|
||||||
|
|
||||||
|
import {uniOriginJump} from './uniOrigin'
|
||||||
|
|
||||||
|
const rewrite: Array<reNavMethodRule|reNotNavMethodRule> = [
|
||||||
|
'navigateTo',
|
||||||
|
'redirectTo',
|
||||||
|
'reLaunch',
|
||||||
|
'switchTab',
|
||||||
|
'navigateBack'
|
||||||
|
];
|
||||||
|
|
||||||
|
export function rewriteMethod(
|
||||||
|
router:Router
|
||||||
|
): void {
|
||||||
|
if (router.options.keepUniOriginNav === false) {
|
||||||
|
rewrite.forEach(name => {
|
||||||
|
const oldMethod: Function = uni[name];
|
||||||
|
uni[name] = function(
|
||||||
|
params:originMixins|{from:string}|navtoRule,
|
||||||
|
originCall:boolean = false,
|
||||||
|
callOkCb?:Function,
|
||||||
|
forceNav?:boolean
|
||||||
|
):void {
|
||||||
|
if (originCall) {
|
||||||
|
uniOriginJump(router, oldMethod, name, params as originMixins, callOkCb, forceNav)
|
||||||
|
} else {
|
||||||
|
if (router.options.platform === 'app-plus') {
|
||||||
|
if (Object.keys(router.appMain).length === 0) {
|
||||||
|
router.appMain = {
|
||||||
|
NAVTYPE: name,
|
||||||
|
path: (params as uniNavApiRule).url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
callRouterMethod(params as uniNavApiRule, name, router);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function callRouterMethod(
|
||||||
|
option: uniNavApiRule|uniBackRule|uniBackApiRule,
|
||||||
|
funName:reNavMethodRule|reNotNavMethodRule,
|
||||||
|
router:Router
|
||||||
|
): void {
|
||||||
|
if (router.options.platform === 'app-plus') {
|
||||||
|
let openType = null;
|
||||||
|
if (option) {
|
||||||
|
openType = (option as uniNavApiRule).openType;
|
||||||
|
}
|
||||||
|
if (openType != null && openType === 'appLaunch') {
|
||||||
|
funName = 'reLaunch'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (funName === 'reLaunch' && JSON.stringify(option) === '{"url":"/"}') {
|
||||||
|
warn(
|
||||||
|
`uni-app 原生方法:reLaunch({url:'/'}) 默认被重写啦!你可以使用 this.$Router.replaceAll() 或者 uni.reLaunch({url:'/?xxx=xxx'})`,
|
||||||
|
router,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
funName = 'navigateBack';
|
||||||
|
option = {
|
||||||
|
from: 'backbutton'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (funName === 'navigateBack') {
|
||||||
|
let level:number = 1;
|
||||||
|
if (option == null) {
|
||||||
|
option = {delta: 1};
|
||||||
|
}
|
||||||
|
if (getDataType<number|undefined>((option as uniBackApiRule).delta) === '[object Number]') {
|
||||||
|
level = ((option as uniBackApiRule).delta as number);
|
||||||
|
}
|
||||||
|
router.back(level, (option as uniBackRule|uniBackApiRule));
|
||||||
|
} else {
|
||||||
|
const routerMethodName = rewriteMethodToggle[(funName as reNavMethodRule)]
|
||||||
|
let path = (option as uniNavApiRule).url;
|
||||||
|
if (!path.startsWith('/')) {
|
||||||
|
const absolutePath = resolveAbsolutePath(path, router);
|
||||||
|
path = absolutePath;
|
||||||
|
(option as uniNavApiRule).url = absolutePath;
|
||||||
|
}
|
||||||
|
if (funName === 'switchTab') {
|
||||||
|
const route = routesForMapRoute(router, path, ['pathMap', 'finallyPathList'])
|
||||||
|
const {finallyPath} = getRoutePath(route, router);
|
||||||
|
if (getDataType<string | string[]>(finallyPath) === '[object Array]') {
|
||||||
|
warn(
|
||||||
|
`uni-app 原生方法跳转路径为:${path}。此路为是tab页面时,不允许设置 alias 为数组的情况,并且不能为动态路由!当然你可以通过通配符*解决!`,
|
||||||
|
router,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if ((finallyPath as string) === '*') {
|
||||||
|
warn(
|
||||||
|
`uni-app 原生方法跳转路径为:${path}。在路由表中找不到相关路由表!当然你可以通过通配符*解决!`,
|
||||||
|
router,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Fixe h5 端无法触发 onTabItemTap hook 2021年6月3日17:26:47
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
const {success: userSuccess} = option as uniNavApiRule;
|
||||||
|
(option as uniNavApiRule).success = (...args:Array<any>) => {
|
||||||
|
userSuccess?.apply(null, args);
|
||||||
|
timeOut(150).then(() => {
|
||||||
|
const cbArgs = (option as uniNavApiRule).detail || {};
|
||||||
|
if (Object.keys(cbArgs).length > 0 && Reflect.has(cbArgs, 'index')) {
|
||||||
|
const cachePage = getUniCachePage(0);
|
||||||
|
if (Object.keys(cachePage).length === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const page = cachePage as objectAny;
|
||||||
|
const hooks = page.$options.onTabItemTap;
|
||||||
|
if (hooks) {
|
||||||
|
for (let j = 0; j < hooks.length; j++) {
|
||||||
|
hooks[j].call(page, cbArgs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
path = (finallyPath as string);
|
||||||
|
}
|
||||||
|
const {events, success, fail, complete, animationType, animationDuration} = option as uniNavApiRule;
|
||||||
|
const jumpOptions:totalNextRoute = {path, events, success, fail, complete, animationDuration, animationType};
|
||||||
|
router[routerMethodName](
|
||||||
|
notDeepClearNull<totalNextRoute>(jumpOptions)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
129
node_modules/uni-simple-router/src/public/router.ts
generated
vendored
Normal file
129
node_modules/uni-simple-router/src/public/router.ts
generated
vendored
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import {PromiseResolve, Router, uniBackApiRule, uniBackRule} from '../options/base';
|
||||||
|
import {InstantiateConfig, LifeCycleConfig} from '../options/config';
|
||||||
|
import { lifeCycle, proxyHookDeps} from '../helpers/config';
|
||||||
|
import {assertNewOptions, def, getDataType} from '../helpers/utils';
|
||||||
|
import {registerRouterHooks, registerEachHooks} from '../helpers/lifeCycle';
|
||||||
|
import {initMixins} from '../helpers/mixins'
|
||||||
|
import {lockNavjump, forceGuardEach, createRoute} from '../public/methods'
|
||||||
|
import {rewriteMethod} from '../public/rewrite'
|
||||||
|
|
||||||
|
let AppReadyResolve:PromiseResolve = () => {};
|
||||||
|
const AppReady:Promise<void> = new Promise(resolve => (AppReadyResolve = resolve));
|
||||||
|
|
||||||
|
function createRouter(params: InstantiateConfig):Router {
|
||||||
|
const options = assertNewOptions<InstantiateConfig>(params);
|
||||||
|
const router:Router = {
|
||||||
|
options,
|
||||||
|
mount: [],
|
||||||
|
Vue: null,
|
||||||
|
proxyHookDeps: proxyHookDeps,
|
||||||
|
appMain: {},
|
||||||
|
enterPath: '',
|
||||||
|
$route: null,
|
||||||
|
$lockStatus: false,
|
||||||
|
routesMap: {},
|
||||||
|
lifeCycle: registerRouterHooks<LifeCycleConfig>(lifeCycle, options),
|
||||||
|
push(to) {
|
||||||
|
lockNavjump(to, router, 'push');
|
||||||
|
},
|
||||||
|
replace(to) {
|
||||||
|
lockNavjump(to, router, 'replace');
|
||||||
|
},
|
||||||
|
replaceAll(to) {
|
||||||
|
lockNavjump(to, router, 'replaceAll');
|
||||||
|
},
|
||||||
|
pushTab(to) {
|
||||||
|
lockNavjump(to, router, 'pushTab');
|
||||||
|
},
|
||||||
|
back(level = 1, animation) {
|
||||||
|
if (getDataType(animation) !== '[object Object]') {
|
||||||
|
const backRule:uniBackRule = {
|
||||||
|
from: 'navigateBack'
|
||||||
|
}
|
||||||
|
animation = backRule;
|
||||||
|
} else {
|
||||||
|
if (!Reflect.has((animation as uniBackRule | uniBackApiRule), 'from')) {
|
||||||
|
animation = {
|
||||||
|
...animation,
|
||||||
|
from: 'navigateBack'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lockNavjump(level + '', router, 'back', undefined, animation)
|
||||||
|
},
|
||||||
|
forceGuardEach(navType, forceNav) {
|
||||||
|
forceGuardEach(router, navType, forceNav)
|
||||||
|
},
|
||||||
|
beforeEach(userGuard):void {
|
||||||
|
registerEachHooks(router, 'beforeHooks', userGuard);
|
||||||
|
},
|
||||||
|
afterEach(userGuard):void {
|
||||||
|
registerEachHooks(router, 'afterHooks', userGuard);
|
||||||
|
},
|
||||||
|
install(Vue:any):void{
|
||||||
|
router.Vue = Vue;
|
||||||
|
rewriteMethod(this);
|
||||||
|
initMixins(Vue, this);
|
||||||
|
Object.defineProperty(Vue.prototype, '$Router', {
|
||||||
|
get() {
|
||||||
|
const actualData = router;
|
||||||
|
|
||||||
|
Object.defineProperty(this, '$Router', {
|
||||||
|
value: actualData,
|
||||||
|
writable: false,
|
||||||
|
configurable: false,
|
||||||
|
enumerable: false
|
||||||
|
});
|
||||||
|
|
||||||
|
return Object.seal(actualData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.defineProperty(Vue.prototype, '$Route', {
|
||||||
|
get() {
|
||||||
|
return createRoute(router);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/254
|
||||||
|
Object.defineProperty(Vue.prototype, '$AppReady', {
|
||||||
|
get() {
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
return AppReady;
|
||||||
|
},
|
||||||
|
set(value:boolean) {
|
||||||
|
if (value === true) {
|
||||||
|
AppReadyResolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def(router, 'currentRoute', () => createRoute(router));
|
||||||
|
|
||||||
|
router.beforeEach((to, from, next) => next());
|
||||||
|
router.afterEach(() => {});
|
||||||
|
return router;
|
||||||
|
}
|
||||||
|
|
||||||
|
function RouterMount(Vim:any, router:Router, el:string | undefined = '#app') :void|never {
|
||||||
|
if (getDataType<Array<any>>(router.mount) === '[object Array]') {
|
||||||
|
router.mount.push({
|
||||||
|
app: Vim,
|
||||||
|
el
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error(`挂载路由失败,router.app 应该为数组类型。当前类型:${typeof router.mount}`);
|
||||||
|
}
|
||||||
|
if (router.options.platform === 'h5') {
|
||||||
|
const vueRouter = (router.$route as any);
|
||||||
|
vueRouter.replace({
|
||||||
|
path: vueRouter.currentRoute.fullPath
|
||||||
|
});
|
||||||
|
} // 其他端目前不需要做啥
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
RouterMount,
|
||||||
|
createRouter
|
||||||
|
}
|
||||||
112
node_modules/uni-simple-router/src/public/uniOrigin.ts
generated
vendored
Normal file
112
node_modules/uni-simple-router/src/public/uniOrigin.ts
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
import { originMixins, reNavMethodRule, reNotNavMethodRule, Router, startAnimationRule, uniNavApiRule } from '../options/base';
|
||||||
|
import { stringifyQuery } from './query';
|
||||||
|
import {notDeepClearNull, timeOut} from '../helpers/utils'
|
||||||
|
import { mpPlatformReg } from '../helpers/config';
|
||||||
|
import { resetAndCallPageHook, resetPageHook } from './page';
|
||||||
|
|
||||||
|
let routerNavCount:number = 0;
|
||||||
|
let lastNavType:reNavMethodRule|reNotNavMethodRule = 'reLaunch'
|
||||||
|
|
||||||
|
export function uniOriginJump(
|
||||||
|
router:Router,
|
||||||
|
originMethod:Function,
|
||||||
|
funName:reNavMethodRule|reNotNavMethodRule,
|
||||||
|
options: originMixins,
|
||||||
|
callOkCb?:Function,
|
||||||
|
forceNav?:boolean
|
||||||
|
):void {
|
||||||
|
const {complete, ...originRule} = formatOriginURLQuery(router, options, funName);
|
||||||
|
const platform = router.options.platform;
|
||||||
|
if (forceNav != null && forceNav === false) {
|
||||||
|
if (routerNavCount === 0) {
|
||||||
|
routerNavCount++
|
||||||
|
if (platform !== 'h5') {
|
||||||
|
resetAndCallPageHook(router, originRule.url) // 还原及执行app.vue及首页下已经重写后的生命周期
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/254
|
||||||
|
// 在小程序端 next 直接放行会执行这个
|
||||||
|
router.Vue.prototype.$AppReady = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
complete && complete.apply(null, {msg: 'forceGuardEach强制触发并且不执行跳转'});
|
||||||
|
callOkCb && callOkCb.apply(null, {msg: 'forceGuardEach强制触发并且不执行跳转'})
|
||||||
|
} else {
|
||||||
|
if (routerNavCount === 0) {
|
||||||
|
if (platform === 'app-plus') {
|
||||||
|
resetAndCallPageHook(router, originRule.url) // 还原及执行app.vue下已经重写后的生命周期
|
||||||
|
} else {
|
||||||
|
if (new RegExp(mpPlatformReg, 'g').test(platform)) {
|
||||||
|
// 其他就是在小程序下,首次启动发生跳转会走这里
|
||||||
|
// 我们先将app.vue的生命周期执行
|
||||||
|
resetAndCallPageHook(router, originRule.url, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
originMethod({
|
||||||
|
...originRule,
|
||||||
|
from: options.BACKTYPE,
|
||||||
|
complete: async function(...args:Array<any>) {
|
||||||
|
if (routerNavCount === 0) {
|
||||||
|
routerNavCount++
|
||||||
|
|
||||||
|
if (platform !== 'h5') {
|
||||||
|
if (new RegExp(mpPlatformReg, 'g').test(platform)) { // 跳转完成后小程序下还原生命周期
|
||||||
|
resetPageHook(router);
|
||||||
|
}
|
||||||
|
// 【Fixe】 https://github.com/SilurianYang/uni-simple-router/issues/254
|
||||||
|
// 在小程序端 第一次 next 做跳转 会触发这个 、在app端首次必定会触发这个
|
||||||
|
router.Vue.prototype.$AppReady = true;
|
||||||
|
|
||||||
|
if (platform === 'app-plus') {
|
||||||
|
const waitPage = plus.nativeObj.View.getViewById('router-loadding');
|
||||||
|
waitPage && waitPage.close();
|
||||||
|
const launchedHook = router.options.APP?.launchedHook;
|
||||||
|
launchedHook && launchedHook();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let time:number = 0;
|
||||||
|
if (new RegExp(mpPlatformReg, 'g').test(platform)) {
|
||||||
|
time = (router.options.applet?.animationDuration) as number
|
||||||
|
} else if (platform === 'app-plus') {
|
||||||
|
if (funName === 'navigateBack' && lastNavType === 'navigateTo') {
|
||||||
|
time = (router.options.APP?.animation?.animationDuration) as number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (funName === 'navigateTo' || funName === 'navigateBack') {
|
||||||
|
if (time !== 0) {
|
||||||
|
await timeOut(time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastNavType = funName;
|
||||||
|
complete && complete.apply(null, args);
|
||||||
|
callOkCb && callOkCb.apply(null, args)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function formatOriginURLQuery(
|
||||||
|
router:Router,
|
||||||
|
options:uniNavApiRule,
|
||||||
|
funName:reNavMethodRule|reNotNavMethodRule
|
||||||
|
):uniNavApiRule {
|
||||||
|
const {url, path, query, animationType, animationDuration, events, success, fail, complete, delta, animation} = options;
|
||||||
|
const strQuery = stringifyQuery(query || {});
|
||||||
|
const queryURL = strQuery === '' ? (path || url) : (path || url) + strQuery;
|
||||||
|
let animationRule:startAnimationRule = {};
|
||||||
|
if (router.options.platform === 'app-plus') {
|
||||||
|
if (funName !== 'navigateBack') {
|
||||||
|
animationRule = router.options.APP?.animation || {};
|
||||||
|
animationRule = {...animationRule, ...animation || {}};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return notDeepClearNull<uniNavApiRule>({
|
||||||
|
delta,
|
||||||
|
url: queryURL,
|
||||||
|
animationType: animationType || animationRule.animationType,
|
||||||
|
animationDuration: animationDuration || animationRule.animationDuration,
|
||||||
|
events,
|
||||||
|
success,
|
||||||
|
fail,
|
||||||
|
complete
|
||||||
|
})
|
||||||
|
}
|
||||||
70
node_modules/uni-simple-router/test/path-to-regexp.spec.ts
generated
vendored
Normal file
70
node_modules/uni-simple-router/test/path-to-regexp.spec.ts
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
import {createRouter, routesMapKeysRule} from '../src/index';
|
||||||
|
|
||||||
|
import {routesForMapRoute} from '../src/helpers/utils';
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{path: '/pages/login/login', name: 'login', aliasPath: '/'},
|
||||||
|
{path: '/pages/page2/page2', name: 'page2', aliasPath: '/page2/:id'},
|
||||||
|
{path: '/pages/page3/page3', aliasPath: '/:name/page3/:id'},
|
||||||
|
{path: '/pages/animation/animation', aliasPath: '/an-(\\d+)-on'},
|
||||||
|
{path: '/static/1/1', aliasPath: '/static/(.*)'},
|
||||||
|
{path: '/dynamic/1/1', aliasPath: '/dynamic-*'},
|
||||||
|
{path: '/dynamic/3/3', aliasPath: '/dynamic3'},
|
||||||
|
{path: '*'}
|
||||||
|
];
|
||||||
|
|
||||||
|
const router = createRouter({
|
||||||
|
platform: 'app-plus',
|
||||||
|
keepUniOriginNav: true,
|
||||||
|
routes,
|
||||||
|
});
|
||||||
|
|
||||||
|
const Vue = function () {};
|
||||||
|
Vue.mixin = () => {};
|
||||||
|
|
||||||
|
router.install(Vue);
|
||||||
|
|
||||||
|
const rules: routesMapKeysRule[] = ['finallyPathMap', 'pathMap'];
|
||||||
|
|
||||||
|
it('别名路径匹配',()=>{
|
||||||
|
const toRoute1 = routesForMapRoute(router, '/dynamic3', rules);
|
||||||
|
expect(toRoute1).toEqual(routes[6]);
|
||||||
|
|
||||||
|
const toRoute2 = routesForMapRoute(router, '/dynamic/3/3', rules);
|
||||||
|
expect(toRoute2).toEqual(routes[6]);
|
||||||
|
})
|
||||||
|
|
||||||
|
it('全局匹配', () => {
|
||||||
|
const toRoute1 = routesForMapRoute(router, '/pages/login/login', rules);
|
||||||
|
expect(toRoute1).toEqual(routes[0]);
|
||||||
|
|
||||||
|
const toRoute2 = routesForMapRoute(router,'/pages/login/login?id=666',rules);
|
||||||
|
expect(toRoute2).toEqual(routes[0]);
|
||||||
|
|
||||||
|
const toRoute3 = routesForMapRoute(router, '/page2/6666', rules);
|
||||||
|
expect(toRoute3).toEqual(routes[1]);
|
||||||
|
|
||||||
|
const toRoute4 = routesForMapRoute(router, '/page2/6666?id=555', rules);
|
||||||
|
expect(toRoute4).toEqual(routes[1]);
|
||||||
|
|
||||||
|
const toRoute5 = routesForMapRoute(router, '/pages/page3/page3', rules);
|
||||||
|
expect(toRoute5).toEqual(routes[2]);
|
||||||
|
|
||||||
|
const toRoute6 = routesForMapRoute(router, '/test/page3/123', rules);
|
||||||
|
expect(toRoute6).toEqual(routes[2]);
|
||||||
|
|
||||||
|
const toRoute7 = routesForMapRoute(router, '/an-123-on', rules);
|
||||||
|
expect(toRoute7).toEqual(routes[3]);
|
||||||
|
|
||||||
|
const toRoute8 = routesForMapRoute(router, '/static/aaa/bbb?id=1444&name=999', rules);
|
||||||
|
expect(toRoute8).toEqual(routes[4]);
|
||||||
|
|
||||||
|
const toRoute9 = routesForMapRoute(router, '/dynamic-6666-5555', rules);
|
||||||
|
expect(toRoute9).toEqual(routes[5]);
|
||||||
|
|
||||||
|
const toRoute10 = routesForMapRoute(router, '/aaaaaa', rules);
|
||||||
|
expect(toRoute10).toEqual(routes[7]);
|
||||||
|
|
||||||
|
const toRoute11 = routesForMapRoute(router, '---48848--14545', rules);
|
||||||
|
expect(toRoute11).toEqual(routes[7]);
|
||||||
|
});
|
||||||
83
node_modules/uni-simple-router/test/query-toggle.spec.ts
generated
vendored
Normal file
83
node_modules/uni-simple-router/test/query-toggle.spec.ts
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import {deepDecodeQuery} from '../src/helpers/utils';
|
||||||
|
|
||||||
|
|
||||||
|
it('编码回转',()=>{
|
||||||
|
const query={
|
||||||
|
str:'%E7%9A%84%E6%8C%A5%E6%B4%92U%E7%9B%BE%E5%A5%BD%E6%92%92%E7%AC%AC%E4%B8%89%E5%A4%A7%E5%8E%A6%E5%8F%91%E7%9A%84%E6%92%92321312%2a%EF%BC%88%EF%BF%A5%23%254'
|
||||||
|
}
|
||||||
|
const result = deepDecodeQuery(query);
|
||||||
|
expect(JSON.stringify(result)).toEqual(JSON.stringify({
|
||||||
|
str:'的挥洒U盾好撒第三大厦发的撒321312*(¥#%4'
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('一些乱码字符',()=>{
|
||||||
|
const query={
|
||||||
|
str:`~!@#$%^&*()_+-,./|][]`
|
||||||
|
}
|
||||||
|
const result = deepDecodeQuery(query);
|
||||||
|
expect(JSON.stringify(result)).toEqual(JSON.stringify({
|
||||||
|
str:`~!@#$%^&*()_+-,./|][]`
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('单个加密参数',()=>{
|
||||||
|
const query={
|
||||||
|
name:'%7B%22status%22%3Atrue%2C%22list%22%3A%5B%7B%22id%22%3A1%7D%5D%7D'
|
||||||
|
}
|
||||||
|
const result = deepDecodeQuery(query);
|
||||||
|
expect(JSON.stringify(result)).toEqual(JSON.stringify({
|
||||||
|
name:{
|
||||||
|
status:true,
|
||||||
|
list:[
|
||||||
|
{
|
||||||
|
id:1
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
|
||||||
|
it('单个普通参数',()=>{
|
||||||
|
const query={
|
||||||
|
name:'hhyang',
|
||||||
|
ages:22,
|
||||||
|
open:true
|
||||||
|
}
|
||||||
|
const result = deepDecodeQuery(query);
|
||||||
|
|
||||||
|
expect(JSON.stringify(result)).toEqual(JSON.stringify(query));
|
||||||
|
})
|
||||||
|
|
||||||
|
it('深度参数加混乱',()=>{
|
||||||
|
const query={
|
||||||
|
list:[
|
||||||
|
1,'2',true,encodeURIComponent(JSON.stringify({name:111})),{
|
||||||
|
name:'hhyang',
|
||||||
|
strObj:encodeURIComponent(JSON.stringify({name:222}))
|
||||||
|
}
|
||||||
|
],
|
||||||
|
obj:{
|
||||||
|
strObj2:encodeURIComponent(JSON.stringify({name:333})),
|
||||||
|
number:1,
|
||||||
|
boolean:false,
|
||||||
|
},
|
||||||
|
str4:encodeURIComponent(JSON.stringify({name:444}))
|
||||||
|
}
|
||||||
|
const result = deepDecodeQuery(query);
|
||||||
|
|
||||||
|
expect(JSON.stringify(result)).toEqual(JSON.stringify({
|
||||||
|
list:[
|
||||||
|
1,'2',true,{name:111},{
|
||||||
|
name:'hhyang',
|
||||||
|
strObj:{name:222}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
obj:{
|
||||||
|
strObj2:{name:333},
|
||||||
|
number:1,
|
||||||
|
boolean:false,
|
||||||
|
},
|
||||||
|
str4:{name:444}
|
||||||
|
}));
|
||||||
|
})
|
||||||
19
node_modules/uni-simple-router/tsconfig.json
generated
vendored
Normal file
19
node_modules/uni-simple-router/tsconfig.json
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"module": "CommonJS",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"lib": ["ES2015", "DOM"],
|
||||||
|
"outDir": "dist/src",
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": false,
|
||||||
|
"rootDir": "./src",
|
||||||
|
"baseUrl": ".",
|
||||||
|
"paths": {}
|
||||||
|
},
|
||||||
|
"include": ["./src/global.d.ts", "./src/*"],
|
||||||
|
"exclude": ["node_modules", "**/*.spec.ts"]
|
||||||
|
}
|
||||||
41
node_modules/uni-simple-router/webpack/webpack.common.js
generated
vendored
Normal file
41
node_modules/uni-simple-router/webpack/webpack.common.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
const {resolve} = require('path');
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
const webpack =require('webpack');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
entry: './src/index.ts',
|
||||||
|
output: {
|
||||||
|
library: 'Router',
|
||||||
|
libraryTarget: 'umd',
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.tsx', '.ts', 'd.ts', '.js', '.json'],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'ts-loader',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin([
|
||||||
|
{
|
||||||
|
force: true,
|
||||||
|
from: resolve(__dirname, '../src/component'),
|
||||||
|
to: resolve(__dirname, '../dist'),
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
$npm_package_name: webpack.DefinePlugin.runtimeValue(() => {
|
||||||
|
return JSON.stringify(process.env.npm_package_name.toLocaleUpperCase())
|
||||||
|
}, true )
|
||||||
|
})
|
||||||
|
],
|
||||||
|
};
|
||||||
22
node_modules/uni-simple-router/webpack/webpack.dev.js
generated
vendored
Normal file
22
node_modules/uni-simple-router/webpack/webpack.dev.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const {merge} = require("webpack-merge");
|
||||||
|
const {resolve} = require('path');
|
||||||
|
const common = require("./webpack.common.js");
|
||||||
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
|
|
||||||
|
const output=resolve(__dirname, '../examples/uni-simple-router2.0/dist');
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: 'development',
|
||||||
|
devtool: 'source-map',
|
||||||
|
output: {
|
||||||
|
path:output ,
|
||||||
|
filename: 'uni-simple-router.js',
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new CopyPlugin([{
|
||||||
|
force: true,
|
||||||
|
from: resolve(__dirname, '../src/component'),
|
||||||
|
to: output,
|
||||||
|
}]),
|
||||||
|
]
|
||||||
|
});
|
||||||
19
node_modules/uni-simple-router/webpack/webpack.prod.js
generated
vendored
Normal file
19
node_modules/uni-simple-router/webpack/webpack.prod.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
const {resolve} = require('path');
|
||||||
|
const {merge} = require("webpack-merge");
|
||||||
|
const common = require("./webpack.common.js");
|
||||||
|
const rimraf = require('rimraf');
|
||||||
|
|
||||||
|
|
||||||
|
function resolvePath(dir) {
|
||||||
|
return resolve(__dirname, '../', dir)
|
||||||
|
}
|
||||||
|
|
||||||
|
rimraf('dist', () => {});
|
||||||
|
|
||||||
|
module.exports = merge(common, {
|
||||||
|
mode: "production",
|
||||||
|
output: {
|
||||||
|
path: resolvePath('dist'),
|
||||||
|
filename: 'uni-simple-router.js',
|
||||||
|
},
|
||||||
|
})
|
||||||
21
node_modules/uview-ui/LICENSE
generated
vendored
Normal file
21
node_modules/uview-ui/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 www.uviewui.com
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
106
node_modules/uview-ui/README.md
generated
vendored
Normal file
106
node_modules/uview-ui/README.md
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<p align="center">
|
||||||
|
<img alt="logo" src="https://uviewui.com/common/logo.png" width="120" height="120" style="margin-bottom: 10px;">
|
||||||
|
</p>
|
||||||
|
<h3 align="center" style="margin: 30px 0 30px;font-weight: bold;font-size:40px;">uView</h3>
|
||||||
|
<h3 align="center">多平台快速开发的UI框架</h3>
|
||||||
|
|
||||||
|
|
||||||
|
## 说明
|
||||||
|
|
||||||
|
uView UI,是[uni-app](https://uniapp.dcloud.io/)生态优秀的UI框架,全面的组件和便捷的工具会让您信手拈来,如鱼得水
|
||||||
|
|
||||||
|
## 特性
|
||||||
|
|
||||||
|
- 兼容安卓,iOS,微信小程序,H5,QQ小程序,百度小程序,支付宝小程序,头条小程序
|
||||||
|
- 60+精选组件,功能丰富,多端兼容,让您快速集成,开箱即用
|
||||||
|
- 众多贴心的JS利器,让您飞镖在手,召之即来,百步穿杨
|
||||||
|
- 众多的常用页面和布局,让您专注逻辑,事半功倍
|
||||||
|
- 详尽的文档支持,现代化的演示效果
|
||||||
|
- 按需引入,精简打包体积
|
||||||
|
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# npm方式安装
|
||||||
|
npm i uview-ui
|
||||||
|
```
|
||||||
|
|
||||||
|
## 快速上手
|
||||||
|
|
||||||
|
1. `main.js`引入uView库
|
||||||
|
```js
|
||||||
|
// main.js
|
||||||
|
import uView from 'uview-ui';
|
||||||
|
Vue.use(uView);
|
||||||
|
```
|
||||||
|
|
||||||
|
2. `App.vue`引入基础样式(注意style标签需声明scss属性支持)
|
||||||
|
```css
|
||||||
|
/* App.vue */
|
||||||
|
<style lang="scss">
|
||||||
|
@import "uview-ui/index.scss";
|
||||||
|
</style>
|
||||||
|
```
|
||||||
|
|
||||||
|
3. `uni.scss`引入全局scss变量文件
|
||||||
|
```css
|
||||||
|
/* uni.scss */
|
||||||
|
@import "uview-ui/theme.scss";
|
||||||
|
```
|
||||||
|
|
||||||
|
4. `pages.json`配置easycom规则(按需引入)
|
||||||
|
|
||||||
|
```js
|
||||||
|
// pages.json
|
||||||
|
{
|
||||||
|
"easycom": {
|
||||||
|
// npm安装的方式不需要前面的"@/",下载安装的方式需要"@/"
|
||||||
|
// npm安装方式
|
||||||
|
"^u-(.*)": "uview-ui/components/u-$1/u-$1.vue"
|
||||||
|
// 下载安装方式
|
||||||
|
// "^u-(.*)": "@/uview-ui/components/u-$1/u-$1.vue"
|
||||||
|
},
|
||||||
|
// 此为本身已有的内容
|
||||||
|
"pages": [
|
||||||
|
// ......
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
配置easycom规则后,自动按需引入,无需`import`组件,直接引用即可。
|
||||||
|
|
||||||
|
```html
|
||||||
|
<template>
|
||||||
|
<u-button>按钮</u-button>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
|
请通过[快速上手](https://uviewui.com/components/quickstart.html)了解更详细的内容
|
||||||
|
|
||||||
|
## 链接
|
||||||
|
|
||||||
|
- [官方文档](https://uviewui.com/)
|
||||||
|
- [更新日志](https://uviewui.com/components/changelog.html)
|
||||||
|
- [升级指南](https://uviewui.com/components/changelog.html)
|
||||||
|
- [关于我们](https://uviewui.com/cooperation/about.html)
|
||||||
|
|
||||||
|
## 预览
|
||||||
|
|
||||||
|
您可以通过**微信**扫码,查看最佳的演示效果。
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
<img src="https://uviewui.com/common/weixin_mini_qrcode.png" width="220" height="220" >
|
||||||
|
|
||||||
|
<!-- ## 捐赠uView的研发
|
||||||
|
|
||||||
|
uView文档和源码全部开源免费,如果您认为uView帮到了您的开发工作,您可以捐赠uView的研发工作,捐赠无门槛,哪怕是一杯可乐也好(相信这比打赏主播更有意义)。
|
||||||
|
|
||||||
|
<img src="https://uviewui.com/common/wechat.png" width="220" >
|
||||||
|
<img style="margin-left: 100px;" src="https://uviewui.com/common/alipay.png" width="220" >
|
||||||
|
-->
|
||||||
|
## 版权信息
|
||||||
|
uView遵循[MIT](https://en.wikipedia.org/wiki/MIT_License)开源协议,意味着您无需支付任何费用,也无需授权,即可将uView应用到您的产品中。
|
||||||
190
node_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue
generated
vendored
Normal file
190
node_modules/uview-ui/components/u-action-sheet/u-action-sheet.vue
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
|||||||
|
<template>
|
||||||
|
<u-popup mode="bottom" :border-radius="borderRadius" :popup="false" v-model="value" :maskCloseAble="maskCloseAble"
|
||||||
|
length="auto" :safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :z-index="uZIndex">
|
||||||
|
<view class="u-tips u-border-bottom" v-if="tips.text" :style="[tipsStyle]">
|
||||||
|
{{tips.text}}
|
||||||
|
</view>
|
||||||
|
<block v-for="(item, index) in list" :key="index">
|
||||||
|
<view
|
||||||
|
@touchmove.stop.prevent
|
||||||
|
@tap="itemClick(index)"
|
||||||
|
:style="[itemStyle(index)]"
|
||||||
|
class="u-action-sheet-item u-line-1"
|
||||||
|
:class="[index < list.length - 1 ? 'u-border-bottom' : '']"
|
||||||
|
:hover-stay-time="150"
|
||||||
|
>
|
||||||
|
<text>{{item.text}}</text>
|
||||||
|
<text class="u-action-sheet-item__subtext u-line-1" v-if="item.subText">{{item.subText}}</text>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<view class="u-gab" v-if="cancelBtn">
|
||||||
|
</view>
|
||||||
|
<view @touchmove.stop.prevent class="u-actionsheet-cancel u-action-sheet-item" hover-class="u-hover-class"
|
||||||
|
:hover-stay-time="150" v-if="cancelBtn" @tap="close">{{cancelText}}</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* actionSheet 操作菜单
|
||||||
|
* @description 本组件用于从底部弹出一个操作菜单,供用户选择并返回结果。本组件功能类似于uni的uni.showActionSheetAPI,配置更加灵活,所有平台都表现一致。
|
||||||
|
* @tutorial https://www.uviewui.com/components/actionSheet.html
|
||||||
|
* @property {Array<Object>} list 按钮的文字数组,见官方文档示例
|
||||||
|
* @property {Object} tips 顶部的提示文字,见官方文档示例
|
||||||
|
* @property {String} cancel-text 取消按钮的提示文字
|
||||||
|
* @property {Boolean} cancel-btn 是否显示底部的取消按钮(默认true)
|
||||||
|
* @property {Number String} border-radius 弹出部分顶部左右的圆角值,单位rpx(默认0)
|
||||||
|
* @property {Boolean} mask-close-able 点击遮罩是否可以关闭(默认true)
|
||||||
|
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
|
||||||
|
* @property {Number String} z-index z-index值(默认1075)
|
||||||
|
* @property {String} cancel-text 取消按钮的提示文字
|
||||||
|
* @event {Function} click 点击ActionSheet列表项时触发
|
||||||
|
* @event {Function} close 点击取消按钮时触发
|
||||||
|
* @example <u-action-sheet :list="list" @click="click" v-model="show"></u-action-sheet>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-action-sheet",
|
||||||
|
props: {
|
||||||
|
// 点击遮罩是否可以关闭actionsheet
|
||||||
|
maskCloseAble: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 按钮的文字数组,可以自定义颜色和字体大小,字体单位为rpx
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
// 如下
|
||||||
|
// return [{
|
||||||
|
// text: '确定',
|
||||||
|
// color: '',
|
||||||
|
// fontSize: ''
|
||||||
|
// }]
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 顶部的提示文字
|
||||||
|
tips: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {
|
||||||
|
text: '',
|
||||||
|
color: '',
|
||||||
|
fontSize: '26'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 底部的取消按钮
|
||||||
|
cancelBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
|
||||||
|
safeAreaInsetBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 通过双向绑定控制组件的弹出与收起
|
||||||
|
value: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 弹出的顶部圆角值
|
||||||
|
borderRadius: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 弹出的z-index值
|
||||||
|
zIndex: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 取消按钮的文字提示
|
||||||
|
cancelText: {
|
||||||
|
type: String,
|
||||||
|
default: '取消'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 顶部提示的样式
|
||||||
|
tipsStyle() {
|
||||||
|
let style = {};
|
||||||
|
if (this.tips.color) style.color = this.tips.color;
|
||||||
|
if (this.tips.fontSize) style.fontSize = this.tips.fontSize + 'rpx';
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 操作项目的样式
|
||||||
|
itemStyle() {
|
||||||
|
return (index) => {
|
||||||
|
let style = {};
|
||||||
|
if (this.list[index].color) style.color = this.list[index].color;
|
||||||
|
if (this.list[index].fontSize) style.fontSize = this.list[index].fontSize + 'rpx';
|
||||||
|
// 选项被禁用的样式
|
||||||
|
if (this.list[index].disabled) style.color = '#c0c4cc';
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
uZIndex() {
|
||||||
|
// 如果用户有传递z-index值,优先使用
|
||||||
|
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击取消按钮
|
||||||
|
close() {
|
||||||
|
// 发送input事件,并不会作用于父组件,而是要设置组件内部通过props传递的value参数
|
||||||
|
// 这是一个vue发送事件的特殊用法
|
||||||
|
this.popupClose();
|
||||||
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
// 弹窗关闭
|
||||||
|
popupClose() {
|
||||||
|
this.$emit('input', false);
|
||||||
|
},
|
||||||
|
// 点击某一个item
|
||||||
|
itemClick(index) {
|
||||||
|
// disabled的项禁止点击
|
||||||
|
if(this.list[index].disabled) return;
|
||||||
|
this.$emit('click', index);
|
||||||
|
this.$emit('input', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-tips {
|
||||||
|
font-size: 26rpx;
|
||||||
|
text-align: center;
|
||||||
|
padding: 34rpx 0;
|
||||||
|
line-height: 1;
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-action-sheet-item {
|
||||||
|
@include vue-flex;;
|
||||||
|
line-height: 1;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 32rpx;
|
||||||
|
padding: 34rpx 0;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-action-sheet-item__subtext {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-gab {
|
||||||
|
height: 12rpx;
|
||||||
|
background-color: rgb(234, 234, 236);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-actionsheet-cancel {
|
||||||
|
color: $u-main-color;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
256
node_modules/uview-ui/components/u-alert-tips/u-alert-tips.vue
generated
vendored
Normal file
256
node_modules/uview-ui/components/u-alert-tips/u-alert-tips.vue
generated
vendored
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-alert-tips" v-if="show" :class="[
|
||||||
|
!show ? 'u-close-alert-tips': '',
|
||||||
|
type ? 'u-alert-tips--bg--' + type + '-light' : '',
|
||||||
|
type ? 'u-alert-tips--border--' + type + '-disabled' : '',
|
||||||
|
]" :style="{
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
borderColor: borderColor
|
||||||
|
}">
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon v-if="showIcon" :name="uIcon" :size="description ? 40 : 32" class="u-icon" :color="uIconType" :custom-style="iconStyle"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-alert-content" @tap.stop="click">
|
||||||
|
<view class="u-alert-title" :style="[uTitleStyle]">
|
||||||
|
{{title}}
|
||||||
|
</view>
|
||||||
|
<view v-if="description" class="u-alert-desc" :style="[descStyle]">
|
||||||
|
{{description}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon @click="close" v-if="closeAble && !closeText" hoverClass="u-type-error-hover-color" name="close" color="#c0c4cc"
|
||||||
|
:size="22" class="u-close-icon" :style="{
|
||||||
|
top: description ? '18rpx' : '24rpx'
|
||||||
|
}"></u-icon>
|
||||||
|
</view>
|
||||||
|
<text v-if="closeAble && closeText" class="u-close-text" :style="{
|
||||||
|
top: description ? '18rpx' : '24rpx'
|
||||||
|
}">{{closeText}}</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* alertTips 警告提示
|
||||||
|
* @description 警告提示,展现需要关注的信息
|
||||||
|
* @tutorial https://uviewui.com/components/alertTips.html
|
||||||
|
* @property {String} title 显示的标题文字
|
||||||
|
* @property {String} description 辅助性文字,颜色比title浅一点,字号也小一点,可选
|
||||||
|
* @property {String} type 关闭按钮(默认为叉号icon图标)
|
||||||
|
* @property {String} icon 图标名称
|
||||||
|
* @property {Object} icon-style 图标的样式,对象形式
|
||||||
|
* @property {Object} title-style 标题的样式,对象形式
|
||||||
|
* @property {Object} desc-style 描述的样式,对象形式
|
||||||
|
* @property {String} close-able 用文字替代关闭图标,close-able为true时有效
|
||||||
|
* @property {Boolean} show-icon 是否显示左边的辅助图标
|
||||||
|
* @property {Boolean} show 显示或隐藏组件
|
||||||
|
* @event {Function} click 点击组件时触发
|
||||||
|
* @event {Function} close 点击关闭按钮时触发
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-alert-tips',
|
||||||
|
props: {
|
||||||
|
// 显示文字
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 主题,success/warning/info/error
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'warning'
|
||||||
|
},
|
||||||
|
// 辅助性文字
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否可关闭
|
||||||
|
closeAble: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 关闭按钮自定义文本
|
||||||
|
closeText: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示图标
|
||||||
|
showIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 文字颜色,如果定义了color值,icon会失效
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 边框颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 左边显示的icon
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// icon的样式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 标题的样式
|
||||||
|
titleStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 描述文字的样式
|
||||||
|
descStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
uTitleStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 如果有描述文字的话,标题进行加粗
|
||||||
|
style.fontWeight = this.description ? 500 : 'normal';
|
||||||
|
// 将用户传入样式对象和style合并,传入的优先级比style高,同属性会被覆盖
|
||||||
|
return this.$u.deepMerge(style, this.titleStyle);
|
||||||
|
},
|
||||||
|
uIcon() {
|
||||||
|
// 如果有设置icon名称就使用,否则根据type主题,推定一个默认的图标
|
||||||
|
return this.icon ? this.icon : this.$u.type2icon(this.type);
|
||||||
|
},
|
||||||
|
uIconType() {
|
||||||
|
// 如果有设置图标的样式,优先使用,没有的话,则用type的样式
|
||||||
|
return Object.keys(this.iconStyle).length ? '' : this.type;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击内容
|
||||||
|
click() {
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
// 点击关闭按钮
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-alert-tips {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16rpx 30rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
position: relative;
|
||||||
|
transition: all 0.3s linear;
|
||||||
|
border: 1px solid #fff;
|
||||||
|
|
||||||
|
&--bg--primary-light {
|
||||||
|
background-color: $u-type-primary-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--info-light {
|
||||||
|
background-color: $u-type-info-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--success-light {
|
||||||
|
background-color: $u-type-success-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--warning-light {
|
||||||
|
background-color: $u-type-warning-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--error-light {
|
||||||
|
background-color: $u-type-error-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--primary-disabled {
|
||||||
|
border-color: $u-type-primary-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--success-disabled {
|
||||||
|
border-color: $u-type-success-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--error-disabled {
|
||||||
|
border-color: $u-type-error-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--warning-disabled {
|
||||||
|
border-color: $u-type-warning-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border--info-disabled {
|
||||||
|
border-color: $u-type-info-disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-alert-tips {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-icon {
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-alert-title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-alert-desc {
|
||||||
|
font-size: 26rpx;
|
||||||
|
text-align: left;
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-hover {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-close-text {
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
position: absolute;
|
||||||
|
top: 20rpx;
|
||||||
|
right: 20rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
290
node_modules/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue
generated
vendored
Normal file
290
node_modules/uview-ui/components/u-avatar-cropper/u-avatar-cropper.vue
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
|||||||
|
<template>
|
||||||
|
<view class="content">
|
||||||
|
<view class="cropper-wrapper" :style="{ height: cropperOpt.height + 'px' }">
|
||||||
|
<canvas
|
||||||
|
class="cropper"
|
||||||
|
:disable-scroll="true"
|
||||||
|
@touchstart="touchStart"
|
||||||
|
@touchmove="touchMove"
|
||||||
|
@touchend="touchEnd"
|
||||||
|
:style="{ width: cropperOpt.width, height: cropperOpt.height, backgroundColor: 'rgba(0, 0, 0, 0.8)' }"
|
||||||
|
canvas-id="cropper"
|
||||||
|
id="cropper"
|
||||||
|
></canvas>
|
||||||
|
<canvas
|
||||||
|
class="cropper"
|
||||||
|
:disable-scroll="true"
|
||||||
|
:style="{
|
||||||
|
position: 'fixed',
|
||||||
|
top: `-${cropperOpt.width * cropperOpt.pixelRatio}px`,
|
||||||
|
left: `-${cropperOpt.height * cropperOpt.pixelRatio}px`,
|
||||||
|
width: `${cropperOpt.width * cropperOpt.pixelRatio}px`,
|
||||||
|
height: `${cropperOpt.height * cropperOpt.pixelRatio}`
|
||||||
|
}"
|
||||||
|
canvas-id="targetId"
|
||||||
|
id="targetId"
|
||||||
|
></canvas>
|
||||||
|
</view>
|
||||||
|
<view class="cropper-buttons safe-area-padding" :style="{ height: bottomNavHeight + 'px' }">
|
||||||
|
<!-- #ifdef H5 -->
|
||||||
|
<view class="upload" @tap="uploadTap">选择图片</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<!-- #ifndef H5 -->
|
||||||
|
<view class="upload" @tap="uploadTap">重新选择</view>
|
||||||
|
<!-- #endif -->
|
||||||
|
<view class="getCropperImage" @tap="getCropperImage(false)">确定</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import WeCropper from './weCropper.js';
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 裁剪矩形框的样式,其中可包含的属性为lineWidth-边框宽度(单位rpx),color: 边框颜色,
|
||||||
|
// mask-遮罩颜色,一般设置为一个rgba的透明度,如"rgba(0, 0, 0, 0.35)"
|
||||||
|
boundStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
lineWidth: 4,
|
||||||
|
borderColor: 'rgb(245, 245, 245)',
|
||||||
|
mask: 'rgba(0, 0, 0, 0.35)'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// // 裁剪框宽度,单位rpx
|
||||||
|
// rectWidth: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 裁剪框高度,单位rpx
|
||||||
|
// rectHeight: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出图片宽度,单位rpx
|
||||||
|
// destWidth: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出图片高度,单位rpx
|
||||||
|
// destHeight: {
|
||||||
|
// type: [String, Number],
|
||||||
|
// default: 400
|
||||||
|
// },
|
||||||
|
// // 输出的图片类型,如果发现裁剪的图片很大,可能是因为设置为了"png",改成"jpg"即可
|
||||||
|
// fileType: {
|
||||||
|
// type: String,
|
||||||
|
// default: 'jpg',
|
||||||
|
// },
|
||||||
|
// // 生成的图片质量
|
||||||
|
// // H5上无效,目前不考虑使用此参数
|
||||||
|
// quality: {
|
||||||
|
// type: [Number, String],
|
||||||
|
// default: 1
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 底部导航的高度
|
||||||
|
bottomNavHeight: 50,
|
||||||
|
originWidth: 200,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
cropperOpt: {
|
||||||
|
id: 'cropper',
|
||||||
|
targetId: 'targetCropper',
|
||||||
|
pixelRatio: 1,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
scale: 2.5,
|
||||||
|
zoom: 8,
|
||||||
|
cut: {
|
||||||
|
x: (this.width - this.originWidth) / 2,
|
||||||
|
y: (this.height - this.originWidth) / 2,
|
||||||
|
width: this.originWidth,
|
||||||
|
height: this.originWidth
|
||||||
|
},
|
||||||
|
boundStyle: {
|
||||||
|
lineWidth: uni.upx2px(this.boundStyle.lineWidth),
|
||||||
|
mask: this.boundStyle.mask,
|
||||||
|
color: this.boundStyle.borderColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 裁剪框和输出图片的尺寸,高度默认等于宽度
|
||||||
|
// 输出图片宽度,单位px
|
||||||
|
destWidth: 200,
|
||||||
|
// 裁剪框宽度,单位px
|
||||||
|
rectWidth: 200,
|
||||||
|
// 输出的图片类型,如果'png'类型发现裁剪的图片太大,改成"jpg"即可
|
||||||
|
fileType: 'jpg',
|
||||||
|
src: '', // 选择的图片路径,用于在点击确定时,判断是否选择了图片
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onLoad(option) {
|
||||||
|
let rectInfo = uni.getSystemInfoSync();
|
||||||
|
this.width = rectInfo.windowWidth;
|
||||||
|
this.height = rectInfo.windowHeight - this.bottomNavHeight;
|
||||||
|
this.cropperOpt.width = this.width;
|
||||||
|
this.cropperOpt.height = this.height;
|
||||||
|
this.cropperOpt.pixelRatio = rectInfo.pixelRatio;
|
||||||
|
|
||||||
|
if (option.destWidth) this.destWidth = option.destWidth;
|
||||||
|
if (option.rectWidth) {
|
||||||
|
let rectWidth = Number(option.rectWidth);
|
||||||
|
this.cropperOpt.cut = {
|
||||||
|
x: (this.width - rectWidth) / 2,
|
||||||
|
y: (this.height - rectWidth) / 2,
|
||||||
|
width: rectWidth,
|
||||||
|
height: rectWidth
|
||||||
|
};
|
||||||
|
}
|
||||||
|
this.rectWidth = option.rectWidth;
|
||||||
|
if (option.fileType) this.fileType = option.fileType;
|
||||||
|
// 初始化
|
||||||
|
this.cropper = new WeCropper(this.cropperOpt)
|
||||||
|
.on('ready', ctx => {
|
||||||
|
// wecropper is ready for work!
|
||||||
|
})
|
||||||
|
.on('beforeImageLoad', ctx => {
|
||||||
|
// before picture loaded, i can do something
|
||||||
|
})
|
||||||
|
.on('imageLoad', ctx => {
|
||||||
|
// picture loaded
|
||||||
|
})
|
||||||
|
.on('beforeDraw', (ctx, instance) => {
|
||||||
|
// before canvas draw,i can do something
|
||||||
|
});
|
||||||
|
// 设置导航栏样式,以免用户在page.json中没有设置为黑色背景
|
||||||
|
uni.setNavigationBarColor({
|
||||||
|
frontColor: '#ffffff',
|
||||||
|
backgroundColor: '#000000'
|
||||||
|
});
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1, // 默认9
|
||||||
|
sizeType: ['compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||||||
|
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
|
||||||
|
success: res => {
|
||||||
|
this.src = res.tempFilePaths[0];
|
||||||
|
// 获取裁剪图片资源后,给data添加src属性及其值
|
||||||
|
this.cropper.pushOrign(this.src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
touchStart(e) {
|
||||||
|
this.cropper.touchStart(e);
|
||||||
|
},
|
||||||
|
touchMove(e) {
|
||||||
|
this.cropper.touchMove(e);
|
||||||
|
},
|
||||||
|
touchEnd(e) {
|
||||||
|
this.cropper.touchEnd(e);
|
||||||
|
},
|
||||||
|
getCropperImage(isPre = false) {
|
||||||
|
if(!this.src) return this.$u.toast('请先选择图片再裁剪');
|
||||||
|
|
||||||
|
let cropper_opt = {
|
||||||
|
destHeight: Number(this.destWidth), // uni.canvasToTempFilePath要求这些参数为数值
|
||||||
|
destWidth: Number(this.destWidth),
|
||||||
|
fileType: this.fileType
|
||||||
|
};
|
||||||
|
this.cropper.getCropperImage(cropper_opt, (path, err) => {
|
||||||
|
if (err) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '温馨提示',
|
||||||
|
content: err.message
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (isPre) {
|
||||||
|
uni.previewImage({
|
||||||
|
current: '', // 当前显示图片的 http 链接
|
||||||
|
urls: [path] // 需要预览的图片 http 链接列表
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
uni.$emit('uAvatarCropper', path);
|
||||||
|
this.$u.route({
|
||||||
|
type: 'back'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
uploadTap() {
|
||||||
|
const self = this;
|
||||||
|
uni.chooseImage({
|
||||||
|
count: 1, // 默认9
|
||||||
|
sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
|
||||||
|
sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
|
||||||
|
success: (res) => {
|
||||||
|
self.src = res.tempFilePaths[0];
|
||||||
|
// 获取裁剪图片资源后,给data添加src属性及其值
|
||||||
|
|
||||||
|
self.cropper.pushOrign(this.src);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../../libs/css/style.components.scss';
|
||||||
|
|
||||||
|
.content {
|
||||||
|
background: rgba(255, 255, 255, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons {
|
||||||
|
background-color: #000000;
|
||||||
|
color: #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-wrapper {
|
||||||
|
position: relative;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons {
|
||||||
|
width: 100vw;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .upload,
|
||||||
|
.cropper-buttons .getCropperImage {
|
||||||
|
width: 50%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .upload {
|
||||||
|
text-align: left;
|
||||||
|
padding-left: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cropper-buttons .getCropperImage {
|
||||||
|
text-align: right;
|
||||||
|
padding-right: 50rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
1265
node_modules/uview-ui/components/u-avatar-cropper/weCropper.js
generated
vendored
Normal file
1265
node_modules/uview-ui/components/u-avatar-cropper/weCropper.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
244
node_modules/uview-ui/components/u-avatar/u-avatar.vue
generated
vendored
Normal file
244
node_modules/uview-ui/components/u-avatar/u-avatar.vue
generated
vendored
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-avatar" :style="[wrapStyle]" @tap="click">
|
||||||
|
<image
|
||||||
|
@error="loadError"
|
||||||
|
:style="[imgStyle]"
|
||||||
|
class="u-avatar__img"
|
||||||
|
v-if="!uText && avatar"
|
||||||
|
:src="avatar"
|
||||||
|
:mode="imgMode"
|
||||||
|
></image>
|
||||||
|
<text class="u-line-1" v-else-if="uText" :style="{
|
||||||
|
fontSize: '38rpx'
|
||||||
|
}">{{uText}}</text>
|
||||||
|
<slot v-else></slot>
|
||||||
|
<view class="u-avatar__sex" v-if="showSex" :class="['u-avatar__sex--' + sexIcon]" :style="[uSexStyle]">
|
||||||
|
<u-icon :name="sexIcon" size="20"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-avatar__level" v-if="showLevel" :style="[uLevelStyle]">
|
||||||
|
<u-icon :name="levelIcon" size="20"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
let base64Avatar = "data:image/jpg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMraHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDUzYgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjREMEQwRkY0RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjREMEQwRkY1RjgwNDExRUE5OTY2RDgxODY3NkJFODMxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NEQwRDBGRjJGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NEQwRDBGRjNGODA0MTFFQTk5NjZEODE4Njc2QkU4MzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwMDAwMDBAMDg8QDw4MExMUFBMTHBsbGxwfHx8fHx8fHx8fAQcHBw0MDRgQEBgaFREVGh8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx//wAARCADIAMgDAREAAhEBAxEB/8QAcQABAQEAAwEBAAAAAAAAAAAAAAUEAQMGAgcBAQAAAAAAAAAAAAAAAAAAAAAQAAIBAwICBgkDBQAAAAAAAAABAhEDBCEFMVFBYXGREiKBscHRMkJSEyOh4XLxYjNDFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8A/fAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHbHFyZ/Dam+yLA+Z2L0Pjtyj2poD4AAAAAAAAAAAAAAAAAAAAAAAAKWFs9y6lcvvwQeqj8z9wFaziY1n/HbUX9XF97A7QAGXI23EvJ1goyfzR0YEfN269jeZ+a03pNe0DIAAAAAAAAAAAAAAAAAAAACvtO3RcVkXlWutuL9YFYAAAAAOJRjKLjJVi9GmB5/csH/mu1h/in8PU+QGMAAAAAAAAAAAAAAAAAAaMDG/6MmMH8C80+xAelSSVFolwQAAAAAAAHVlWI37ErUulaPk+hgeYnCUJuElSUXRrrQHAAAAAAAAAAAAAAAAABa2Oz4bM7r4zdF2ICmAAAAAAAAAg7zZ8GX41wuJP0rRgYAAAAAAAAAAAAAAAAAD0m2R8ODaXU33tsDSAAAAAAAAAlb9HyWZcnJd9PcBHAAAAAAAAAAAAAAAAAPS7e64Vn+KA0AAAAAAAAAJm+v8Ftf3ewCKAAAAAAAAAAAAAAAAAX9muqeGo9NttP06+0DcAAAAAAAAAjb7dTu2ra+VOT9P8AQCWAAAAAAAAAAAAAAAAAUNmyPt5Ltv4bui/kuAF0AAAAAAADiUlGLlJ0SVW+oDzOXfd/Ind6JPRdS0QHSAAAAAAAAAAAAAAAAAE2nVaNcGB6Lbs6OTao9LsF51z60BrAAAAAABJ3jOVHjW3r/sa9QEgAAAAAAAAAAAAAAAAAAAPu1duWriuW34ZR4MC9hbnZyEoy8l36XwfYBsAAADaSq9EuLAlZ+7xSdrGdW9Hc5dgEdtt1erfFgAAAAAAAAAAAAAAAAADVjbblX6NR8MH80tEBRs7HYivyzlN8lovaBPzduvY0m6eK10TXtAyAarO55lpJK54orolr+4GqO/Xaea1FvqbXvA+Z77kNeW3GPbV+4DJfzcm/pcm3H6Vou5AdAFLC2ed2Pjv1txa8sV8T6wOL+yZEKu1JXFy4MDBOE4ScZxcZLinoB8gAAAAAAAAAAAB242LeyJ+C3GvN9C7QLmJtePYpKS+5c+p8F2IDYAANJqj1T4oCfk7Nj3G5Wn9qXJax7gJ93Z82D8sVNc4v30A6Xg5i42Z+iLfqARwcyT0sz9MWvWBps7LlTf5Grce9/oBTxdtxseklHxT+uWr9AGoAB138ezfj4bsFJdD6V2MCPm7RdtJzs1uW1xXzL3gTgAAAAAAAAADRhYc8q74I6RWs5ckB6GxYtWLat21SK731sDsAAAAAAAAAAAAAAAASt021NO/YjrxuQXT1oCOAAAAAAABzGLlJRSq26JAelwsWONYjbXxcZvmwO8AAAAAAAAAAAAAAAAAAef3TEWPkVivx3NY9T6UBiAAAAAABo2+VmGXblddIJ8eivRUD0oAAAAAAAAAAAAAAAAAAAYt4tKeFKVNYNSXfRgefAAAAAAAAr7VuSSWPedKaW5v1MCsAAAAAAAAAAAAAAAAAAIe6bj96Ts2n+JPzSXzP3ATgAAAAAAAAFbbt1UUrOQ9FpC4/UwK6aaqtU+DAAAAAAAAAAAAAAA4lKMIuUmoxWrb4ARNx3R3q2rLpa4Sl0y/YCcAAAAAAAAAAANmFud7G8r89r6X0dgFvGzLGRGtuWvTF6NAdwAAAAAAAAAAAy5W442PVN+K59EePp5ARMvOv5MvO6QXCC4AZwAAAAAAAAAAAAAcxlKLUotprg1owN+PvORborq+7Hnwl3gUbO74VzRydt8pKn68ANcJwmqwkpLmnUDkAAAAfNy9atqtyagut0AxXt5xIV8Fbj6lRd7Am5G65V6qUvtwfyx94GMAAAAAAAAAAAAAAAAAAAOU2nVOj5gdsc3LiqRvTpyqwOxbnnrhdfpSfrQB7pnv/AGvuS9gHXPMy5/Fem1yq0v0A6W29XqwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAf//Z";
|
||||||
|
/**
|
||||||
|
* avatar 头像
|
||||||
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
|
* @tutorial https://www.uviewui.com/components/avatar.html
|
||||||
|
* @property {String} bg-color 背景颜色,一般显示文字时用(默认#ffffff)
|
||||||
|
* @property {String} src 头像路径,如加载失败,将会显示默认头像
|
||||||
|
* @property {String Number} size 头像尺寸,可以为指定字符串(large, default, mini),或者数值,单位rpx(默认default)
|
||||||
|
* @property {String} mode 显示类型,见上方说明(默认circle)
|
||||||
|
* @property {String} sex-icon 性别图标,man-男,woman-女(默认man)
|
||||||
|
* @property {String} level-icon 等级图标(默认level)
|
||||||
|
* @property {String} sex-bg-color 性别图标背景颜色
|
||||||
|
* @property {String} level-bg-color 等级图标背景颜色
|
||||||
|
* @property {String} show-sex 是否显示性别图标(默认false)
|
||||||
|
* @property {String} show-level 是否显示等级图标(默认false)
|
||||||
|
* @property {String} img-mode 头像图片的裁剪类型,与uni的image组件的mode参数一致,如效果达不到需求,可尝试传widthFix值(默认aspectFill)
|
||||||
|
* @property {String} index 用户传递的标识符值,如果是列表循环,可穿v-for的index值
|
||||||
|
* @event {Function} click 头像被点击
|
||||||
|
* @example <u-avatar :src="src"></u-avatar>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-avatar',
|
||||||
|
props: {
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
// 头像路径
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 尺寸,large-大,default-中等,mini-小,如果为数值,则单位为rpx
|
||||||
|
// 宽度等于高度
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
// 头像模型,square-带圆角方形,circle-圆形
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'circle'
|
||||||
|
},
|
||||||
|
// 文字内容
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 图片的裁剪模型
|
||||||
|
imgMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'aspectFill'
|
||||||
|
},
|
||||||
|
// 标识符
|
||||||
|
index: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右上角性别角标,man-男,woman-女
|
||||||
|
sexIcon: {
|
||||||
|
type: String,
|
||||||
|
default: 'man'
|
||||||
|
},
|
||||||
|
// 右下角的等级图标
|
||||||
|
levelIcon: {
|
||||||
|
type: String,
|
||||||
|
default: 'level'
|
||||||
|
},
|
||||||
|
// 右下角等级图标背景颜色
|
||||||
|
levelBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右上角性别图标的背景颜色
|
||||||
|
sexBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示性别图标
|
||||||
|
showSex: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示等级图标
|
||||||
|
showLevel: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
error: false,
|
||||||
|
// 头像的地址,因为如果加载错误,需要赋值为默认图片,props值无法修改,所以需要一个中间值
|
||||||
|
avatar: this.src ? this.src : base64Avatar,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src(n) {
|
||||||
|
// 用户可能会在头像加载失败时,再次修改头像值,所以需要重新赋值
|
||||||
|
if(!n) {
|
||||||
|
// 如果传入null或者'',或者undefined,显示默认头像
|
||||||
|
this.avatar = base64Avatar;
|
||||||
|
this.error = true;
|
||||||
|
} else {
|
||||||
|
this.avatar = n;
|
||||||
|
this.error = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
wrapStyle() {
|
||||||
|
let style = {};
|
||||||
|
style.height = this.size == 'large' ? '120rpx' : this.size == 'default' ?
|
||||||
|
'90rpx' : this.size == 'mini' ? '70rpx' : this.size + 'rpx';
|
||||||
|
style.width = style.height;
|
||||||
|
style.flex = `0 0 ${style.height}`;
|
||||||
|
style.backgroundColor = this.bgColor;
|
||||||
|
style.borderRadius = this.mode == 'circle' ? '500px' : '5px';
|
||||||
|
if(this.text) style.padding = `0 6rpx`;
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
imgStyle() {
|
||||||
|
let style = {};
|
||||||
|
style.borderRadius = this.mode == 'circle' ? '500px' : '5px';
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 取字符串的第一个字符
|
||||||
|
uText() {
|
||||||
|
return String(this.text)[0];
|
||||||
|
},
|
||||||
|
// 性别图标的自定义样式
|
||||||
|
uSexStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.sexBgColor) style.backgroundColor = this.sexBgColor;
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 等级图标的自定义样式
|
||||||
|
uLevelStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.levelBgColor) style.backgroundColor = this.levelBgColor;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 图片加载错误时,显示默认头像
|
||||||
|
loadError() {
|
||||||
|
this.error = true;
|
||||||
|
this.avatar = base64Avatar;
|
||||||
|
},
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-avatar {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
border-radius: 10px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__sex {
|
||||||
|
position: absolute;
|
||||||
|
width: 32rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
height: 32rpx;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 100rpx;
|
||||||
|
top: 5%;
|
||||||
|
z-index: 1;
|
||||||
|
right: -7%;
|
||||||
|
border: 1px #ffffff solid;
|
||||||
|
|
||||||
|
&--man {
|
||||||
|
background-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--woman {
|
||||||
|
background-color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--none {
|
||||||
|
background-color: $u-type-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__level {
|
||||||
|
position: absolute;
|
||||||
|
width: 32rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
height: 32rpx;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 100rpx;
|
||||||
|
bottom: 5%;
|
||||||
|
z-index: 1;
|
||||||
|
right: -7%;
|
||||||
|
border: 1px #ffffff solid;
|
||||||
|
background-color: $u-type-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
153
node_modules/uview-ui/components/u-back-top/u-back-top.vue
generated
vendored
Normal file
153
node_modules/uview-ui/components/u-back-top/u-back-top.vue
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<template>
|
||||||
|
<view @tap="backToTop" class="u-back-top" :class="['u-back-top--mode--' + mode]" :style="[{
|
||||||
|
bottom: bottom + 'rpx',
|
||||||
|
right: right + 'rpx',
|
||||||
|
borderRadius: mode == 'circle' ? '10000rpx' : '8rpx',
|
||||||
|
zIndex: uZIndex,
|
||||||
|
opacity: opacity
|
||||||
|
}, customStyle]">
|
||||||
|
<view class="u-back-top__content" v-if="!$slots.default && !$slots.$default">
|
||||||
|
<u-icon @click="backToTop" :name="icon" :custom-style="iconStyle"></u-icon>
|
||||||
|
<view class="u-back-top__content__tips">
|
||||||
|
{{tips}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot v-else />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'u-back-top',
|
||||||
|
props: {
|
||||||
|
// 返回顶部的形状,circle-圆形,square-方形
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'circle'
|
||||||
|
},
|
||||||
|
// 自定义图标
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: 'arrow-upward'
|
||||||
|
},
|
||||||
|
// 提示文字
|
||||||
|
tips: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 返回顶部滚动时间
|
||||||
|
duration: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 100
|
||||||
|
},
|
||||||
|
// 滚动距离
|
||||||
|
scrollTop: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 距离顶部多少距离显示,单位rpx
|
||||||
|
top: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 400
|
||||||
|
},
|
||||||
|
// 返回顶部按钮到底部的距离,单位rpx
|
||||||
|
bottom: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
// 返回顶部按钮到右边的距离,单位rpx
|
||||||
|
right: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 40
|
||||||
|
},
|
||||||
|
// 层级
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '9'
|
||||||
|
},
|
||||||
|
// 图标的样式,对象形式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
color: '#909399',
|
||||||
|
fontSize: '38rpx'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 整个组件的样式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
showBackTop(nVal, oVal) {
|
||||||
|
// 当组件的显示与隐藏状态发生跳变时,修改组件的层级和不透明度
|
||||||
|
// 让组件有显示和消失的动画效果,如果用v-if控制组件状态,将无设置动画效果
|
||||||
|
if(nVal) {
|
||||||
|
this.uZIndex = this.zIndex;
|
||||||
|
this.opacity = 1;
|
||||||
|
} else {
|
||||||
|
this.uZIndex = -1;
|
||||||
|
this.opacity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showBackTop() {
|
||||||
|
// 由于scrollTop为页面的滚动距离,默认为px单位,这里将用于传入的top(rpx)值
|
||||||
|
// 转为px用于比较,如果滚动条到顶的距离大于设定的距离,就显示返回顶部的按钮
|
||||||
|
return this.scrollTop > uni.upx2px(this.top);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 不透明度,为了让组件有一个显示和隐藏的过渡动画
|
||||||
|
opacity: 0,
|
||||||
|
// 组件的z-index值,隐藏时设置为-1,就会看不到
|
||||||
|
uZIndex: -1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
backToTop() {
|
||||||
|
uni.pageScrollTo({
|
||||||
|
scrollTop: 0,
|
||||||
|
duration: this.duration
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-back-top {
|
||||||
|
width: 80rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 9;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: #E1E1E1;
|
||||||
|
color: $u-content-color;
|
||||||
|
align-items: center;
|
||||||
|
transition: opacity 0.4s;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__tips {
|
||||||
|
font-size: 24rpx;
|
||||||
|
transform: scale(0.8);
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
216
node_modules/uview-ui/components/u-badge/u-badge.vue
generated
vendored
Normal file
216
node_modules/uview-ui/components/u-badge/u-badge.vue
generated
vendored
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
<template>
|
||||||
|
<view v-if="show" class="u-badge" :class="[
|
||||||
|
isDot ? 'u-badge-dot' : '',
|
||||||
|
size == 'mini' ? 'u-badge-mini' : '',
|
||||||
|
type ? 'u-badge--bg--' + type : ''
|
||||||
|
]" :style="[{
|
||||||
|
top: offset[0] + 'rpx',
|
||||||
|
right: offset[1] + 'rpx',
|
||||||
|
fontSize: fontSize + 'rpx',
|
||||||
|
position: absolute ? 'absolute' : 'static',
|
||||||
|
color: color,
|
||||||
|
backgroundColor: bgColor
|
||||||
|
}, boxStyle]"
|
||||||
|
>
|
||||||
|
{{showText}}
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* badge 角标
|
||||||
|
* @description 本组件一般用于展示头像的地方,如个人中心,或者评论列表页的用户头像展示等场所。
|
||||||
|
* @tutorial https://www.uviewui.com/components/badge.html
|
||||||
|
* @property {String Number} count 展示的数字,大于 overflowCount 时显示为 ${overflowCount}+,为0且show-zero为false时隐藏
|
||||||
|
* @property {Boolean} is-dot 不展示数字,只有一个小点(默认false)
|
||||||
|
* @property {Boolean} absolute 组件是否绝对定位,为true时,offset参数才有效(默认true)
|
||||||
|
* @property {String Number} overflow-count 展示封顶的数字值(默认99)
|
||||||
|
* @property {String} type 使用预设的背景颜色(默认error)
|
||||||
|
* @property {Boolean} show-zero 当数值为 0 时,是否展示 Badge(默认false)
|
||||||
|
* @property {String} size Badge的尺寸,设为mini会得到小一号的Badge(默认default)
|
||||||
|
* @property {Array} offset 设置badge的位置偏移,格式为 [x, y],也即设置的为top和right的值,单位rpx。absolute为true时有效(默认[20, 20])
|
||||||
|
* @property {String} color 字体颜色(默认#ffffff)
|
||||||
|
* @property {String} bgColor 背景颜色,优先级比type高,如设置,type参数会失效
|
||||||
|
* @property {Boolean} is-center 组件中心点是否和父组件右上角重合,优先级比offset高,如设置,offset参数会失效(默认false)
|
||||||
|
* @example <u-badge type="error" count="7"></u-badge>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-badge',
|
||||||
|
props: {
|
||||||
|
// primary,warning,success,error,info
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'error'
|
||||||
|
},
|
||||||
|
// default, mini
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
//是否是圆点
|
||||||
|
isDot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 显示的数值内容
|
||||||
|
count: {
|
||||||
|
type: [Number, String],
|
||||||
|
},
|
||||||
|
// 展示封顶的数字值
|
||||||
|
overflowCount: {
|
||||||
|
type: Number,
|
||||||
|
default: 99
|
||||||
|
},
|
||||||
|
// 当数值为 0 时,是否展示 Badge
|
||||||
|
showZero: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 位置偏移
|
||||||
|
offset: {
|
||||||
|
type: Array,
|
||||||
|
default: () => {
|
||||||
|
return [20, 20]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否开启绝对定位,开启了offset才会起作用
|
||||||
|
absolute: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
fontSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '24'
|
||||||
|
},
|
||||||
|
// 字体演示
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
},
|
||||||
|
// badge的背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否让badge组件的中心点和父组件右上角重合,配置的话,offset将会失效
|
||||||
|
isCenter: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 是否将badge中心与父组件右上角重合
|
||||||
|
boxStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.isCenter) {
|
||||||
|
style.top = 0;
|
||||||
|
style.right = 0;
|
||||||
|
// Y轴-50%,意味着badge向上移动了badge自身高度一半,X轴50%,意味着向右移动了自身宽度一半
|
||||||
|
style.transform = "translateY(-50%) translateX(50%)";
|
||||||
|
} else {
|
||||||
|
style.top = this.offset[0] + 'rpx';
|
||||||
|
style.right = this.offset[1] + 'rpx';
|
||||||
|
style.transform = "translateY(0) translateX(0)";
|
||||||
|
}
|
||||||
|
// 如果尺寸为mini,后接上scal()
|
||||||
|
if(this.size == 'mini') {
|
||||||
|
style.transform = style.transform + " scale(0.8)";
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// isDot类型时,不显示文字
|
||||||
|
showText() {
|
||||||
|
if(this.isDot) return '';
|
||||||
|
else {
|
||||||
|
if(this.count > this.overflowCount) return `${this.overflowCount}+`;
|
||||||
|
else return this.count;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否显示组件
|
||||||
|
show() {
|
||||||
|
// 如果count的值为0,并且showZero设置为false,不显示组件
|
||||||
|
if(this.count == 0 && this.showZero == false) return false;
|
||||||
|
else return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-badge {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
line-height: 24rpx;
|
||||||
|
padding: 4rpx 8rpx;
|
||||||
|
border-radius: 100rpx;
|
||||||
|
z-index: 9;
|
||||||
|
|
||||||
|
&--bg--primary {
|
||||||
|
background-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--error {
|
||||||
|
background-color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--success {
|
||||||
|
background-color: $u-type-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--info {
|
||||||
|
background-color: $u-type-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bg--warning {
|
||||||
|
background-color: $u-type-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-badge-dot {
|
||||||
|
height: 16rpx;
|
||||||
|
width: 16rpx;
|
||||||
|
border-radius: 100rpx;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-badge-mini {
|
||||||
|
transform: scale(0.8);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .u-primary {
|
||||||
|
// background: $u-type-primary;
|
||||||
|
// color: #fff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .u-error {
|
||||||
|
// background: $u-type-error;
|
||||||
|
// color: #fff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .u-warning {
|
||||||
|
// background: $u-type-warning;
|
||||||
|
// color: #fff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .u-success {
|
||||||
|
// background: $u-type-success;
|
||||||
|
// color: #fff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// .u-black {
|
||||||
|
// background: #585858;
|
||||||
|
// color: #fff;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.u-info {
|
||||||
|
background-color: $u-type-info;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
596
node_modules/uview-ui/components/u-button/u-button.vue
generated
vendored
Normal file
596
node_modules/uview-ui/components/u-button/u-button.vue
generated
vendored
Normal file
@@ -0,0 +1,596 @@
|
|||||||
|
<template>
|
||||||
|
<button
|
||||||
|
id="u-wave-btn"
|
||||||
|
class="u-btn u-line-1 u-fix-ios-appearance"
|
||||||
|
:class="[
|
||||||
|
'u-size-' + size,
|
||||||
|
plain ? 'u-btn--' + type + '--plain' : '',
|
||||||
|
loading ? 'u-loading' : '',
|
||||||
|
shape == 'circle' ? 'u-round-circle' : '',
|
||||||
|
hairLine ? showHairLineBorder : 'u-btn--bold-border',
|
||||||
|
'u-btn--' + type,
|
||||||
|
disabled ? `u-btn--${type}--disabled` : '',
|
||||||
|
]"
|
||||||
|
:hover-start-time="Number(hoverStartTime)"
|
||||||
|
:hover-stay-time="Number(hoverStayTime)"
|
||||||
|
:disabled="disabled"
|
||||||
|
:form-type="formType"
|
||||||
|
:open-type="openType"
|
||||||
|
:app-parameter="appParameter"
|
||||||
|
:hover-stop-propagation="hoverStopPropagation"
|
||||||
|
:send-message-title="sendMessageTitle"
|
||||||
|
send-message-path="sendMessagePath"
|
||||||
|
:lang="lang"
|
||||||
|
:data-name="dataName"
|
||||||
|
:session-from="sessionFrom"
|
||||||
|
:send-message-img="sendMessageImg"
|
||||||
|
:show-message-card="showMessageCard"
|
||||||
|
@getphonenumber="getphonenumber"
|
||||||
|
@getuserinfo="getuserinfo"
|
||||||
|
@error="error"
|
||||||
|
@opensetting="opensetting"
|
||||||
|
@launchapp="launchapp"
|
||||||
|
:style="[customStyle, {
|
||||||
|
overflow: ripple ? 'hidden' : 'visible'
|
||||||
|
}]"
|
||||||
|
@tap.stop="click($event)"
|
||||||
|
:hover-class="getHoverClass"
|
||||||
|
:loading="loading"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
<view
|
||||||
|
v-if="ripple"
|
||||||
|
class="u-wave-ripple"
|
||||||
|
:class="[waveActive ? 'u-wave-active' : '']"
|
||||||
|
:style="{
|
||||||
|
top: rippleTop + 'px',
|
||||||
|
left: rippleLeft + 'px',
|
||||||
|
width: fields.targetWidth + 'px',
|
||||||
|
height: fields.targetWidth + 'px',
|
||||||
|
'background-color': rippleBgColor || 'rgba(0, 0, 0, 0.15)'
|
||||||
|
}"
|
||||||
|
></view>
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* button 按钮
|
||||||
|
* @description Button 按钮
|
||||||
|
* @tutorial https://www.uviewui.com/components/button.html
|
||||||
|
* @property {String} size 按钮的大小
|
||||||
|
* @property {Boolean} ripple 是否开启点击水波纹效果
|
||||||
|
* @property {String} ripple-bg-color 水波纹的背景色,ripple为true时有效
|
||||||
|
* @property {String} type 按钮的样式类型
|
||||||
|
* @property {Boolean} plain 按钮是否镂空,背景色透明
|
||||||
|
* @property {Boolean} disabled 是否禁用
|
||||||
|
* @property {Boolean} hair-line 是否显示按钮的细边框(默认true)
|
||||||
|
* @property {Boolean} shape 按钮外观形状,见文档说明
|
||||||
|
* @property {Boolean} loading 按钮名称前是否带 loading 图标(App-nvue 平台,在 ios 上为雪花,Android上为圆圈)
|
||||||
|
* @property {String} form-type 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
|
||||||
|
* @property {String} open-type 开放能力
|
||||||
|
* @property {String} data-name 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
|
||||||
|
* @property {String} hover-class 指定按钮按下去的样式类。当 hover-class="none" 时,没有点击态效果(App-nvue 平台暂不支持)
|
||||||
|
* @property {Number} hover-start-time 按住后多久出现点击态,单位毫秒
|
||||||
|
* @property {Number} hover-stay-time 手指松开后点击态保留时间,单位毫秒
|
||||||
|
* @property {Object} custom-style 对按钮的自定义样式,对象形式,见文档说明
|
||||||
|
* @event {Function} click 按钮点击
|
||||||
|
* @event {Function} getphonenumber open-type="getPhoneNumber"时有效
|
||||||
|
* @event {Function} getuserinfo 用户点击该按钮时,会返回获取到的用户信息,从返回参数的detail中获取到的值同uni.getUserInfo
|
||||||
|
* @event {Function} error 当使用开放能力时,发生错误的回调
|
||||||
|
* @event {Function} opensetting 在打开授权设置页并关闭后回调
|
||||||
|
* @event {Function} launchapp 打开 APP 成功的回调
|
||||||
|
* @example <u-button>月落</u-button>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-button',
|
||||||
|
props: {
|
||||||
|
// 是否细边框
|
||||||
|
hairLine: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 按钮的预置样式,default,primary,error,warning,success
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
// 按钮尺寸,default,medium,mini
|
||||||
|
size: {
|
||||||
|
type: String,
|
||||||
|
default: 'default'
|
||||||
|
},
|
||||||
|
// 按钮形状,circle(两边为半圆),square(带圆角)
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
// 按钮是否镂空
|
||||||
|
plain: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否禁止状态
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否加载中
|
||||||
|
loading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 开放能力,具体请看uniapp稳定关于button组件部分说明
|
||||||
|
// https://uniapp.dcloud.io/component/button
|
||||||
|
openType: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 用于 <form> 组件,点击分别会触发 <form> 组件的 submit/reset 事件
|
||||||
|
// 取值为submit(提交表单),reset(重置表单)
|
||||||
|
formType: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 打开 APP 时,向 APP 传递的参数,open-type=launchApp时有效
|
||||||
|
// 只微信小程序、QQ小程序有效
|
||||||
|
appParameter: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 指定是否阻止本节点的祖先节点出现点击态,微信小程序有效
|
||||||
|
hoverStopPropagation: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 指定返回用户信息的语言,zh_CN 简体中文,zh_TW 繁体中文,en 英文。只微信小程序有效
|
||||||
|
lang: {
|
||||||
|
type: String,
|
||||||
|
default: 'en'
|
||||||
|
},
|
||||||
|
// 会话来源,open-type="contact"时有效。只微信小程序有效
|
||||||
|
sessionFrom: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 会话内消息卡片标题,open-type="contact"时有效
|
||||||
|
// 默认当前标题,只微信小程序有效
|
||||||
|
sendMessageTitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 会话内消息卡片点击跳转小程序路径,open-type="contact"时有效
|
||||||
|
// 默认当前分享路径,只微信小程序有效
|
||||||
|
sendMessagePath: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 会话内消息卡片图片,open-type="contact"时有效
|
||||||
|
// 默认当前页面截图,只微信小程序有效
|
||||||
|
sendMessageImg: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示会话内消息卡片,设置此参数为 true,用户进入客服会话会在右下角显示"可能要发送的小程序"提示,
|
||||||
|
// 用户点击后可以快速发送小程序消息,open-type="contact"时有效
|
||||||
|
showMessageCard: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 手指按(触摸)按钮时按钮时的背景颜色
|
||||||
|
hoverBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 水波纹的背景颜色
|
||||||
|
rippleBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否开启水波纹效果
|
||||||
|
ripple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 按下的类名
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义样式,对象形式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 额外传参参数,用于小程序的data-xxx属性,通过target.dataset.name获取
|
||||||
|
dataName: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 节流,一定时间内只能触发一次
|
||||||
|
throttleTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 1000
|
||||||
|
},
|
||||||
|
// 按住后多久出现点击态,单位毫秒
|
||||||
|
hoverStartTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
// 手指松开后点击态保留时间,单位毫秒
|
||||||
|
hoverStayTime: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 150
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 当没有传bgColor变量时,按钮按下去的颜色类名
|
||||||
|
getHoverClass() {
|
||||||
|
// 如果开启水波纹效果,则不启用hover-class效果
|
||||||
|
if (this.loading || this.disabled || this.ripple || this.hoverClass) return '';
|
||||||
|
let hoverClass = '';
|
||||||
|
hoverClass = this.plain ? 'u-' + this.type + '-plain-hover' : 'u-' + this.type + '-hover';
|
||||||
|
return hoverClass;
|
||||||
|
},
|
||||||
|
// 在'primary', 'success', 'error', 'warning'类型下,不显示边框,否则会造成四角有毛刺现象
|
||||||
|
showHairLineBorder() {
|
||||||
|
if (['primary', 'success', 'error', 'warning'].indexOf(this.type) >= 0 && !this.plain) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return 'u-hairline-border';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rippleTop: 0, // 水波纹的起点Y坐标到按钮上边界的距离
|
||||||
|
rippleLeft: 0, // 水波纹起点X坐标到按钮左边界的距离
|
||||||
|
fields: {}, // 波纹按钮节点信息
|
||||||
|
waveActive: false // 激活水波纹
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 按钮点击
|
||||||
|
click(e) {
|
||||||
|
// 进行节流控制,每this.throttle毫秒内,只在开始处执行
|
||||||
|
this.$u.throttle(() => {
|
||||||
|
// 如果按钮时disabled和loading状态,不触发水波纹效果
|
||||||
|
if (this.loading === true || this.disabled === true) return;
|
||||||
|
// 是否开启水波纹效果
|
||||||
|
if (this.ripple) {
|
||||||
|
// 每次点击时,移除上一次的类,再次添加,才能触发动画效果
|
||||||
|
this.waveActive = false;
|
||||||
|
this.$nextTick(function() {
|
||||||
|
this.getWaveQuery(e);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.$emit('click', e);
|
||||||
|
}, this.throttleTime);
|
||||||
|
},
|
||||||
|
// 查询按钮的节点信息
|
||||||
|
getWaveQuery(e) {
|
||||||
|
this.getElQuery().then(res => {
|
||||||
|
// 查询返回的是一个数组节点
|
||||||
|
let data = res[0];
|
||||||
|
// 查询不到节点信息,不操作
|
||||||
|
if (!data.width || !data.width) return;
|
||||||
|
// 水波纹的最终形态是一个正方形(通过border-radius让其变为一个圆形),这里要保证正方形的边长等于按钮的最长边
|
||||||
|
// 最终的方形(变换后的圆形)才能覆盖整个按钮
|
||||||
|
data.targetWidth = data.height > data.width ? data.height : data.width;
|
||||||
|
if (!data.targetWidth) return;
|
||||||
|
this.fields = data;
|
||||||
|
let touchesX = '',
|
||||||
|
touchesY = '';
|
||||||
|
// #ifdef MP-BAIDU
|
||||||
|
touchesX = e.changedTouches[0].clientX;
|
||||||
|
touchesY = e.changedTouches[0].clientY;
|
||||||
|
// #endif
|
||||||
|
// #ifdef MP-ALIPAY
|
||||||
|
touchesX = e.detail.clientX;
|
||||||
|
touchesY = e.detail.clientY;
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-BAIDU || MP-ALIPAY
|
||||||
|
touchesX = e.touches[0].clientX;
|
||||||
|
touchesY = e.touches[0].clientY;
|
||||||
|
// #endif
|
||||||
|
// 获取触摸点相对于按钮上边和左边的x和y坐标,原理是通过屏幕的触摸点(touchesY),减去按钮的上边界data.top
|
||||||
|
// 但是由于`transform-origin`默认是center,所以这里再减去半径才是水波纹view应该的位置
|
||||||
|
// 总的来说,就是把水波纹的矩形(变换后的圆形)的中心点,移动到我们的触摸点位置
|
||||||
|
this.rippleTop = touchesY - data.top - data.targetWidth / 2;
|
||||||
|
this.rippleLeft = touchesX - data.left - data.targetWidth / 2;
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.waveActive = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 获取节点信息
|
||||||
|
getElQuery() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let queryInfo = '';
|
||||||
|
// 获取元素节点信息,请查看uniapp相关文档
|
||||||
|
// https://uniapp.dcloud.io/api/ui/nodes-info?id=nodesrefboundingclientrect
|
||||||
|
queryInfo = uni.createSelectorQuery().in(this);
|
||||||
|
//#ifdef MP-ALIPAY
|
||||||
|
queryInfo = uni.createSelectorQuery();
|
||||||
|
//#endif
|
||||||
|
queryInfo.select('.u-btn').boundingClientRect();
|
||||||
|
queryInfo.exec(data => {
|
||||||
|
resolve(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 下面为对接uniapp官方按钮开放能力事件回调的对接
|
||||||
|
getphonenumber(res) {
|
||||||
|
this.$emit('getphonenumber', res);
|
||||||
|
},
|
||||||
|
getuserinfo(res) {
|
||||||
|
this.$emit('getuserinfo', res);
|
||||||
|
},
|
||||||
|
error(res) {
|
||||||
|
this.$emit('error', res);
|
||||||
|
},
|
||||||
|
opensetting(res) {
|
||||||
|
this.$emit('opensetting', res);
|
||||||
|
},
|
||||||
|
launchapp(res) {
|
||||||
|
this.$emit('launchapp', res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../../libs/css/style.components.scss';
|
||||||
|
.u-btn::after {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-btn {
|
||||||
|
position: relative;
|
||||||
|
border: 0;
|
||||||
|
//border-radius: 10rpx;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
// 避免边框某些场景可能被“裁剪”,不能设置为hidden
|
||||||
|
overflow: visible;
|
||||||
|
line-height: 1;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 40rpx;
|
||||||
|
z-index: 1;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.15s;
|
||||||
|
|
||||||
|
&--bold-border {
|
||||||
|
border: 1px solid #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--default {
|
||||||
|
color: $u-content-color;
|
||||||
|
border-color: #c0c4cc;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: $u-type-primary;
|
||||||
|
background-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: $u-type-success;
|
||||||
|
background-color: $u-type-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: $u-type-error;
|
||||||
|
background-color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: $u-type-warning;
|
||||||
|
background-color: $u-type-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--default--disabled {
|
||||||
|
color: #ffffff;
|
||||||
|
border-color: #e4e7ed;
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary--disabled {
|
||||||
|
color: #ffffff!important;
|
||||||
|
border-color: $u-type-primary-disabled!important;
|
||||||
|
background-color: $u-type-primary-disabled!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success--disabled {
|
||||||
|
color: #ffffff!important;
|
||||||
|
border-color: $u-type-success-disabled!important;
|
||||||
|
background-color: $u-type-success-disabled!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error--disabled {
|
||||||
|
color: #ffffff!important;
|
||||||
|
border-color: $u-type-error-disabled!important;
|
||||||
|
background-color: $u-type-error-disabled!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning--disabled {
|
||||||
|
color: #ffffff!important;
|
||||||
|
border-color: $u-type-warning-disabled!important;
|
||||||
|
background-color: $u-type-warning-disabled!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--primary--plain {
|
||||||
|
color: $u-type-primary!important;
|
||||||
|
border-color: $u-type-primary-disabled!important;
|
||||||
|
background-color: $u-type-primary-light!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success--plain {
|
||||||
|
color: $u-type-success!important;
|
||||||
|
border-color: $u-type-success-disabled!important;
|
||||||
|
background-color: $u-type-success-light!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error--plain {
|
||||||
|
color: $u-type-error!important;
|
||||||
|
border-color: $u-type-error-disabled!important;
|
||||||
|
background-color: $u-type-error-light!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning--plain {
|
||||||
|
color: $u-type-warning!important;
|
||||||
|
border-color: $u-type-warning-disabled!important;
|
||||||
|
background-color: $u-type-warning-light!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-hairline-border:after {
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
// 设置为border-box,意味着下面的scale缩小为0.5,实际上缩小的是伪元素的内容(border-box意味着内容不含border)
|
||||||
|
box-sizing: border-box;
|
||||||
|
// 中心点作为变形(scale())的原点
|
||||||
|
-webkit-transform-origin: 0 0;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
width: 199.8%;
|
||||||
|
height: 199.7%;
|
||||||
|
-webkit-transform: scale(0.5, 0.5);
|
||||||
|
transform: scale(0.5, 0.5);
|
||||||
|
border: 1px solid currentColor;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-wave-ripple {
|
||||||
|
z-index: 0;
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 100%;
|
||||||
|
background-clip: padding-box;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
transform: scale(0);
|
||||||
|
opacity: 1;
|
||||||
|
transform-origin: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-wave-ripple.u-wave-active {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(2);
|
||||||
|
transition: opacity 1s linear, transform 0.4s linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-round-circle {
|
||||||
|
border-radius: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-round-circle::after {
|
||||||
|
border-radius: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-loading::after {
|
||||||
|
background-color: hsla(0, 0%, 100%, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-size-default {
|
||||||
|
font-size: 30rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
line-height: 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-size-medium {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
width: auto;
|
||||||
|
font-size: 26rpx;
|
||||||
|
height: 70rpx;
|
||||||
|
line-height: 70rpx;
|
||||||
|
padding: 0 80rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-size-mini {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
width: auto;
|
||||||
|
font-size: 22rpx;
|
||||||
|
padding-top: 1px;
|
||||||
|
height: 50rpx;
|
||||||
|
line-height: 50rpx;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-primary-plain-hover {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: $u-type-primary-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-default-plain-hover {
|
||||||
|
color: $u-type-primary-dark !important;
|
||||||
|
background: $u-type-primary-light !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-success-plain-hover {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: $u-type-success-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-warning-plain-hover {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: $u-type-warning-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-error-plain-hover {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: $u-type-error-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-info-plain-hover {
|
||||||
|
color: #ffffff !important;
|
||||||
|
background: $u-type-info-dark !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-default-hover {
|
||||||
|
color: $u-type-primary-dark !important;
|
||||||
|
border-color: $u-type-primary-dark !important;
|
||||||
|
background-color: $u-type-primary-light !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-primary-hover {
|
||||||
|
background: $u-type-primary-dark !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-success-hover {
|
||||||
|
background: $u-type-success-dark !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-info-hover {
|
||||||
|
background: $u-type-info-dark !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-warning-hover {
|
||||||
|
background: $u-type-warning-dark !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-error-hover {
|
||||||
|
background: $u-type-error-dark !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
639
node_modules/uview-ui/components/u-calendar/u-calendar.vue
generated
vendored
Normal file
639
node_modules/uview-ui/components/u-calendar/u-calendar.vue
generated
vendored
Normal file
@@ -0,0 +1,639 @@
|
|||||||
|
<template>
|
||||||
|
<u-popup closeable :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
|
||||||
|
:safeAreaInsetBottom="safeAreaInsetBottom" @close="close" :z-index="uZIndex" :border-radius="borderRadius" :closeable="closeable">
|
||||||
|
<view class="u-calendar">
|
||||||
|
<view class="u-calendar__header">
|
||||||
|
<view class="u-calendar__header__text" v-if="!$slots['tooltip']">
|
||||||
|
{{toolTip}}
|
||||||
|
</view>
|
||||||
|
<slot v-else name="tooltip" />
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__action u-flex u-row-center">
|
||||||
|
<view class="u-calendar__action__icon">
|
||||||
|
<u-icon v-if="changeYear" name="arrow-left-double" :color="yearArrowColor" @click="changeYearHandler(0)"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__action__icon">
|
||||||
|
<u-icon v-if="changeMonth" name="arrow-left" :color="monthArrowColor" @click="changeMonthHandler(0)"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__action__text">{{ showTitle }}</view>
|
||||||
|
<view class="u-calendar__action__icon">
|
||||||
|
<u-icon v-if="changeMonth" name="arrow-right" :color="monthArrowColor" @click="changeMonthHandler(1)"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__action__icon">
|
||||||
|
<u-icon v-if="changeYear" name="arrow-right-double" :color="yearArrowColor" @click="changeYearHandler(1)"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__week-day">
|
||||||
|
<view class="u-calendar__week-day__text" v-for="(item, index) in weekDayZh" :key="index">{{item}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__content">
|
||||||
|
<!-- 前置空白部分 -->
|
||||||
|
<block v-for="(item, index) in weekdayArr" :key="index">
|
||||||
|
<view class="u-calendar__content__item"></view>
|
||||||
|
</block>
|
||||||
|
<view class="u-calendar__content__item" :class="{
|
||||||
|
'u-hover-class':openDisAbled(year,month,index+1),
|
||||||
|
'u-calendar__content--start-date': (mode == 'range' && startDate==`${year}-${month}-${index+1}`) || mode== 'date',
|
||||||
|
'u-calendar__content--end-date':(mode== 'range' && endDate==`${year}-${month}-${index+1}`) || mode == 'date'
|
||||||
|
}" :style="{backgroundColor: getColor(index,1)}" v-for="(item, index) in daysArr" :key="index"
|
||||||
|
@tap="dateClick(index)">
|
||||||
|
<view class="u-calendar__content__item__inner" :style="{color: getColor(index,2)}">
|
||||||
|
<view>{{ index + 1 }}</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && startDate==`${year}-${month}-${index+1}` && startDate!=endDate">{{startText}}</view>
|
||||||
|
<view class="u-calendar__content__item__tips" :style="{color:activeColor}" v-if="mode== 'range' && endDate==`${year}-${month}-${index+1}`">{{endText}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__content__bg-month">{{month}}</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__bottom">
|
||||||
|
<view class="u-calendar__bottom__choose">
|
||||||
|
<text>{{mode == 'date' ? activeDate : startDate}}</text>
|
||||||
|
<text v-if="endDate">至{{endDate}}</text>
|
||||||
|
</view>
|
||||||
|
<view class="u-calendar__bottom__btn">
|
||||||
|
<u-button :type="btnType" shape="circle" size="default" @click="btnFix(false)">确定</u-button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* calendar 日历
|
||||||
|
* @description 此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中。
|
||||||
|
* @tutorial http://uviewui.com/components/calendar.html
|
||||||
|
* @property {String} mode 选择日期的模式,date-为单个日期,range-为选择日期范围
|
||||||
|
* @property {Boolean} v-model 布尔值变量,用于控制日历的弹出与收起
|
||||||
|
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
|
||||||
|
* @property {Boolean} change-year 是否显示顶部的切换年份方向的按钮(默认true)
|
||||||
|
* @property {Boolean} change-month 是否显示顶部的切换月份方向的按钮(默认true)
|
||||||
|
* @property {String Number} max-year 可切换的最大年份(默认2050)
|
||||||
|
* @property {String Number} min-year 可切换的最小年份(默认1950)
|
||||||
|
* @property {String Number} min-date 最小可选日期(默认1950-01-01)
|
||||||
|
* @property {String Number} max-date 最大可选日期(默认当前日期)
|
||||||
|
* @property {String Number} 弹窗顶部左右两边的圆角值,单位rpx(默认20)
|
||||||
|
* @property {Boolean} mask-close-able 是否允许通过点击遮罩关闭日历(默认true)
|
||||||
|
* @property {String} month-arrow-color 月份切换按钮箭头颜色(默认#606266)
|
||||||
|
* @property {String} year-arrow-color 年份切换按钮箭头颜色(默认#909399)
|
||||||
|
* @property {String} color 日期字体的默认颜色(默认#303133)
|
||||||
|
* @property {String} active-bg-color 起始/结束日期按钮的背景色(默认#2979ff)
|
||||||
|
* @property {String Number} z-index 弹出时的z-index值(默认10075)
|
||||||
|
* @property {String} active-color 起始/结束日期按钮的字体颜色(默认#ffffff)
|
||||||
|
* @property {String} range-bg-color 起始/结束日期之间的区域的背景颜色(默认rgba(41,121,255,0.13))
|
||||||
|
* @property {String} range-color 选择范围内字体颜色(默认#2979ff)
|
||||||
|
* @property {String} start-text 起始日期底部的提示文字(默认 '开始')
|
||||||
|
* @property {String} end-text 结束日期底部的提示文字(默认 '结束')
|
||||||
|
* @property {String} btn-type 底部确定按钮的主题(默认 'primary')
|
||||||
|
* @property {String} toolTip 顶部提示文字,如设置名为tooltip的slot,此参数将失效(默认 '选择日期')
|
||||||
|
* @property {Boolean} closeable 是否显示右上角的关闭图标(默认true)
|
||||||
|
* @example <u-calendar v-model="show" :mode="mode"></u-calendar>
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'u-calendar',
|
||||||
|
props: {
|
||||||
|
safeAreaInsetBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否允许通过点击遮罩关闭Picker
|
||||||
|
maskCloseAble: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 通过双向绑定控制组件的弹出与收起
|
||||||
|
value: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 弹出的z-index值
|
||||||
|
zIndex: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否允许切换年份
|
||||||
|
changeYear: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否允许切换月份
|
||||||
|
changeMonth: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// date-单个日期选择,range-开始日期+结束日期选择
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'date'
|
||||||
|
},
|
||||||
|
// 可切换的最大年份
|
||||||
|
maxYear: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 2050
|
||||||
|
},
|
||||||
|
// 可切换的最小年份
|
||||||
|
minYear: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 1950
|
||||||
|
},
|
||||||
|
// 最小可选日期(不在范围内日期禁用不可选)
|
||||||
|
minDate: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '1950-01-01'
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 最大可选日期
|
||||||
|
* 默认最大值为今天,之后的日期不可选
|
||||||
|
* 2030-12-31
|
||||||
|
* */
|
||||||
|
maxDate: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 弹窗顶部左右两边的圆角值
|
||||||
|
borderRadius: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
// 月份切换按钮箭头颜色
|
||||||
|
monthArrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#606266'
|
||||||
|
},
|
||||||
|
// 年份切换按钮箭头颜色
|
||||||
|
yearArrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#909399'
|
||||||
|
},
|
||||||
|
// 默认日期字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 选中|起始结束日期背景色
|
||||||
|
activeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
},
|
||||||
|
// 选中|起始结束日期字体颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
},
|
||||||
|
// 范围内日期背景色
|
||||||
|
rangeBgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'rgba(41,121,255,0.13)'
|
||||||
|
},
|
||||||
|
// 范围内日期字体颜色
|
||||||
|
rangeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
},
|
||||||
|
// mode=range时生效,起始日期自定义文案
|
||||||
|
startText: {
|
||||||
|
type: String,
|
||||||
|
default: '开始'
|
||||||
|
},
|
||||||
|
// mode=range时生效,结束日期自定义文案
|
||||||
|
endText: {
|
||||||
|
type: String,
|
||||||
|
default: '结束'
|
||||||
|
},
|
||||||
|
//按钮样式类型
|
||||||
|
btnType: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
// 当前选中日期带选中效果
|
||||||
|
isActiveCurrent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 切换年月是否触发事件 mode=date时生效
|
||||||
|
isChange: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示右上角的关闭图标
|
||||||
|
closeable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 顶部的提示文字
|
||||||
|
toolTip: {
|
||||||
|
type: String,
|
||||||
|
default: '选择日期'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 星期几,值为1-7
|
||||||
|
weekday: 1,
|
||||||
|
weekdayArr:[],
|
||||||
|
// 当前月有多少天
|
||||||
|
days: 0,
|
||||||
|
daysArr:[],
|
||||||
|
showTitle: '',
|
||||||
|
year: 2020,
|
||||||
|
month: 0,
|
||||||
|
day: 0,
|
||||||
|
startYear: 0,
|
||||||
|
startMonth: 0,
|
||||||
|
startDay: 0,
|
||||||
|
endYear: 0,
|
||||||
|
endMonth: 0,
|
||||||
|
endDay: 0,
|
||||||
|
today: '',
|
||||||
|
activeDate: '',
|
||||||
|
startDate: '',
|
||||||
|
endDate: '',
|
||||||
|
isStart: true,
|
||||||
|
min: null,
|
||||||
|
max: null,
|
||||||
|
weekDayZh: ['日', '一', '二', '三', '四', '五', '六']
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
dataChange() {
|
||||||
|
return `${this.mode}-${this.minDate}-${this.maxDate}`;
|
||||||
|
},
|
||||||
|
uZIndex() {
|
||||||
|
// 如果用户有传递z-index值,优先使用
|
||||||
|
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
dataChange(val) {
|
||||||
|
this.init()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.init()
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getColor(index, type) {
|
||||||
|
let color = type == 1 ? '' : this.color;
|
||||||
|
let day = index + 1
|
||||||
|
let date = `${this.year}-${this.month}-${day}`
|
||||||
|
let timestamp = new Date(date.replace(/\-/g, '/')).getTime();
|
||||||
|
let start = this.startDate.replace(/\-/g, '/')
|
||||||
|
let end = this.endDate.replace(/\-/g, '/')
|
||||||
|
if ((this.isActiveCurrent && this.activeDate == date) || this.startDate == date || this.endDate == date) {
|
||||||
|
color = type == 1 ? this.activeBgColor : this.activeColor;
|
||||||
|
} else if (this.endDate && timestamp > new Date(start).getTime() && timestamp < new Date(end).getTime()) {
|
||||||
|
color = type == 1 ? this.rangeBgColor : this.rangeColor;
|
||||||
|
}
|
||||||
|
return color;
|
||||||
|
},
|
||||||
|
init() {
|
||||||
|
let now = new Date();
|
||||||
|
this.year = now.getFullYear();
|
||||||
|
this.month = now.getMonth() + 1;
|
||||||
|
this.day = now.getDate();
|
||||||
|
this.today = `${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}`;
|
||||||
|
this.activeDate = this.today;
|
||||||
|
this.min = this.initDate(this.minDate);
|
||||||
|
this.max = this.initDate(this.maxDate || this.today);
|
||||||
|
this.startDate = "";
|
||||||
|
this.startYear = 0;
|
||||||
|
this.startMonth = 0;
|
||||||
|
this.startDay = 0;
|
||||||
|
this.endYear = 0;
|
||||||
|
this.endMonth = 0;
|
||||||
|
this.endDay = 0;
|
||||||
|
this.endDate = "";
|
||||||
|
this.isStart = true;
|
||||||
|
this.changeData();
|
||||||
|
},
|
||||||
|
//日期处理
|
||||||
|
initDate(date) {
|
||||||
|
let fdate = date.split('-');
|
||||||
|
return {
|
||||||
|
year: Number(fdate[0] || 1920),
|
||||||
|
month: Number(fdate[1] || 1),
|
||||||
|
day: Number(fdate[2] || 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
openDisAbled: function(year, month, day) {
|
||||||
|
let bool = true;
|
||||||
|
let date = `${year}/${month}/${day}`;
|
||||||
|
// let today = this.today.replace(/\-/g, '/');
|
||||||
|
let min = `${this.min.year}/${this.min.month}/${this.min.day}`;
|
||||||
|
let max = `${this.max.year}/${this.max.month}/${this.max.day}`;
|
||||||
|
let timestamp = new Date(date).getTime();
|
||||||
|
if (timestamp >= new Date(min).getTime() && timestamp <= new Date(max).getTime()) {
|
||||||
|
bool = false;
|
||||||
|
}
|
||||||
|
return bool;
|
||||||
|
},
|
||||||
|
generateArray: function(start, end) {
|
||||||
|
return Array.from(new Array(end + 1).keys()).slice(start);
|
||||||
|
},
|
||||||
|
formatNum: function(num) {
|
||||||
|
return num < 10 ? '0' + num : num + '';
|
||||||
|
},
|
||||||
|
//一个月有多少天
|
||||||
|
getMonthDay(year, month) {
|
||||||
|
let days = new Date(year, month, 0).getDate();
|
||||||
|
return days;
|
||||||
|
},
|
||||||
|
getWeekday(year, month) {
|
||||||
|
let date = new Date(`${year}/${month}/01 00:00:00`);
|
||||||
|
return date.getDay();
|
||||||
|
},
|
||||||
|
checkRange(year) {
|
||||||
|
let overstep = false;
|
||||||
|
if (year < this.minYear || year > this.maxYear) {
|
||||||
|
uni.showToast({
|
||||||
|
title: "日期超出范围啦~",
|
||||||
|
icon: 'none'
|
||||||
|
})
|
||||||
|
overstep = true;
|
||||||
|
}
|
||||||
|
return overstep;
|
||||||
|
},
|
||||||
|
changeMonthHandler(isAdd) {
|
||||||
|
if (isAdd) {
|
||||||
|
let month = this.month + 1;
|
||||||
|
let year = month > 12 ? this.year + 1 : this.year;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.month = month > 12 ? 1 : month;
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
let month = this.month - 1;
|
||||||
|
let year = month < 1 ? this.year - 1 : this.year;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.month = month < 1 ? 12 : month;
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeYearHandler(isAdd) {
|
||||||
|
let year = isAdd ? this.year + 1 : this.year - 1;
|
||||||
|
if (!this.checkRange(year)) {
|
||||||
|
this.year = year;
|
||||||
|
this.changeData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
changeData() {
|
||||||
|
this.days = this.getMonthDay(this.year, this.month);
|
||||||
|
this.daysArr=this.generateArray(1,this.days)
|
||||||
|
this.weekday = this.getWeekday(this.year, this.month);
|
||||||
|
this.weekdayArr=this.generateArray(1,this.weekday)
|
||||||
|
this.showTitle = `${this.year}年${this.month}月`;
|
||||||
|
if (this.isChange && this.mode == 'date') {
|
||||||
|
this.btnFix(true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dateClick: function(day) {
|
||||||
|
day += 1;
|
||||||
|
if (!this.openDisAbled(this.year, this.month, day)) {
|
||||||
|
this.day = day;
|
||||||
|
let date = `${this.year}-${this.month}-${day}`;
|
||||||
|
if (this.mode == 'date') {
|
||||||
|
this.activeDate = date;
|
||||||
|
} else {
|
||||||
|
let compare = new Date(date.replace(/\-/g, '/')).getTime() < new Date(this.startDate.replace(/\-/g, '/')).getTime()
|
||||||
|
if (this.isStart || compare) {
|
||||||
|
this.startDate = date;
|
||||||
|
this.startYear = this.year;
|
||||||
|
this.startMonth = this.month;
|
||||||
|
this.startDay = this.day;
|
||||||
|
this.endYear = 0;
|
||||||
|
this.endMonth = 0;
|
||||||
|
this.endDay = 0;
|
||||||
|
this.endDate = "";
|
||||||
|
this.activeDate = "";
|
||||||
|
this.isStart = false;
|
||||||
|
} else {
|
||||||
|
this.endDate = date;
|
||||||
|
this.endYear = this.year;
|
||||||
|
this.endMonth = this.month;
|
||||||
|
this.endDay = this.day;
|
||||||
|
this.isStart = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
close() {
|
||||||
|
// 修改通过v-model绑定的父组件变量的值为false,从而隐藏日历弹窗
|
||||||
|
this.$emit('input', false);
|
||||||
|
},
|
||||||
|
getWeekText(date) {
|
||||||
|
date = new Date(`${date.replace(/\-/g, '/')} 00:00:00`);
|
||||||
|
let week = date.getDay();
|
||||||
|
return '星期' + ['日', '一', '二', '三', '四', '五', '六'][week];
|
||||||
|
},
|
||||||
|
btnFix(show) {
|
||||||
|
if (!show) {
|
||||||
|
this.close();
|
||||||
|
}
|
||||||
|
if (this.mode == 'date') {
|
||||||
|
let arr = this.activeDate.split('-')
|
||||||
|
let year = this.isChange ? this.year : Number(arr[0]);
|
||||||
|
let month = this.isChange ? this.month : Number(arr[1]);
|
||||||
|
let day = this.isChange ? this.day : Number(arr[2]);
|
||||||
|
//当前月有多少天
|
||||||
|
let days = this.getMonthDay(year, month);
|
||||||
|
let result = `${year}-${this.formatNum(month)}-${this.formatNum(day)}`;
|
||||||
|
let weekText = this.getWeekText(result);
|
||||||
|
let isToday = false;
|
||||||
|
if (`${year}-${month}-${day}` == this.today) {
|
||||||
|
//今天
|
||||||
|
isToday = true;
|
||||||
|
}
|
||||||
|
this.$emit('change', {
|
||||||
|
year: year,
|
||||||
|
month: month,
|
||||||
|
day: day,
|
||||||
|
days: days,
|
||||||
|
result: result,
|
||||||
|
week: weekText,
|
||||||
|
isToday: isToday,
|
||||||
|
// switch: show //是否是切换年月操作
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
if (!this.startDate || !this.endDate) return;
|
||||||
|
let startMonth = this.formatNum(this.startMonth);
|
||||||
|
let startDay = this.formatNum(this.startDay);
|
||||||
|
let startDate = `${this.startYear}-${startMonth}-${startDay}`;
|
||||||
|
let startWeek = this.getWeekText(startDate)
|
||||||
|
|
||||||
|
let endMonth = this.formatNum(this.endMonth);
|
||||||
|
let endDay = this.formatNum(this.endDay);
|
||||||
|
let endDate = `${this.endYear}-${endMonth}-${endDay}`;
|
||||||
|
let endWeek = this.getWeekText(endDate);
|
||||||
|
this.$emit('change', {
|
||||||
|
startYear: this.startYear,
|
||||||
|
startMonth: this.startMonth,
|
||||||
|
startDay: this.startDay,
|
||||||
|
startDate: startDate,
|
||||||
|
startWeek: startWeek,
|
||||||
|
endYear: this.endYear,
|
||||||
|
endMonth: this.endMonth,
|
||||||
|
endDay: this.endDay,
|
||||||
|
endDate: endDate,
|
||||||
|
endWeek: endWeek
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-calendar {
|
||||||
|
color: $u-content-color;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 30rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
color: $u-main-color;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
margin-top: 30rpx;
|
||||||
|
padding: 0 60rpx;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__action {
|
||||||
|
padding: 40rpx 0 40rpx 0;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
margin: 0 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
padding: 0 16rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 32rpx;
|
||||||
|
line-height: 32rpx;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__week-day {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
width: 100%;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 6px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
background-color: #fff;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--end-date {
|
||||||
|
border-top-right-radius: 8rpx;
|
||||||
|
border-bottom-right-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--start-date {
|
||||||
|
border-top-left-radius: 8rpx;
|
||||||
|
border-bottom-left-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
width: 14.2857%;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 6px 0;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
z-index: 2;
|
||||||
|
|
||||||
|
&__inner {
|
||||||
|
height: 84rpx;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
font-size: 32rpx;
|
||||||
|
position: relative;
|
||||||
|
border-radius: 50%;
|
||||||
|
|
||||||
|
&__desc {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
transform: scale(0.75);
|
||||||
|
transform-origin: center center;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
text-align: center;
|
||||||
|
bottom: 2rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__tips {
|
||||||
|
width: 100%;
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
transform: scale(0.8);
|
||||||
|
transform-origin: center center;
|
||||||
|
text-align: center;
|
||||||
|
bottom: 8rpx;
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bg-month {
|
||||||
|
position: absolute;
|
||||||
|
font-size: 130px;
|
||||||
|
line-height: 130px;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
color: #e4e7ed;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__bottom {
|
||||||
|
width: 100%;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 0 40rpx 30rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
|
||||||
|
&__choose {
|
||||||
|
height: 50rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
257
node_modules/uview-ui/components/u-car-keyboard/u-car-keyboard.vue
generated
vendored
Normal file
257
node_modules/uview-ui/components/u-car-keyboard/u-car-keyboard.vue
generated
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-keyboard" @touchmove.stop.prevent="() => {}">
|
||||||
|
<view class="u-keyboard-grids">
|
||||||
|
<block>
|
||||||
|
<view class="u-keyboard-grids-item" v-for="(group, i) in abc ? EngKeyBoardList : areaList" :key="i">
|
||||||
|
<view :hover-stay-time="100" @tap="carInputClick(i, j)" hover-class="u-carinput-hover" class="u-keyboard-grids-btn"
|
||||||
|
v-for="(item, j) in group" :key="j">
|
||||||
|
{{ item }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view @touchstart="backspaceClick" @touchend="clearTimer" :hover-stay-time="100" class="u-keyboard-back"
|
||||||
|
hover-class="u-hover-class">
|
||||||
|
<u-icon :size="38" name="backspace" :bold="true"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view :hover-stay-time="100" class="u-keyboard-change" hover-class="u-carinput-hover" @tap="changeCarInputMode">
|
||||||
|
<text class="zh" :class="[!abc ? 'active' : 'inactive']">中</text>
|
||||||
|
/
|
||||||
|
<text class="en" :class="[abc ? 'active' : 'inactive']">英</text>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: "u-keyboard",
|
||||||
|
props: {
|
||||||
|
// 是否打乱键盘按键的顺序
|
||||||
|
random: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 车牌输入时,abc=true为输入车牌号码,bac=false为输入省份中文简称
|
||||||
|
abc: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
areaList() {
|
||||||
|
let data = [
|
||||||
|
'京',
|
||||||
|
'沪',
|
||||||
|
'粤',
|
||||||
|
'津',
|
||||||
|
'冀',
|
||||||
|
'豫',
|
||||||
|
'云',
|
||||||
|
'辽',
|
||||||
|
'黑',
|
||||||
|
'湘',
|
||||||
|
'皖',
|
||||||
|
'鲁',
|
||||||
|
'苏',
|
||||||
|
'浙',
|
||||||
|
'赣',
|
||||||
|
'鄂',
|
||||||
|
'桂',
|
||||||
|
'甘',
|
||||||
|
'晋',
|
||||||
|
'陕',
|
||||||
|
'蒙',
|
||||||
|
'吉',
|
||||||
|
'闽',
|
||||||
|
'贵',
|
||||||
|
'渝',
|
||||||
|
'川',
|
||||||
|
'青',
|
||||||
|
'琼',
|
||||||
|
'宁',
|
||||||
|
'挂',
|
||||||
|
'藏',
|
||||||
|
'港',
|
||||||
|
'澳',
|
||||||
|
'新',
|
||||||
|
'使',
|
||||||
|
'学'
|
||||||
|
];
|
||||||
|
let tmp = [];
|
||||||
|
// 打乱顺序
|
||||||
|
if (this.random) data = this.$u.randomArray(data);
|
||||||
|
// 切割成二维数组
|
||||||
|
tmp[0] = data.slice(0, 10);
|
||||||
|
tmp[1] = data.slice(10, 20);
|
||||||
|
tmp[2] = data.slice(20, 30);
|
||||||
|
tmp[3] = data.slice(30, 36);
|
||||||
|
return tmp;
|
||||||
|
},
|
||||||
|
EngKeyBoardList() {
|
||||||
|
let data = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
0,
|
||||||
|
'Q',
|
||||||
|
'W',
|
||||||
|
'E',
|
||||||
|
'R',
|
||||||
|
'T',
|
||||||
|
'Y',
|
||||||
|
'U',
|
||||||
|
'I',
|
||||||
|
'O',
|
||||||
|
'P',
|
||||||
|
'A',
|
||||||
|
'S',
|
||||||
|
'D',
|
||||||
|
'F',
|
||||||
|
'G',
|
||||||
|
'H',
|
||||||
|
'J',
|
||||||
|
'K',
|
||||||
|
'L',
|
||||||
|
'Z',
|
||||||
|
'X',
|
||||||
|
'C',
|
||||||
|
'V',
|
||||||
|
'B',
|
||||||
|
'N',
|
||||||
|
'M'
|
||||||
|
];
|
||||||
|
let tmp = [];
|
||||||
|
if (this.random) data = this.$u.randomArray(data);
|
||||||
|
tmp[0] = data.slice(0, 10);
|
||||||
|
tmp[1] = data.slice(10, 20);
|
||||||
|
tmp[2] = data.slice(20, 30);
|
||||||
|
tmp[3] = data.slice(30, 36);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击键盘按钮
|
||||||
|
carInputClick(i, j) {
|
||||||
|
let value = '';
|
||||||
|
// 不同模式,获取不同数组的值
|
||||||
|
if (this.abc) value = this.EngKeyBoardList[i][j];
|
||||||
|
else value = this.areaList[i][j];
|
||||||
|
this.$emit('change', value);
|
||||||
|
},
|
||||||
|
// 修改汽车牌键盘的输入模式,中文|英文
|
||||||
|
changeCarInputMode() {
|
||||||
|
this.abc = !this.abc;
|
||||||
|
},
|
||||||
|
// 点击退格键
|
||||||
|
backspaceClick() {
|
||||||
|
this.$emit('backspace');
|
||||||
|
clearInterval(this.timer); //再次清空定时器,防止重复注册定时器
|
||||||
|
this.timer = null;
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.$emit('backspace');
|
||||||
|
}, 250);
|
||||||
|
},
|
||||||
|
clearTimer() {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-keyboard-grids {
|
||||||
|
background: rgb(215, 215, 217);
|
||||||
|
padding: 24rpx 0;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-grids-item {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-grids-btn {
|
||||||
|
text-decoration: none;
|
||||||
|
width: 62rpx;
|
||||||
|
flex: 0 0 64rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
font-size: 36rpx;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 80rpx;
|
||||||
|
background-color: #fff;
|
||||||
|
margin: 8rpx 5rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
box-shadow: 0 2rpx 0rpx #888992;
|
||||||
|
font-weight: 500;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-carinput-hover {
|
||||||
|
background-color: rgb(185, 188, 195) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-back {
|
||||||
|
position: absolute;
|
||||||
|
width: 96rpx;
|
||||||
|
right: 22rpx;
|
||||||
|
bottom: 32rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
background-color: rgb(185, 188, 195);
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
justify-content: center;
|
||||||
|
box-shadow: 0 2rpx 0rpx #888992;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change {
|
||||||
|
font-size: 24rpx;
|
||||||
|
box-shadow: 0 2rpx 0rpx #888992;
|
||||||
|
position: absolute;
|
||||||
|
width: 96rpx;
|
||||||
|
left: 22rpx;
|
||||||
|
line-height: 1;
|
||||||
|
bottom: 32rpx;
|
||||||
|
height: 80rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change .inactive.zh {
|
||||||
|
transform: scale(0.85) translateY(-10rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change .inactive.en {
|
||||||
|
transform: scale(0.85) translateY(10rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change .active {
|
||||||
|
color: rgb(237, 112, 64);
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change .zh {
|
||||||
|
transform: translateY(-10rpx);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-keyboard-change .en {
|
||||||
|
transform: translateY(10rpx);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
299
node_modules/uview-ui/components/u-card/u-card.vue
generated
vendored
Normal file
299
node_modules/uview-ui/components/u-card/u-card.vue
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-card"
|
||||||
|
@tap.stop="click"
|
||||||
|
:class="{ 'u-border': border, 'u-card-full': full, 'u-card--border': borderRadius > 0 }"
|
||||||
|
:style="{
|
||||||
|
borderRadius: borderRadius + 'rpx',
|
||||||
|
margin: margin,
|
||||||
|
boxShadow: boxShadow
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<view
|
||||||
|
v-if="showHead"
|
||||||
|
class="u-card__head"
|
||||||
|
:style="[{padding: padding + 'rpx'}, headStyle]"
|
||||||
|
:class="{
|
||||||
|
'u-border-bottom': headBorderBottom
|
||||||
|
}"
|
||||||
|
@tap="headClick"
|
||||||
|
>
|
||||||
|
<view v-if="!$slots.head" class="u-flex u-row-between">
|
||||||
|
<view class="u-card__head--left u-flex u-line-1" v-if="title">
|
||||||
|
<image
|
||||||
|
:src="thumb"
|
||||||
|
class="u-card__head--left__thumb"
|
||||||
|
mode="aspectfull"
|
||||||
|
v-if="thumb"
|
||||||
|
:style="{
|
||||||
|
height: thumbWidth + 'rpx',
|
||||||
|
width: thumbWidth + 'rpx',
|
||||||
|
borderRadius: thumbCircle ? '100rpx' : '6rpx'
|
||||||
|
}"
|
||||||
|
></image>
|
||||||
|
<text
|
||||||
|
class="u-card__head--left__title u-line-1"
|
||||||
|
:style="{
|
||||||
|
fontSize: titleSize + 'rpx',
|
||||||
|
color: titleColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ title }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<view class="u-card__head--right u-line-1" v-if="subTitle">
|
||||||
|
<text
|
||||||
|
class="u-card__head__title__text"
|
||||||
|
:style="{
|
||||||
|
fontSize: subTitleSize + 'rpx',
|
||||||
|
color: subTitleColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ subTitle }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<slot name="head" v-else />
|
||||||
|
</view>
|
||||||
|
<view @tap="bodyClick" class="u-card__body" :style="[{padding: padding + 'rpx'}, bodyStyle]"><slot name="body" /></view>
|
||||||
|
<view
|
||||||
|
v-if="showFoot"
|
||||||
|
class="u-card__foot"
|
||||||
|
@tap="footClick"
|
||||||
|
:style="[{padding: $slots.foot ? padding + 'rpx' : 0}, footStyle]"
|
||||||
|
:class="{
|
||||||
|
'u-border-top': footBorderTop
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot name="foot" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* card 卡片
|
||||||
|
* @description 卡片组件一般用于多个列表条目,且风格统一的场景
|
||||||
|
* @tutorial https://www.uviewui.com/components/card.html
|
||||||
|
* @property {Boolean} full 卡片与屏幕两侧是否留空隙(默认false)
|
||||||
|
* @property {String} title 头部左边的标题
|
||||||
|
* @property {String} title-color 标题颜色(默认#303133)
|
||||||
|
* @property {String | Number} title-size 标题字体大小,单位rpx(默认30)
|
||||||
|
* @property {String} sub-title 头部右边的副标题
|
||||||
|
* @property {String} sub-title-color 副标题颜色(默认#909399)
|
||||||
|
* @property {String | Number} sub-title-size 副标题字体大小(默认26)
|
||||||
|
* @property {Boolean} border 是否显示边框(默认true)
|
||||||
|
* @property {String | Number} index 用于标识点击了第几个卡片
|
||||||
|
* @property {String} box-shadow 卡片外围阴影,字符串形式(默认none)
|
||||||
|
* @property {String} margin 卡片与屏幕两边和上下元素的间距,需带单位,如"30rpx 20rpx"(默认30rpx)
|
||||||
|
* @property {String | Number} border-radius 卡片整体的圆角值,单位rpx(默认16)
|
||||||
|
* @property {Object} head-style 头部自定义样式,对象形式
|
||||||
|
* @property {Object} body-style 中部自定义样式,对象形式
|
||||||
|
* @property {Object} foot-style 底部自定义样式,对象形式
|
||||||
|
* @property {Boolean} head-border-bottom 是否显示头部的下边框(默认true)
|
||||||
|
* @property {Boolean} foot-border-top 是否显示底部的上边框(默认true)
|
||||||
|
* @property {Boolean} show-head 是否显示头部(默认true)
|
||||||
|
* @property {Boolean} show-head 是否显示尾部(默认true)
|
||||||
|
* @property {String} thumb 缩略图路径,如设置将显示在标题的左边,不建议使用相对路径
|
||||||
|
* @property {String | Number} thumb-width 缩略图的宽度,高等于宽,单位rpx(默认60)
|
||||||
|
* @property {Boolean} thumb-circle 缩略图是否为圆形(默认false)
|
||||||
|
* @event {Function} click 整个卡片任意位置被点击时触发
|
||||||
|
* @event {Function} head-click 卡片头部被点击时触发
|
||||||
|
* @event {Function} body-click 卡片主体部分被点击时触发
|
||||||
|
* @event {Function} foot-click 卡片底部部分被点击时触发
|
||||||
|
* @example <u-card padding="30" title="card"></u-card>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-card',
|
||||||
|
props: {
|
||||||
|
// 与屏幕两侧是否留空隙
|
||||||
|
full: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题颜色
|
||||||
|
titleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 标题字体大小,单位rpx
|
||||||
|
titleSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '30'
|
||||||
|
},
|
||||||
|
// 副标题
|
||||||
|
subTitle: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 副标题颜色
|
||||||
|
subTitleColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#909399'
|
||||||
|
},
|
||||||
|
// 副标题字体大小,单位rpx
|
||||||
|
subTitleSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '26'
|
||||||
|
},
|
||||||
|
// 是否显示外部边框,只对full=false时有效(卡片与边框有空隙时)
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 用于标识点击了第几个
|
||||||
|
index: {
|
||||||
|
type: [Number, String, Object],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 用于隔开上下左右的边距,带单位的写法,如:"30rpx 30rpx","20rpx 20rpx 30rpx 30rpx"
|
||||||
|
margin: {
|
||||||
|
type: String,
|
||||||
|
default: '30rpx'
|
||||||
|
},
|
||||||
|
// card卡片的圆角
|
||||||
|
borderRadius: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '16'
|
||||||
|
},
|
||||||
|
// 头部自定义样式,对象形式
|
||||||
|
headStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 主体自定义样式,对象形式
|
||||||
|
bodyStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 底部自定义样式,对象形式
|
||||||
|
footStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 头部是否下边框
|
||||||
|
headBorderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 底部是否有上边框
|
||||||
|
footBorderTop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 标题左边的缩略图
|
||||||
|
thumb: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 缩略图宽高,单位rpx
|
||||||
|
thumbWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '60'
|
||||||
|
},
|
||||||
|
// 缩略图是否为圆形
|
||||||
|
thumbCircle: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 给head,body,foot的内边距
|
||||||
|
padding: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '30'
|
||||||
|
},
|
||||||
|
// 是否显示头部
|
||||||
|
showHead: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示尾部
|
||||||
|
showFoot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 卡片外围阴影,字符串形式
|
||||||
|
boxShadow: {
|
||||||
|
type: String,
|
||||||
|
default: 'none'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
},
|
||||||
|
headClick() {
|
||||||
|
this.$emit('head-click', this.index);
|
||||||
|
},
|
||||||
|
bodyClick() {
|
||||||
|
this.$emit('body-click', this.index);
|
||||||
|
},
|
||||||
|
footClick() {
|
||||||
|
this.$emit('foot-click', this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-card {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 28rpx;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
&-full {
|
||||||
|
// 如果是与屏幕之间不留空隙,应该设置左右边距为0
|
||||||
|
margin-left: 0 !important;
|
||||||
|
margin-right: 0 !important;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border:after {
|
||||||
|
border-radius: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
&--left {
|
||||||
|
color: $u-main-color;
|
||||||
|
|
||||||
|
&__thumb {
|
||||||
|
margin-right: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
max-width: 400rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
color: $u-tips-color;
|
||||||
|
margin-left: 6rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__body {
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__foot {
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
70
node_modules/uview-ui/components/u-cell-group/u-cell-group.vue
generated
vendored
Normal file
70
node_modules/uview-ui/components/u-cell-group/u-cell-group.vue
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-cell-box">
|
||||||
|
<view class="u-cell-title" v-if="title" :style="[titleStyle]">
|
||||||
|
{{title}}
|
||||||
|
</view>
|
||||||
|
<view class="u-cell-item-box" :class="{'u-border-bottom u-border-top': border}">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* cellGroup 单元格父组件Group
|
||||||
|
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-item
|
||||||
|
* @tutorial https://www.uviewui.com/components/cell.html
|
||||||
|
* @property {String} title 分组标题
|
||||||
|
* @property {Boolean} border 是否显示外边框(默认true)
|
||||||
|
* @property {Object} title-style 分组标题的的样式,对象形式,如{'font-size': '24rpx'} 或 {'fontSize': '24rpx'}
|
||||||
|
* @example <u-cell-group title="设置喜好">
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-cell-group",
|
||||||
|
props: {
|
||||||
|
// 分组标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示分组list上下边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 分组标题的样式,对象形式,注意驼峰属性写法
|
||||||
|
// 类似 {'font-size': '24rpx'} 和 {'fontSize': '24rpx'}
|
||||||
|
titleStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-cell-box {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-title {
|
||||||
|
padding: 30rpx 32rpx 10rpx 32rpx;
|
||||||
|
font-size: 30rpx;
|
||||||
|
text-align: left;
|
||||||
|
color: $u-tips-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-item-box {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
316
node_modules/uview-ui/components/u-cell-item/u-cell-item.vue
generated
vendored
Normal file
316
node_modules/uview-ui/components/u-cell-item/u-cell-item.vue
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
@tap="click"
|
||||||
|
class="u-cell"
|
||||||
|
:class="{ 'u-border-bottom': borderBottom, 'u-border-top': borderTop, 'u-col-center': center, 'u-cell--required': required }"
|
||||||
|
hover-stay-time="150"
|
||||||
|
:hover-class="hoverClass"
|
||||||
|
:style="{
|
||||||
|
backgroundColor: bgColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<u-icon :size="iconSize" :name="icon" v-if="icon" :custom-style="iconStyle" class="u-cell__left-icon-wrap"></u-icon>
|
||||||
|
<view class="u-flex" v-else>
|
||||||
|
<slot name="icon"></slot>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-cell_title"
|
||||||
|
:style="[
|
||||||
|
{
|
||||||
|
width: titleWidth ? titleWidth + 'rpx' : 'auto'
|
||||||
|
},
|
||||||
|
titleStyle
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<block v-if="title !== ''">{{ title }}</block>
|
||||||
|
<slot name="title" v-else></slot>
|
||||||
|
|
||||||
|
<view class="u-cell__label" v-if="label || $slots.label" :style="[labelStyle]">
|
||||||
|
<block v-if="label !== ''">{{ label }}</block>
|
||||||
|
<slot name="label" v-else></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="u-cell__value" :style="[valueStyle]">
|
||||||
|
<block class="u-cell__value" v-if="value !== ''">{{ value }}</block>
|
||||||
|
<slot v-else></slot>
|
||||||
|
</view>
|
||||||
|
<view class="u-flex u-cell_right" v-if="$slots['right-icon']">
|
||||||
|
<slot name="right-icon"></slot>
|
||||||
|
</view>
|
||||||
|
<u-icon v-if="arrow" name="arrow-right" :style="[arrowStyle]" class="u-icon-wrap u-cell__right-icon-wrap"></u-icon>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* cellItem 单元格Item
|
||||||
|
* @description cell单元格一般用于一组列表的情况,比如个人中心页,设置页等。搭配u-cell-group使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/cell.html
|
||||||
|
* @property {String} title 左侧标题
|
||||||
|
* @property {String} icon 左侧图标名,只支持uView内置图标,见Icon 图标
|
||||||
|
* @property {Object} icon-style 左边图标的样式,对象形式
|
||||||
|
* @property {String} value 右侧内容
|
||||||
|
* @property {String} label 标题下方的描述信息
|
||||||
|
* @property {Boolean} border-bottom 是否显示cell的下边框(默认true)
|
||||||
|
* @property {Boolean} border-top 是否显示cell的上边框(默认false)
|
||||||
|
* @property {Boolean} center 是否使内容垂直居中(默认false)
|
||||||
|
* @property {String} hover-class 是否开启点击反馈,none为无效果(默认true)
|
||||||
|
* // @property {Boolean} border-gap border-bottom为true时,Cell列表中间的条目的下边框是否与左边有一个间隔(默认true)
|
||||||
|
* @property {Boolean} arrow 是否显示右侧箭头(默认true)
|
||||||
|
* @property {Boolean} required 箭头方向,可选值(默认right)
|
||||||
|
* @property {Boolean} arrow-direction 是否显示左边表示必填的星号(默认false)
|
||||||
|
* @property {Object} title-style 标题样式,对象形式
|
||||||
|
* @property {Object} value-style 右侧内容样式,对象形式
|
||||||
|
* @property {Object} label-style 标题下方描述信息的样式,对象形式
|
||||||
|
* @property {String} bg-color 背景颜色(默认transparent)
|
||||||
|
* @property {String Number} index 用于在click事件回调中返回,标识当前是第几个Item
|
||||||
|
* @property {String Number} title-width 标题的宽度,单位rpx
|
||||||
|
* @example <u-cell-item icon="integral-fill" title="会员等级" value="新版本"></u-cell-item>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-cell-item',
|
||||||
|
props: {
|
||||||
|
// 左侧图标名称(只能uView内置图标),或者图标src
|
||||||
|
icon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 左侧标题
|
||||||
|
title: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右侧内容
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题下方的描述信息
|
||||||
|
label: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示下边框
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示上边框
|
||||||
|
borderTop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 多个cell中,中间的cell显示下划线时,下划线是否给一个到左边的距离
|
||||||
|
// 1.4.0版本废除此参数,默认边框由border-top和border-bottom提供,此参数会造成干扰
|
||||||
|
// borderGap: {
|
||||||
|
// type: Boolean,
|
||||||
|
// default: true
|
||||||
|
// },
|
||||||
|
// 是否开启点击反馈,即点击时cell背景为灰色,none为无效果
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: 'u-cell-hover'
|
||||||
|
},
|
||||||
|
// 是否显示右侧箭头
|
||||||
|
arrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 内容是否垂直居中
|
||||||
|
center: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示左边表示必填的星号
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 标题的宽度,单位rpx
|
||||||
|
titleWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右侧箭头方向,可选值:right|up|down,默认为right
|
||||||
|
arrowDirection: {
|
||||||
|
type: String,
|
||||||
|
default: 'right'
|
||||||
|
},
|
||||||
|
// 控制标题的样式
|
||||||
|
titleStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 右侧显示内容的样式
|
||||||
|
valueStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 描述信息的样式
|
||||||
|
labelStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent'
|
||||||
|
},
|
||||||
|
// 用于识别被点击的是第几个cell
|
||||||
|
index: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否使用lable插槽
|
||||||
|
useLabelSlot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 左边图标的大小,单位rpx,只对传入icon字段时有效
|
||||||
|
iconSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 34
|
||||||
|
},
|
||||||
|
// 左边图标的样式,对象形式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
arrowStyle() {
|
||||||
|
let style = {};
|
||||||
|
if (this.arrowDirection == 'up') style.transform = 'rotate(-90deg)';
|
||||||
|
else if (this.arrowDirection == 'down') style.transform = 'rotate(90deg)';
|
||||||
|
else style.transform = 'rotate(0deg)';
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
.u-cell {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
/* #endif */
|
||||||
|
width: 100%;
|
||||||
|
padding: 26rpx 32rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 54rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
background-color: #fff;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell_title {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__left-icon-wrap {
|
||||||
|
margin-right: 10rpx;
|
||||||
|
font-size: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__right-icon-wrap {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
color: #969799;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__left-icon-wrap,
|
||||||
|
.u-cell__right-icon-wrap {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 48rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-border:after {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
box-sizing: border-box;
|
||||||
|
content: ' ';
|
||||||
|
pointer-events: none;
|
||||||
|
border-bottom: 1px solid $u-border-color;
|
||||||
|
/* #endif */
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
transform: scaleY(0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell-border {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__label {
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 26rpx;
|
||||||
|
line-height: 36rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
word-wrap: break-word;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__value {
|
||||||
|
overflow: hidden;
|
||||||
|
text-align: right;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
vertical-align: middle;
|
||||||
|
/* #endif */
|
||||||
|
color: $u-tips-color;
|
||||||
|
font-size: 26rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell__title,
|
||||||
|
.u-cell__value {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell--required {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
overflow: visible;
|
||||||
|
/* #endif */
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell--required:before {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
content: '*';
|
||||||
|
/* #endif */
|
||||||
|
left: 8px;
|
||||||
|
margin-top: 4rpx;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-cell_right {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
123
node_modules/uview-ui/components/u-checkbox-group/u-checkbox-group.vue
generated
vendored
Normal file
123
node_modules/uview-ui/components/u-checkbox-group/u-checkbox-group.vue
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-checkbox-group u-clearfix">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Emitter from '../../libs/util/emitter.js';
|
||||||
|
/**
|
||||||
|
* checkboxGroup 开关选择器父组件Group
|
||||||
|
* @description 复选框组件一般用于需要多个选择的场景,该组件功能完整,使用方便
|
||||||
|
* @tutorial https://www.uviewui.com/components/checkbox.html
|
||||||
|
* @property {String Number} max 最多能选中多少个checkbox(默认999)
|
||||||
|
* @property {String Number} size 组件整体的大小,单位rpx(默认40)
|
||||||
|
* @property {Boolean} disabled 是否禁用所有checkbox(默认false)
|
||||||
|
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
|
||||||
|
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox(默认false)
|
||||||
|
* @property {String} width 宽度,需带单位
|
||||||
|
* @property {String} width 宽度,需带单位
|
||||||
|
* @property {String} shape 外观形状,shape-方形,circle-圆形(默认circle)
|
||||||
|
* @property {Boolean} wrap 是否每个checkbox都换行(默认false)
|
||||||
|
* @property {String} active-color 选中时的颜色,应用到所有子Checkbox组件(默认#2979ff)
|
||||||
|
* @event {Function} change 任一个checkbox状态发生变化时触发,回调为一个对象
|
||||||
|
* @example <u-checkbox-group></u-checkbox-group>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-checkbox-group',
|
||||||
|
mixins: [Emitter],
|
||||||
|
props: {
|
||||||
|
// 最多能选中多少个checkbox
|
||||||
|
max: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 999
|
||||||
|
},
|
||||||
|
// 所有选中项的 name
|
||||||
|
// value: {
|
||||||
|
// default: Array,
|
||||||
|
// default() {
|
||||||
|
// return []
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// 是否禁用所有复选框
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 在表单内提交时的标识符
|
||||||
|
name: {
|
||||||
|
type: [Boolean, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否禁止点击提示语选中复选框
|
||||||
|
labelDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 形状,square为方形,circle为原型
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
// 选中状态下的颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
},
|
||||||
|
// 组件的整体大小
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 34
|
||||||
|
},
|
||||||
|
// 每个checkbox占u-checkbox-group的宽度
|
||||||
|
width: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
// 是否每个checkbox都换行
|
||||||
|
wrap: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 图标的大小,单位rpx
|
||||||
|
iconSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 20
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 如果将children定义在data中,在微信小程序会造成循环引用而报错
|
||||||
|
this.children = [];
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
emitEvent() {
|
||||||
|
let values = [];
|
||||||
|
this.children.map(val => {
|
||||||
|
if(val.value) values.push(val.name);
|
||||||
|
})
|
||||||
|
this.$emit('change', values);
|
||||||
|
// 发出事件,用于在表单组件中嵌入checkbox的情况,进行验证
|
||||||
|
// 由于头条小程序执行迟钝,故需要用几十毫秒的延时
|
||||||
|
setTimeout(() => {
|
||||||
|
// 将当前的值发送到 u-form-item 进行校验
|
||||||
|
this.dispatch('u-form-item', 'on-form-change', values);
|
||||||
|
}, 60)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-checkbox-group {
|
||||||
|
/* #ifndef MP || APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
284
node_modules/uview-ui/components/u-checkbox/u-checkbox.vue
generated
vendored
Normal file
284
node_modules/uview-ui/components/u-checkbox/u-checkbox.vue
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-checkbox" :style="[checkboxStyle]">
|
||||||
|
<view class="u-checkbox__icon-wrap" @tap="toggle" :class="[iconClass]" :style="[iconStyle]">
|
||||||
|
<u-icon class="u-checkbox__icon-wrap__icon" name="checkbox-mark" :size="checkboxIconSize" :color="iconColor"/>
|
||||||
|
</view>
|
||||||
|
<view class="u-checkbox__label" @tap="onClickLabel" :style="{
|
||||||
|
fontSize: $u.addUnit(labelSize)
|
||||||
|
}">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* checkbox 复选框
|
||||||
|
* @description 该组件需要搭配checkboxGroup组件使用,以便用户进行操作时,获得当前复选框组的选中情况。
|
||||||
|
* @tutorial https://www.uviewui.com/components/checkbox.html
|
||||||
|
* @property {String Number} icon-size 图标大小,单位rpx(默认20)
|
||||||
|
* @property {String Number} label-size label字体大小,单位rpx(默认28)
|
||||||
|
* @property {String Number} name checkbox组件的标示符
|
||||||
|
* @property {String} shape 形状,见官网说明(默认circle)
|
||||||
|
* @property {Boolean} disabled 是否禁用
|
||||||
|
* @property {Boolean} label-disabled 是否禁止点击文本操作checkbox
|
||||||
|
* @property {String} active-color 选中时的颜色,如设置CheckboxGroup的active-color将失效
|
||||||
|
* @event {Function} change 某个checkbox状态发生变化时触发,回调为一个对象
|
||||||
|
* @example <u-checkbox v-model="checked" :disabled="false">天涯</u-checkbox>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-checkbox",
|
||||||
|
props: {
|
||||||
|
// checkbox的名称
|
||||||
|
name: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 形状,square为方形,circle为原型
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否为选中状态
|
||||||
|
value: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否禁用
|
||||||
|
disabled: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否禁止点击提示语选中复选框
|
||||||
|
labelDisabled: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 选中状态下的颜色,如设置此值,将会覆盖checkboxGroup的activeColor值
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 图标的大小,单位rpx
|
||||||
|
iconSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// label的字体大小,rpx单位
|
||||||
|
labelSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 组件的整体大小
|
||||||
|
size: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
parentDisabled: false,
|
||||||
|
newParams: {},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 支付宝小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环应用
|
||||||
|
this.parent = this.$u.$parent.call(this, 'u-checkbox-group');
|
||||||
|
// 如果存在u-checkbox-group,将本组件的this塞进父组件的children中
|
||||||
|
this.parent && this.parent.children.push(this);
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 是否禁用,如果父组件u-checkbox-group禁用的话,将会忽略子组件的配置
|
||||||
|
isDisabled() {
|
||||||
|
return this.disabled !== '' ? this.disabled : this.parent ? this.parent.disabled : false;
|
||||||
|
},
|
||||||
|
// 是否禁用label点击
|
||||||
|
isLabelDisabled() {
|
||||||
|
return this.labelDisabled !== '' ? this.labelDisabled : this.parent ? this.parent.labelDisabled : false;
|
||||||
|
},
|
||||||
|
// 组件尺寸,对应size的值,默认值为34rpx
|
||||||
|
checkboxSize() {
|
||||||
|
return this.size ? this.size : (this.parent ? this.parent.size : 34);
|
||||||
|
},
|
||||||
|
// 组件的勾选图标的尺寸,默认20
|
||||||
|
checkboxIconSize() {
|
||||||
|
return this.iconSize ? this.iconSize : (this.parent ? this.parent.iconSize : 20);
|
||||||
|
},
|
||||||
|
// 组件选中激活时的颜色
|
||||||
|
elActiveColor() {
|
||||||
|
return this.activeColor ? this.activeColor : (this.parent ? this.parent.activeColor : 'primary');
|
||||||
|
},
|
||||||
|
// 组件的形状
|
||||||
|
elShape() {
|
||||||
|
return this.shape ? this.shape : (this.parent ? this.parent.shape : 'square');
|
||||||
|
},
|
||||||
|
iconStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 既要判断是否手动禁用,还要判断用户v-model绑定的值,如果绑定为false,那么也无法选中
|
||||||
|
if (this.elActiveColor && this.value && !this.isDisabled) {
|
||||||
|
style.borderColor = this.elActiveColor;
|
||||||
|
style.backgroundColor = this.elActiveColor;
|
||||||
|
}
|
||||||
|
style.width = this.$u.addUnit(this.checkboxSize);
|
||||||
|
style.height = this.$u.addUnit(this.checkboxSize);
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// checkbox内部的勾选图标,如果选中状态,为白色,否则为透明色即可
|
||||||
|
iconColor() {
|
||||||
|
return this.value ? '#ffffff' : 'transparent';
|
||||||
|
},
|
||||||
|
iconClass() {
|
||||||
|
let classes = [];
|
||||||
|
classes.push('u-checkbox__icon-wrap--' + this.elShape);
|
||||||
|
if (this.value == true) classes.push('u-checkbox__icon-wrap--checked');
|
||||||
|
if (this.isDisabled) classes.push('u-checkbox__icon-wrap--disabled');
|
||||||
|
if (this.value && this.isDisabled) classes.push('u-checkbox__icon-wrap--disabled--checked');
|
||||||
|
// 支付宝小程序无法动态绑定一个数组类名,否则解析出来的结果会带有",",而导致失效
|
||||||
|
return classes.join(' ');
|
||||||
|
},
|
||||||
|
checkboxStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.parent && this.parent.width) {
|
||||||
|
style.width = this.parent.width;
|
||||||
|
// #ifdef MP
|
||||||
|
// 各家小程序因为它们特殊的编译结构,使用float布局
|
||||||
|
style.float = 'left';
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP
|
||||||
|
// H5和APP使用flex布局
|
||||||
|
style.flex = `0 0 ${this.parent.width}`;
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
if(this.parent && this.parent.wrap) {
|
||||||
|
style.width = '100%';
|
||||||
|
// #ifndef MP
|
||||||
|
// H5和APP使用flex布局,将宽度设置100%,即可自动换行
|
||||||
|
style.flex = '0 0 100%';
|
||||||
|
// #endif
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onClickLabel() {
|
||||||
|
if (!this.isLabelDisabled && !this.isDisabled) {
|
||||||
|
this.setValue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
toggle() {
|
||||||
|
if (!this.isDisabled) {
|
||||||
|
this.setValue();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emitEvent() {
|
||||||
|
this.$emit('change', {
|
||||||
|
value: !this.value,
|
||||||
|
name: this.name
|
||||||
|
})
|
||||||
|
// 执行父组件u-checkbox-group的事件方法
|
||||||
|
// 等待下一个周期再执行,因为this.$emit('input')作用于父组件,再反馈到子组件内部,需要时间
|
||||||
|
setTimeout(() => {
|
||||||
|
if(this.parent && this.parent.emitEvent) this.parent.emitEvent();
|
||||||
|
}, 80);
|
||||||
|
},
|
||||||
|
// 设置input的值,这里通过input事件,设置通过v-model绑定的组件的值
|
||||||
|
setValue() {
|
||||||
|
// 判断是否超过了可选的最大数量
|
||||||
|
let checkedNum = 0;
|
||||||
|
if(this.parent && this.parent.children) {
|
||||||
|
// 只要父组件的某一个子元素的value为true,就加1(已有的选中数量)
|
||||||
|
this.parent.children.map(val => {
|
||||||
|
if (val.value) checkedNum++;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 如果原来为选中状态,那么可以取消
|
||||||
|
if (this.value == true) {
|
||||||
|
this.emitEvent();
|
||||||
|
this.$emit('input', !this.value);
|
||||||
|
} else {
|
||||||
|
// 如果超出最多可选项,提示
|
||||||
|
if(this.parent && checkedNum >= this.parent.max) {
|
||||||
|
return this.$u.toast(`最多可选${this.parent.max}项`);
|
||||||
|
}
|
||||||
|
// 如果原来为未选中状态,需要选中的数量少于父组件中设置的max值,才可以选中
|
||||||
|
this.emitEvent();
|
||||||
|
this.$emit('input', !this.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-checkbox {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
user-select: none;
|
||||||
|
line-height: 1.8;
|
||||||
|
|
||||||
|
&__icon-wrap {
|
||||||
|
color: $u-content-color;
|
||||||
|
flex: none;
|
||||||
|
display: -webkit-flex;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 42rpx;
|
||||||
|
height: 42rpx;
|
||||||
|
color: transparent;
|
||||||
|
text-align: center;
|
||||||
|
transition-property: color, border-color, background-color;
|
||||||
|
font-size: 20px;
|
||||||
|
border: 1px solid #c8c9cc;
|
||||||
|
transition-duration: 0.2s;
|
||||||
|
|
||||||
|
/* #ifdef MP-TOUTIAO */
|
||||||
|
// 头条小程序兼容性问题,需要设置行高为0,否则图标偏下
|
||||||
|
&__icon {
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
&--circle {
|
||||||
|
border-radius: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--square {
|
||||||
|
border-radius: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--checked {
|
||||||
|
color: #fff;
|
||||||
|
background-color: $u-type-primary;
|
||||||
|
border-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
background-color: #ebedf0;
|
||||||
|
border-color: #c8c9cc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--disabled--checked {
|
||||||
|
color: #c8c9cc !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
word-wrap: break-word;
|
||||||
|
margin-left: 10rpx;
|
||||||
|
margin-right: 24rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
font-size: 30rpx;
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: #c8c9cc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
220
node_modules/uview-ui/components/u-circle-progress/u-circle-progress.vue
generated
vendored
Normal file
220
node_modules/uview-ui/components/u-circle-progress/u-circle-progress.vue
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-circle-progress"
|
||||||
|
:style="{
|
||||||
|
width: widthPx + 'px',
|
||||||
|
height: widthPx + 'px',
|
||||||
|
backgroundColor: bgColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<!-- 支付宝小程序不支持canvas-id属性,必须用id属性 -->
|
||||||
|
<canvas
|
||||||
|
class="u-canvas-bg"
|
||||||
|
:canvas-id="elBgId"
|
||||||
|
:id="elBgId"
|
||||||
|
:style="{
|
||||||
|
width: widthPx + 'px',
|
||||||
|
height: widthPx + 'px'
|
||||||
|
}"
|
||||||
|
></canvas>
|
||||||
|
<canvas
|
||||||
|
class="u-canvas"
|
||||||
|
:canvas-id="elId"
|
||||||
|
:id="elId"
|
||||||
|
:style="{
|
||||||
|
width: widthPx + 'px',
|
||||||
|
height: widthPx + 'px'
|
||||||
|
}"
|
||||||
|
></canvas>
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* circleProgress 环形进度条
|
||||||
|
* @description 展示操作或任务的当前进度,比如上传文件,是一个圆形的进度条。注意:此组件的percent值只能动态增加,不能动态减少。
|
||||||
|
* @tutorial https://www.uviewui.com/components/circleProgress.html
|
||||||
|
* @property {String Number} percent 圆环进度百分比值,为数值类型,0-100
|
||||||
|
* @property {String} inactive-color 圆环的底色,默认为灰色(该值无法动态变更)(默认#ececec)
|
||||||
|
* @property {String} active-color 圆环激活部分的颜色(该值无法动态变更)(默认#19be6b)
|
||||||
|
* @property {String Number} width 整个圆环组件的宽度,高度默认等于宽度值,单位rpx(默认200)
|
||||||
|
* @property {String Number} border-width 圆环的边框宽度,单位rpx(默认14)
|
||||||
|
* @property {String Number} duration 整个圆环执行一圈的时间,单位ms(默认呢1500)
|
||||||
|
* @property {String} type 如设置,active-color值将会失效
|
||||||
|
* @property {String} bg-color 整个组件背景颜色,默认为白色
|
||||||
|
* @example <u-circle-progress active-color="#2979ff" :percent="80"></u-circle-progress>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-circle-progress',
|
||||||
|
props: {
|
||||||
|
// 圆环进度百分比值
|
||||||
|
percent: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
// 限制值在0到100之间
|
||||||
|
validator: val => {
|
||||||
|
return val >= 0 && val <= 100;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 底部圆环的颜色(灰色的圆环)
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ececec'
|
||||||
|
},
|
||||||
|
// 圆环激活部分的颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#19be6b'
|
||||||
|
},
|
||||||
|
// 圆环线条的宽度,单位rpx
|
||||||
|
borderWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 14
|
||||||
|
},
|
||||||
|
// 整个圆形的宽度,单位rpx
|
||||||
|
width: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 200
|
||||||
|
},
|
||||||
|
// 整个圆环执行一圈的时间,单位ms
|
||||||
|
duration: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 1500
|
||||||
|
},
|
||||||
|
// 主题类型
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 整个圆环进度区域的背景色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// #ifdef MP-WEIXIN
|
||||||
|
elBgId: 'uCircleProgressBgId', // 微信小程序中不能使用this.$u.guid()形式动态生成id值,否则会报错
|
||||||
|
elId: 'uCircleProgressElId',
|
||||||
|
// #endif
|
||||||
|
// #ifndef MP-WEIXIN
|
||||||
|
elBgId: this.$u.guid(), // 非微信端的时候,需用动态的id,否则一个页面多个圆形进度条组件数据会混乱
|
||||||
|
elId: this.$u.guid(),
|
||||||
|
// #endif
|
||||||
|
widthPx: uni.upx2px(this.width), // 转成px后的整个组件的背景宽度
|
||||||
|
borderWidthPx: uni.upx2px(this.borderWidth), // 转成px后的圆环的宽度
|
||||||
|
startAngle: -Math.PI / 2, // canvas画圆的起始角度,默认为3点钟方向,定位到12点钟方向
|
||||||
|
progressContext: null, // 活动圆的canvas上下文
|
||||||
|
newPercent: 0, // 当动态修改进度值的时候,保存进度值的变化前后值,用于比较用
|
||||||
|
oldPercent: 0 // 当动态修改进度值的时候,保存进度值的变化前后值,用于比较用
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
percent(nVal, oVal = 0) {
|
||||||
|
if (nVal > 100) nVal = 100;
|
||||||
|
if (nVal < 0) oVal = 0;
|
||||||
|
// 此值其实等于this.percent,命名一个新
|
||||||
|
this.newPercent = nVal;
|
||||||
|
this.oldPercent = oVal;
|
||||||
|
setTimeout(() => {
|
||||||
|
// 无论是百分比值增加还是减少,需要操作还是原来的旧的百分比值
|
||||||
|
// 将此值减少或者新增到新的百分比值
|
||||||
|
this.drawCircleByProgress(oVal);
|
||||||
|
}, 50);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 赋值,用于加载后第一个画圆使用
|
||||||
|
this.newPercent = this.percent;
|
||||||
|
this.oldPercent = 0;
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 有type主题时,优先起作用
|
||||||
|
circleColor() {
|
||||||
|
if (['success', 'error', 'info', 'primary', 'warning'].indexOf(this.type) >= 0) return this.$u.color[this.type];
|
||||||
|
else return this.activeColor;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 在h5端,必须要做一点延时才起作用,this.$nextTick()无效(HX2.4.7)
|
||||||
|
setTimeout(() => {
|
||||||
|
this.drawProgressBg();
|
||||||
|
this.drawCircleByProgress(this.oldPercent);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
drawProgressBg() {
|
||||||
|
let ctx = uni.createCanvasContext(this.elBgId, this);
|
||||||
|
ctx.setLineWidth(this.borderWidthPx); // 设置圆环宽度
|
||||||
|
ctx.setStrokeStyle(this.inactiveColor); // 线条颜色
|
||||||
|
ctx.beginPath(); // 开始描绘路径
|
||||||
|
// 设置一个原点(110,110),半径为100的圆的路径到当前路径
|
||||||
|
let radius = this.widthPx / 2;
|
||||||
|
ctx.arc(radius, radius, radius - this.borderWidthPx, 0, 2 * Math.PI, false);
|
||||||
|
ctx.stroke(); // 对路径进行描绘
|
||||||
|
ctx.draw();
|
||||||
|
},
|
||||||
|
drawCircleByProgress(progress) {
|
||||||
|
// 第一次操作进度环时将上下文保存到了this.data中,直接使用即可
|
||||||
|
let ctx = this.progressContext;
|
||||||
|
if (!ctx) {
|
||||||
|
ctx = uni.createCanvasContext(this.elId, this);
|
||||||
|
this.progressContext = ctx;
|
||||||
|
}
|
||||||
|
// 表示进度的两端为圆形
|
||||||
|
ctx.setLineCap('round');
|
||||||
|
// 设置线条的宽度和颜色
|
||||||
|
ctx.setLineWidth(this.borderWidthPx);
|
||||||
|
ctx.setStrokeStyle(this.circleColor);
|
||||||
|
// 将总过渡时间除以100,得出每修改百分之一进度所需的时间
|
||||||
|
let time = Math.floor(this.duration / 100);
|
||||||
|
// 结束角的计算依据为:将2π分为100份,乘以当前的进度值,得出终止点的弧度值,加起始角,为整个圆从默认的
|
||||||
|
// 3点钟方向开始画图,转为更好理解的12点钟方向开始作图,这需要起始角和终止角同时加上this.startAngle值
|
||||||
|
let endAngle = ((2 * Math.PI) / 100) * progress + this.startAngle;
|
||||||
|
ctx.beginPath();
|
||||||
|
// 半径为整个canvas宽度的一半
|
||||||
|
let radius = this.widthPx / 2;
|
||||||
|
ctx.arc(radius, radius, radius - this.borderWidthPx, this.startAngle, endAngle, false);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.draw();
|
||||||
|
// 如果变更后新值大于旧值,意味着增大了百分比
|
||||||
|
if (this.newPercent > this.oldPercent) {
|
||||||
|
// 每次递增百分之一
|
||||||
|
progress++;
|
||||||
|
// 如果新增后的值,大于需要设置的值百分比值,停止继续增加
|
||||||
|
if (progress > this.newPercent) return;
|
||||||
|
} else {
|
||||||
|
// 同理于上面
|
||||||
|
progress--;
|
||||||
|
if (progress < this.newPercent) return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
// 定时器,每次操作间隔为time值,为了让进度条有动画效果
|
||||||
|
this.drawCircleByProgress(progress);
|
||||||
|
}, time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
.u-circle-progress {
|
||||||
|
position: relative;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-canvas-bg {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-canvas {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
147
node_modules/uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue
generated
vendored
Normal file
147
node_modules/uview-ui/components/u-circle-progress/u-line-progress/u-line-progress.vue
generated
vendored
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-progress" :style="{
|
||||||
|
borderRadius: round ? '100rpx' : 0,
|
||||||
|
height: height + 'rpx',
|
||||||
|
backgroundColor: inactiveColor
|
||||||
|
}">
|
||||||
|
<view :class="[
|
||||||
|
type ? `u-type-${type}-bg` : '',
|
||||||
|
striped ? 'u-striped' : '',
|
||||||
|
striped && stripedActive ? 'u-striped-active' : ''
|
||||||
|
]" class="u-active" :style="[progressStyle]">
|
||||||
|
<slot v-if="$slots.default || $slots.$default" />
|
||||||
|
<block v-else-if="showPercent">
|
||||||
|
{{percent + '%'}}
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* lineProgress 线型进度条
|
||||||
|
* @description 展示操作或任务的当前进度,比如上传文件,是一个线形的进度条。
|
||||||
|
* @tutorial https://www.uviewui.com/components/lineProgress.html
|
||||||
|
* @property {String Number} percent 进度条百分比值,为数值类型,0-100
|
||||||
|
* @property {Boolean} round 进度条两端是否为半圆(默认true)
|
||||||
|
* @property {String} type 如设置,active-color值将会失效
|
||||||
|
* @property {String} active-color 进度条激活部分的颜色(默认#19be6b)
|
||||||
|
* @property {String} inactive-color 进度条的底色(默认#ececec)
|
||||||
|
* @property {Boolean} show-percent 是否在进度条内部显示当前的百分比值数值(默认true)
|
||||||
|
* @property {String Number} height 进度条的高度,单位rpx(默认28)
|
||||||
|
* @property {Boolean} striped 是否显示进度条激活部分的条纹(默认false)
|
||||||
|
* @property {Boolean} striped-active 条纹是否具有动态效果(默认false)
|
||||||
|
* @example <u-line-progress :percent="70" :show-percent="true"></u-line-progress>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-line-progress",
|
||||||
|
props: {
|
||||||
|
// 两端是否显示半圆形
|
||||||
|
round: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 主题颜色
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 激活部分的颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#19be6b'
|
||||||
|
},
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ececec'
|
||||||
|
},
|
||||||
|
// 进度百分比,数值
|
||||||
|
percent: {
|
||||||
|
type: Number,
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否在进度条内部显示百分比的值
|
||||||
|
showPercent: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 进度条的高度,单位rpx
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
// 是否显示条纹
|
||||||
|
striped: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 条纹是否显示活动状态
|
||||||
|
stripedActive: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
progressStyle() {
|
||||||
|
let style = {};
|
||||||
|
style.width = this.percent + '%';
|
||||||
|
if(this.activeColor) style.backgroundColor = this.activeColor;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-progress {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 15px;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 100rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-active {
|
||||||
|
width: 0;
|
||||||
|
height: 100%;
|
||||||
|
align-items: center;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-items: flex-end;
|
||||||
|
justify-content: space-around;
|
||||||
|
font-size: 20rpx;
|
||||||
|
color: #ffffff;
|
||||||
|
transition: all 0.4s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-striped {
|
||||||
|
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||||
|
background-size: 39px 39px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-striped-active {
|
||||||
|
animation: progress-stripes 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes progress-stripes {
|
||||||
|
0% {
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
100% {
|
||||||
|
background-position: 39px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
156
node_modules/uview-ui/components/u-col/u-col.vue
generated
vendored
Normal file
156
node_modules/uview-ui/components/u-col/u-col.vue
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-col" :class="[
|
||||||
|
'u-col-' + span
|
||||||
|
]" :style="{
|
||||||
|
padding: `0 ${Number(gutter)/2 + 'rpx'}`,
|
||||||
|
marginLeft: 100 / 12 * offset + '%',
|
||||||
|
flex: `0 0 ${100 / 12 * span}%`,
|
||||||
|
alignItems: uAlignItem,
|
||||||
|
justifyContent: uJustify,
|
||||||
|
textAlign: textAlign
|
||||||
|
}"
|
||||||
|
@tap="click">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* col 布局单元格
|
||||||
|
* @description 通过基础的 12 分栏,迅速简便地创建布局(搭配<u-row>使用)
|
||||||
|
* @tutorial https://www.uviewui.com/components/layout.html
|
||||||
|
* @property {String Number} span 栅格占据的列数,总12等分(默认0)
|
||||||
|
* @property {String} text-align 文字水平对齐方式(默认left)
|
||||||
|
* @property {String Number} offset 分栏左边偏移,计算方式与span相同(默认0)
|
||||||
|
* @example <u-col span="3"><view class="demo-layout bg-purple"></view></u-col>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-col",
|
||||||
|
props: {
|
||||||
|
// 占父容器宽度的多少等分,总分为12份
|
||||||
|
span: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 12
|
||||||
|
},
|
||||||
|
// 指定栅格左侧的间隔数(总12栏)
|
||||||
|
offset: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 水平排列方式,可选值为`start`(或`flex-start`)、`end`(或`flex-end`)、`center`、`around`(或`space-around`)、`between`(或`space-between`)
|
||||||
|
justify: {
|
||||||
|
type: String,
|
||||||
|
default: 'start'
|
||||||
|
},
|
||||||
|
// 垂直对齐方式,可选值为top、center、bottom
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'center'
|
||||||
|
},
|
||||||
|
// 文字对齐方式
|
||||||
|
textAlign: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// 是否阻止事件传播
|
||||||
|
stop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gutter: 20, // 给col添加间距,左右边距各占一半,从父组件u-row获取
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.parent = false;
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 获取父组件实例,并赋值给对应的参数
|
||||||
|
this.parent = this.$u.$parent.call(this, 'u-row');
|
||||||
|
if (this.parent) {
|
||||||
|
this.gutter = this.parent.gutter;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
uJustify() {
|
||||||
|
if (this.justify == 'end' || this.justify == 'start') return 'flex-' + this.justify;
|
||||||
|
else if (this.justify == 'around' || this.justify == 'between') return 'space-' + this.justify;
|
||||||
|
else return this.justify;
|
||||||
|
},
|
||||||
|
uAlignItem() {
|
||||||
|
if (this.align == 'top') return 'flex-start';
|
||||||
|
if (this.align == 'bottom') return 'flex-end';
|
||||||
|
else return this.align;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click(e) {
|
||||||
|
this.$emit('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-col {
|
||||||
|
/* #ifdef MP-WEIXIN || MP-QQ || MP-TOUTIAO */
|
||||||
|
float: left;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-0 {
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-1 {
|
||||||
|
width: calc(100%/12);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-2 {
|
||||||
|
width: calc(100%/12 * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-3 {
|
||||||
|
width: calc(100%/12 * 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-4 {
|
||||||
|
width: calc(100%/12 * 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-5 {
|
||||||
|
width: calc(100%/12 * 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-6 {
|
||||||
|
width: calc(100%/12 * 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-7 {
|
||||||
|
width: calc(100%/12 * 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-8 {
|
||||||
|
width: calc(100%/12 * 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-9 {
|
||||||
|
width: calc(100%/12 * 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-10 {
|
||||||
|
width: calc(100%/12 * 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-11 {
|
||||||
|
width: calc(100%/12 * 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-col-12 {
|
||||||
|
width: calc(100%/12 * 12);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
204
node_modules/uview-ui/components/u-collapse-item/u-collapse-item.vue
generated
vendored
Normal file
204
node_modules/uview-ui/components/u-collapse-item/u-collapse-item.vue
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-collapse-item" :style="[itemStyle]">
|
||||||
|
<view :hover-stay-time="200" class="u-collapse-head" @tap.stop="headClick" :hover-class="hoverClass" :style="[headStyle]">
|
||||||
|
<block v-if="!$slots['title-all']">
|
||||||
|
<view v-if="!$slots['title']" class="u-collapse-title u-line-1" :style="[{ textAlign: align ? align : 'left' },
|
||||||
|
isShow && activeStyle && !arrow ? activeStyle : '']">
|
||||||
|
{{ title }}
|
||||||
|
</view>
|
||||||
|
<slot v-else name="title" />
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon v-if="arrow" :color="arrowColor" :class="{ 'u-arrow-down-icon-active': isShow }"
|
||||||
|
class="u-arrow-down-icon" name="arrow-down"></u-icon>
|
||||||
|
</view>
|
||||||
|
</block>
|
||||||
|
<slot v-else name="title-all" />
|
||||||
|
</view>
|
||||||
|
<view class="u-collapse-body" :style="[{
|
||||||
|
height: isShow ? height + 'px' : '0'
|
||||||
|
}]">
|
||||||
|
<view class="u-collapse-content" :id="elId" :style="[bodyStyle]">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* collapseItem 手风琴Item
|
||||||
|
* @description 通过折叠面板收纳内容区域(搭配u-collapse使用)
|
||||||
|
* @tutorial https://www.uviewui.com/components/collapse.html
|
||||||
|
* @property {String} title 面板标题
|
||||||
|
* @property {String Number} index 主要用于事件的回调,标识那个Item被点击
|
||||||
|
* @property {Boolean} disabled 面板是否可以打开或收起(默认false)
|
||||||
|
* @property {Boolean} open 设置某个面板的初始状态是否打开(默认false)
|
||||||
|
* @property {String Number} name 唯一标识符,如不设置,默认用当前collapse-item的索引值
|
||||||
|
* @property {String} align 标题的对齐方式(默认left)
|
||||||
|
* @property {Object} active-style 不显示箭头时,可以添加当前选择的collapse-item活动样式,对象形式
|
||||||
|
* @event {Function} change 某个item被打开或者收起时触发
|
||||||
|
* @example <u-collapse-item :title="item.head" v-for="(item, index) in itemList" :key="index">{{item.body}}</u-collapse-item>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-collapse-item",
|
||||||
|
props: {
|
||||||
|
// 标题
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 标题的对齐方式
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// 是否可以点击收起
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// collapse显示与否
|
||||||
|
open: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 唯一标识符
|
||||||
|
name: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
//活动样式
|
||||||
|
activeStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 标识当前为第几个
|
||||||
|
index: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isShow: false,
|
||||||
|
elId: this.$u.guid(),
|
||||||
|
height: 0, // body内容的高度
|
||||||
|
headStyle: {}, // 头部样式,对象形式
|
||||||
|
bodyStyle: {}, // 主体部分样式
|
||||||
|
itemStyle: {}, // 每个item的整体样式
|
||||||
|
arrowColor: '', // 箭头的颜色
|
||||||
|
hoverClass: '', // 头部按下时的效果样式类
|
||||||
|
arrow: true, // 是否显示右侧箭头
|
||||||
|
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
open(val) {
|
||||||
|
this.isShow = val;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.parent = false;
|
||||||
|
// 获取u-collapse的信息,放在u-collapse是为了方便,不用每个u-collapse-item写一遍
|
||||||
|
this.isShow = this.open;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 异步获取内容,或者动态修改了内容时,需要重新初始化
|
||||||
|
init() {
|
||||||
|
this.parent = this.$u.$parent.call(this, 'u-collapse');
|
||||||
|
if(this.parent) {
|
||||||
|
this.nameSync = this.name ? this.name : this.parent.childrens.length;
|
||||||
|
this.parent.childrens.push(this);
|
||||||
|
this.headStyle = this.parent.headStyle;
|
||||||
|
this.bodyStyle = this.parent.bodyStyle;
|
||||||
|
this.arrowColor = this.parent.arrowColor;
|
||||||
|
this.hoverClass = this.parent.hoverClass;
|
||||||
|
this.arrow = this.parent.arrow;
|
||||||
|
this.itemStyle = this.parent.itemStyle;
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.queryRect();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 点击collapsehead头部
|
||||||
|
headClick() {
|
||||||
|
if (this.disabled) return;
|
||||||
|
if (this.parent && this.parent.accordion == true) {
|
||||||
|
this.parent.childrens.map(val => {
|
||||||
|
// 自身不设置为false,因为后面有this.isShow = !this.isShow;处理了
|
||||||
|
if (this != val) {
|
||||||
|
val.isShow = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isShow = !this.isShow;
|
||||||
|
// 触发本组件的事件
|
||||||
|
this.$emit('change', {
|
||||||
|
index: this.index,
|
||||||
|
show: this.isShow
|
||||||
|
})
|
||||||
|
// 只有在打开时才发出事件
|
||||||
|
if (this.isShow) this.parent && this.parent.onChange();
|
||||||
|
this.$forceUpdate();
|
||||||
|
},
|
||||||
|
// 查询内容高度
|
||||||
|
queryRect() {
|
||||||
|
// $uGetRect为uView自带的节点查询简化方法,详见文档介绍:https://www.uviewui.com/js/getRect.html
|
||||||
|
// 组件内部一般用this.$uGetRect,对外的为this.$u.getRect,二者功能一致,名称不同
|
||||||
|
this.$uGetRect('#' + this.elId).then(res => {
|
||||||
|
this.height = res.height;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-collapse-head {
|
||||||
|
position: relative;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
color: $u-main-color;
|
||||||
|
font-size: 30rpx;
|
||||||
|
line-height: 1;
|
||||||
|
padding: 24rpx 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-collapse-title {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-arrow-down-icon {
|
||||||
|
transition: all 0.3s;
|
||||||
|
margin-right: 20rpx;
|
||||||
|
margin-left: 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-arrow-down-icon-active {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-collapse-body {
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-collapse-content {
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-tips-color;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
99
node_modules/uview-ui/components/u-collapse/u-collapse.vue
generated
vendored
Normal file
99
node_modules/uview-ui/components/u-collapse/u-collapse.vue
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-collapse">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* collapse 手风琴
|
||||||
|
* @description 通过折叠面板收纳内容区域
|
||||||
|
* @tutorial https://www.uviewui.com/components/collapse.html
|
||||||
|
* @property {Boolean} accordion 是否手风琴模式(默认true)
|
||||||
|
* @property {Boolean} arrow 是否显示标题右侧的箭头(默认true)
|
||||||
|
* @property {String} arrow-color 标题右侧箭头的颜色(默认#909399)
|
||||||
|
* @property {Object} head-style 标题自定义样式,对象形式
|
||||||
|
* @property {Object} body-style 主体自定义样式,对象形式
|
||||||
|
* @property {String} hover-class 样式类名,按下时有效(默认u-hover-class)
|
||||||
|
* @event {Function} change 当前激活面板展开时触发(如果是手风琴模式,参数activeNames类型为String,否则为Array)
|
||||||
|
* @example <u-collapse></u-collapse>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name:"u-collapse",
|
||||||
|
props: {
|
||||||
|
// 是否手风琴模式
|
||||||
|
accordion: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 头部的样式
|
||||||
|
headStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 主体的样式
|
||||||
|
bodyStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 每一个item的样式
|
||||||
|
itemStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否显示右侧的箭头
|
||||||
|
arrow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 箭头的颜色
|
||||||
|
arrowColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#909399'
|
||||||
|
},
|
||||||
|
// 标题部分按压时的样式类,"none"为无效果
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: 'u-hover-class'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.childrens = []
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 重新初始化一次内部的所有子元素的高度计算,用于异步获取数据渲染的情况
|
||||||
|
init() {
|
||||||
|
this.childrens.forEach((vm, index) => {
|
||||||
|
vm.init();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// collapse item被点击,由collapse item调用父组件方法
|
||||||
|
onChange() {
|
||||||
|
let activeItem = [];
|
||||||
|
this.childrens.forEach((vm, index) => {
|
||||||
|
if (vm.isShow) {
|
||||||
|
activeItem.push(vm.nameSync);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 如果是手风琴模式,只有一个匹配结果,也即activeItem长度为1,将其转为字符串
|
||||||
|
if (this.accordion) activeItem = activeItem.join('');
|
||||||
|
this.$emit('change', activeItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
</style>
|
||||||
237
node_modules/uview-ui/components/u-column-notice/u-column-notice.vue
generated
vendored
Normal file
237
node_modules/uview-ui/components/u-column-notice/u-column-notice.vue
generated
vendored
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-notice-bar"
|
||||||
|
:style="{
|
||||||
|
background: computeBgColor,
|
||||||
|
padding: padding
|
||||||
|
}"
|
||||||
|
:class="[
|
||||||
|
type ? `u-type-${type}-light-bg` : ''
|
||||||
|
]"
|
||||||
|
>
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon class="u-left-icon" v-if="volumeIcon" name="volume-fill" :size="volumeSize" :color="computeColor"></u-icon>
|
||||||
|
</view>
|
||||||
|
<swiper :disable-touch="disableTouch" @change="change" :autoplay="autoplay && playState == 'play'" :vertical="vertical" circular :interval="duration" class="u-swiper">
|
||||||
|
<swiper-item v-for="(item, index) in list" :key="index" class="u-swiper-item">
|
||||||
|
<view
|
||||||
|
class="u-news-item u-line-1"
|
||||||
|
:style="[textStyle]"
|
||||||
|
@tap="click(index)"
|
||||||
|
:class="['u-type-' + type]"
|
||||||
|
>
|
||||||
|
{{ item }}
|
||||||
|
</view>
|
||||||
|
</swiper-item>
|
||||||
|
</swiper>
|
||||||
|
<view class="u-icon-wrap">
|
||||||
|
<u-icon @click="getMore" class="u-right-icon" v-if="moreIcon" name="arrow-right" :size="26" :color="computeColor"></u-icon>
|
||||||
|
<u-icon @click="close" class="u-right-icon" v-if="closeIcon" name="close" :size="24" :color="computeColor"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
props: {
|
||||||
|
// 显示的内容,数组
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 显示的主题,success|error|primary|info|warning
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'warning'
|
||||||
|
},
|
||||||
|
// 是否显示左侧的音量图标
|
||||||
|
volumeIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示右侧的右箭头图标
|
||||||
|
moreIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示右侧的关闭图标
|
||||||
|
closeIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否自动播放
|
||||||
|
autoplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 文字颜色,各图标也会使用文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 滚动方向,row-水平滚动,column-垂直滚动
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
default: 'row'
|
||||||
|
},
|
||||||
|
// 是否显示
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 字体大小,单位rpx
|
||||||
|
fontSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 26
|
||||||
|
},
|
||||||
|
// 滚动一个周期的时间长,单位ms
|
||||||
|
duration: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 2000
|
||||||
|
},
|
||||||
|
// 音量喇叭的大小
|
||||||
|
volumeSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 34
|
||||||
|
},
|
||||||
|
// 水平滚动时的滚动速度,即每秒滚动多少rpx,这有利于控制文字无论多少时,都能有一个恒定的速度
|
||||||
|
speed: {
|
||||||
|
type: Number,
|
||||||
|
default: 160
|
||||||
|
},
|
||||||
|
// 水平滚动时,是否采用衔接形式滚动
|
||||||
|
isCircular: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 滚动方向,horizontal-水平滚动,vertical-垂直滚动
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'horizontal'
|
||||||
|
},
|
||||||
|
// 播放状态,play-播放,paused-暂停
|
||||||
|
playState: {
|
||||||
|
type: String,
|
||||||
|
default: 'play'
|
||||||
|
},
|
||||||
|
// 是否禁止用手滑动切换
|
||||||
|
// 目前HX2.6.11,只支持App 2.5.5+、H5 2.5.5+、支付宝小程序、字节跳动小程序
|
||||||
|
disableTouch: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 通知的边距
|
||||||
|
padding: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '18rpx 24rpx'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 计算字体颜色,如果没有自定义的,就用uview主题颜色
|
||||||
|
computeColor() {
|
||||||
|
if (this.color) return this.color;
|
||||||
|
// 如果是无主题,就默认使用content-color
|
||||||
|
else if(this.type == 'none') return '#606266';
|
||||||
|
else return this.type;
|
||||||
|
},
|
||||||
|
// 文字内容的样式
|
||||||
|
textStyle() {
|
||||||
|
let style = {};
|
||||||
|
if (this.color) style.color = this.color;
|
||||||
|
else if(this.type == 'none') style.color = '#606266';
|
||||||
|
style.fontSize = this.fontSize + 'rpx';
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 垂直或者水平滚动
|
||||||
|
vertical() {
|
||||||
|
if(this.mode == 'horizontal') return false;
|
||||||
|
else return true;
|
||||||
|
},
|
||||||
|
// 计算背景颜色
|
||||||
|
computeBgColor() {
|
||||||
|
if (this.bgColor) return this.bgColor;
|
||||||
|
else if(this.type == 'none') return 'transparent';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// animation: false
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击通告栏
|
||||||
|
click(index) {
|
||||||
|
this.$emit('click', index);
|
||||||
|
},
|
||||||
|
// 点击关闭按钮
|
||||||
|
close() {
|
||||||
|
this.$emit('close');
|
||||||
|
},
|
||||||
|
// 点击更多箭头按钮
|
||||||
|
getMore() {
|
||||||
|
this.$emit('getMore');
|
||||||
|
},
|
||||||
|
change(e) {
|
||||||
|
let index = e.detail.current;
|
||||||
|
if(index == this.list.length - 1) {
|
||||||
|
this.$emit('end');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-notice-bar {
|
||||||
|
width: 100%;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
padding: 18rpx 24rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-swiper {
|
||||||
|
font-size: 26rpx;
|
||||||
|
height: 32rpx;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
margin-left: 12rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-swiper-item {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-news-item {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-right-icon {
|
||||||
|
margin-left: 12rpx;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-left-icon {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
318
node_modules/uview-ui/components/u-count-down/u-count-down.vue
generated
vendored
Normal file
318
node_modules/uview-ui/components/u-count-down/u-count-down.vue
generated
vendored
Normal file
@@ -0,0 +1,318 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-countdown">
|
||||||
|
<view class="u-countdown-item" :style="[itemStyle]" v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))">
|
||||||
|
<view class="u-countdown-time" :style="[letterStyle]">
|
||||||
|
{{ d }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-countdown-colon"
|
||||||
|
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
|
||||||
|
v-if="showDays && (hideZeroDay || (!hideZeroDay && d != '00'))"
|
||||||
|
>
|
||||||
|
{{ separator == 'colon' ? ':' : '天' }}
|
||||||
|
</view>
|
||||||
|
<view class="u-countdown-item" :style="[itemStyle]" v-if="showHours">
|
||||||
|
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
|
||||||
|
{{ h }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-countdown-colon"
|
||||||
|
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
|
||||||
|
v-if="showHours"
|
||||||
|
>
|
||||||
|
{{ separator == 'colon' ? ':' : '时' }}
|
||||||
|
</view>
|
||||||
|
<view class="u-countdown-item" :style="[itemStyle]" v-if="showMinutes">
|
||||||
|
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
|
||||||
|
{{ i }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-countdown-colon"
|
||||||
|
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
|
||||||
|
v-if="showMinutes"
|
||||||
|
>
|
||||||
|
{{ separator == 'colon' ? ':' : '分' }}
|
||||||
|
</view>
|
||||||
|
<view class="u-countdown-item" :style="[itemStyle]" v-if="showSeconds">
|
||||||
|
<view class="u-countdown-time" :style="{ fontSize: fontSize + 'rpx', color: color}">
|
||||||
|
{{ s }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
class="u-countdown-colon"
|
||||||
|
:style="{fontSize: separatorSize + 'rpx', color: separatorColor, paddingBottom: separator == 'colon' ? '4rpx' : 0}"
|
||||||
|
v-if="showSeconds && separator == 'zh'"
|
||||||
|
>
|
||||||
|
秒
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* countDown 倒计时
|
||||||
|
* @description 该组件一般使用于某个活动的截止时间上,通过数字的变化,给用户明确的时间感受,提示用户进行某一个行为操作。
|
||||||
|
* @tutorial https://www.uviewui.com/components/countDown.html
|
||||||
|
* @property {String Number} timestamp 倒计时,单位为秒
|
||||||
|
* @property {Boolean} autoplay 是否自动开始倒计时,如果为false,需手动调用开始方法。见官网说明(默认true)
|
||||||
|
* @property {String} separator 分隔符,colon为英文冒号,zh为中文(默认colon)
|
||||||
|
* @property {String Number} separator-size 分隔符的字体大小,单位rpx(默认30)
|
||||||
|
* @property {String} separator-color 分隔符的颜色(默认#303133)
|
||||||
|
* @property {String Number} font-size 倒计时字体大小,单位rpx(默认30)
|
||||||
|
* @property {Boolean} show-border 是否显示倒计时数字的边框(默认false)
|
||||||
|
* @property {Boolean} hide-zero-day 当"天"的部分为0时,隐藏该字段 (默认true)
|
||||||
|
* @property {String} border-color 数字边框的颜色(默认#303133)
|
||||||
|
* @property {String} bg-color 倒计时数字的背景颜色(默认#ffffff)
|
||||||
|
* @property {String} color 倒计时数字的颜色(默认#303133)
|
||||||
|
* @property {String} height 数字高度值(宽度等同此值),设置边框时看情况是否需要设置此值,单位rpx(默认auto)
|
||||||
|
* @property {Boolean} show-days 是否显示倒计时的"天"部分(默认true)
|
||||||
|
* @property {Boolean} show-hours 是否显示倒计时的"时"部分(默认true)
|
||||||
|
* @property {Boolean} show-minutes 是否显示倒计时的"分"部分(默认true)
|
||||||
|
* @property {Boolean} show-seconds 是否显示倒计时的"秒"部分(默认true)
|
||||||
|
* @event {Function} end 倒计时结束
|
||||||
|
* @event {Function} change 每秒触发一次,回调为当前剩余的倒计秒数
|
||||||
|
* @example <u-count-down ref="uCountDown" :timestamp="86400" :autoplay="false"></u-count-down>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-count-down',
|
||||||
|
props: {
|
||||||
|
// 倒计时的时间,秒为单位
|
||||||
|
timestamp: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否自动开始倒计时
|
||||||
|
autoplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 用英文冒号(colon)或者中文(zh)当做分隔符,false的时候为中文,如:"11:22"或"11时22秒"
|
||||||
|
separator: {
|
||||||
|
type: String,
|
||||||
|
default: 'colon'
|
||||||
|
},
|
||||||
|
// 分隔符的大小,单位rpx
|
||||||
|
separatorSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
// 分隔符颜色
|
||||||
|
separatorColor: {
|
||||||
|
type: String,
|
||||||
|
default: "#303133"
|
||||||
|
},
|
||||||
|
// 字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 字体大小,单位rpx
|
||||||
|
fontSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#fff'
|
||||||
|
},
|
||||||
|
// 数字框高度,单位rpx
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
// 是否显示数字框
|
||||||
|
showBorder: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 边框颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 是否显示秒
|
||||||
|
showSeconds: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示分钟
|
||||||
|
showMinutes: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示小时
|
||||||
|
showHours: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示“天”
|
||||||
|
showDays: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 当"天"的部分为0时,不显示
|
||||||
|
hideZeroDay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 监听时间戳的变化
|
||||||
|
timestamp(newVal, oldVal) {
|
||||||
|
// 如果倒计时间发生变化,清除定时器,重新开始倒计时
|
||||||
|
this.clearTimer();
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
d: '00', // 天的默认值
|
||||||
|
h: '00', // 小时的默认值
|
||||||
|
i: '00', // 分钟的默认值
|
||||||
|
s: '00', // 秒的默认值
|
||||||
|
timer: null ,// 定时器
|
||||||
|
seconds: 0, // 记录不停倒计过程中变化的秒数
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 倒计时item的样式,item为分别的时分秒部分的数字
|
||||||
|
itemStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.height) {
|
||||||
|
style.height = this.height + 'rpx';
|
||||||
|
style.width = this.height + 'rpx';
|
||||||
|
}
|
||||||
|
if(this.showBorder) {
|
||||||
|
style.borderStyle = 'solid';
|
||||||
|
style.borderColor = this.borderColor;
|
||||||
|
style.borderWidth = '1px';
|
||||||
|
}
|
||||||
|
if(this.bgColor) {
|
||||||
|
style.backgroundColor = this.bgColor;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// 倒计时数字的样式
|
||||||
|
letterStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.fontSize) style.fontSize = this.fontSize + 'rpx';
|
||||||
|
if(this.color) style.color = this.color;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
// 如果自动倒计时
|
||||||
|
this.autoplay && this.timestamp && this.start();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 倒计时
|
||||||
|
start() {
|
||||||
|
// 避免可能出现的倒计时重叠情况
|
||||||
|
this.clearTimer();
|
||||||
|
if (this.timestamp <= 0) return;
|
||||||
|
this.seconds = Number(this.timestamp);
|
||||||
|
this.formatTime(this.seconds);
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.seconds--;
|
||||||
|
// 发出change事件
|
||||||
|
this.$emit('change', this.seconds);
|
||||||
|
if (this.seconds < 0) {
|
||||||
|
return this.end();
|
||||||
|
}
|
||||||
|
this.formatTime(this.seconds);
|
||||||
|
}, 1000);
|
||||||
|
},
|
||||||
|
// 格式化时间
|
||||||
|
formatTime(seconds) {
|
||||||
|
// 小于等于0的话,结束倒计时
|
||||||
|
seconds <= 0 && this.end();
|
||||||
|
let [day, hour, minute, second] = [0, 0, 0, 0];
|
||||||
|
day = Math.floor(seconds / (60 * 60 * 24));
|
||||||
|
// 判断是否显示“天”参数,如果不显示,将天部分的值,加入到小时中
|
||||||
|
// hour为给后面计算秒和分等用的(基于显示天的前提下计算)
|
||||||
|
hour = Math.floor(seconds / (60 * 60)) - day * 24;
|
||||||
|
// showHour为需要显示的小时
|
||||||
|
let showHour = null;
|
||||||
|
if(this.showDays) {
|
||||||
|
showHour = hour;
|
||||||
|
} else {
|
||||||
|
// 如果不显示天数,将“天”部分的时间折算到小时中去
|
||||||
|
showHour = Math.floor(seconds / (60 * 60));
|
||||||
|
}
|
||||||
|
minute = Math.floor(seconds / 60) - hour * 60 - day * 24 * 60;
|
||||||
|
second = Math.floor(seconds) - day * 24 * 60 * 60 - hour * 60 * 60 - minute * 60;
|
||||||
|
// 如果小于10,在前面补上一个"0"
|
||||||
|
showHour = showHour < 10 ? '0' + showHour : showHour;
|
||||||
|
minute = minute < 10 ? '0' + minute : minute;
|
||||||
|
second = second < 10 ? '0' + second : second;
|
||||||
|
day = day < 10 ? '0' + day : day;
|
||||||
|
this.d = day;
|
||||||
|
this.h = showHour;
|
||||||
|
this.i = minute;
|
||||||
|
this.s = second;
|
||||||
|
},
|
||||||
|
// 停止倒计时
|
||||||
|
end() {
|
||||||
|
this.clearTimer();
|
||||||
|
this.$emit('end', {});
|
||||||
|
},
|
||||||
|
// 清除定时器
|
||||||
|
clearTimer() {
|
||||||
|
if(this.timer) {
|
||||||
|
// 清除定时器
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
clearInterval(this.timer);
|
||||||
|
this.timer = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-countdown {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-countdown-item {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rpx;
|
||||||
|
border-radius: 6rpx;
|
||||||
|
white-space: nowrap;
|
||||||
|
transform: translateZ(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-countdown-time {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-countdown-colon {
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 0 5rpx;
|
||||||
|
line-height: 1;
|
||||||
|
align-items: center;
|
||||||
|
padding-bottom: 4rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-countdown-scale {
|
||||||
|
transform: scale(0.9);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
241
node_modules/uview-ui/components/u-count-to/u-count-to.vue
generated
vendored
Normal file
241
node_modules/uview-ui/components/u-count-to/u-count-to.vue
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-count-num"
|
||||||
|
:style="{
|
||||||
|
fontSize: fontSize + 'rpx',
|
||||||
|
fontWeight: bold ? 'bold' : 'normal',
|
||||||
|
color: color
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
{{ displayValue }}
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* countTo 数字滚动
|
||||||
|
* @description 该组件一般用于需要滚动数字到某一个值的场景,目标要求是一个递增的值。
|
||||||
|
* @tutorial https://www.uviewui.com/components/countTo.html
|
||||||
|
* @property {String Number} start-val 开始值
|
||||||
|
* @property {String Number} end-val 结束值
|
||||||
|
* @property {String Number} duration 滚动过程所需的时间,单位ms(默认2000)
|
||||||
|
* @property {Boolean} autoplay 是否自动开始滚动(默认true)
|
||||||
|
* @property {String Number} decimals 要显示的小数位数,见官网说明(默认0)
|
||||||
|
* @property {Boolean} use-easing 滚动结束时,是否缓动结尾,见官网说明(默认true)
|
||||||
|
* @property {String} separator 千位分隔符,见官网说明
|
||||||
|
* @property {String} color 字体颜色(默认#303133)
|
||||||
|
* @property {String Number} font-size 字体大小,单位rpx(默认50)
|
||||||
|
* @property {Boolean} bold 字体是否加粗(默认false)
|
||||||
|
* @event {Function} end 数值滚动到目标值时触发
|
||||||
|
* @example <u-count-to ref="uCountTo" :end-val="endVal" :autoplay="autoplay"></u-count-to>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-count-to',
|
||||||
|
props: {
|
||||||
|
// 开始的数值,默认从0增长到某一个数
|
||||||
|
startVal: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 要滚动的目标数值,必须
|
||||||
|
endVal: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
// 滚动到目标数值的动画持续时间,单位为毫秒(ms)
|
||||||
|
duration: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 2000
|
||||||
|
},
|
||||||
|
// 设置数值后是否自动开始滚动
|
||||||
|
autoplay: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 要显示的小数位数
|
||||||
|
decimals: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否在即将到达目标数值的时候,使用缓慢滚动的效果
|
||||||
|
useEasing: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 十进制分割
|
||||||
|
decimal: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '.'
|
||||||
|
},
|
||||||
|
// 字体颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#303133'
|
||||||
|
},
|
||||||
|
// 字体大小
|
||||||
|
fontSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 50
|
||||||
|
},
|
||||||
|
// 是否加粗字体
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 千位分隔符,类似金额的分割(¥23,321.05中的",")
|
||||||
|
separator: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
localStartVal: this.startVal,
|
||||||
|
displayValue: this.formatNumber(this.startVal),
|
||||||
|
printVal: null,
|
||||||
|
paused: false, // 是否暂停
|
||||||
|
localDuration: Number(this.duration),
|
||||||
|
startTime: null, // 开始的时间
|
||||||
|
timestamp: null, // 时间戳
|
||||||
|
remaining: null, // 停留的时间
|
||||||
|
rAF: null,
|
||||||
|
lastTime: 0 // 上一次的时间
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
countDown() {
|
||||||
|
return this.startVal > this.endVal;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
startVal() {
|
||||||
|
this.autoplay && this.start();
|
||||||
|
},
|
||||||
|
endVal() {
|
||||||
|
this.autoplay && this.start();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.autoplay && this.start();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
easingFn(t, b, c, d) {
|
||||||
|
return (c * (-Math.pow(2, (-10 * t) / d) + 1) * 1024) / 1023 + b;
|
||||||
|
},
|
||||||
|
requestAnimationFrame(callback) {
|
||||||
|
const currTime = new Date().getTime();
|
||||||
|
// 为了使setTimteout的尽可能的接近每秒60帧的效果
|
||||||
|
const timeToCall = Math.max(0, 16 - (currTime - this.lastTime));
|
||||||
|
const id = setTimeout(() => {
|
||||||
|
callback(currTime + timeToCall);
|
||||||
|
}, timeToCall);
|
||||||
|
this.lastTime = currTime + timeToCall;
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelAnimationFrame(id) {
|
||||||
|
clearTimeout(id);
|
||||||
|
},
|
||||||
|
// 开始滚动数字
|
||||||
|
start() {
|
||||||
|
this.localStartVal = this.startVal;
|
||||||
|
this.startTime = null;
|
||||||
|
this.localDuration = this.duration;
|
||||||
|
this.paused = false;
|
||||||
|
this.rAF = this.requestAnimationFrame(this.count);
|
||||||
|
},
|
||||||
|
// 暂定状态,重新再开始滚动;或者滚动状态下,暂停
|
||||||
|
reStart() {
|
||||||
|
if (this.paused) {
|
||||||
|
this.resume();
|
||||||
|
this.paused = false;
|
||||||
|
} else {
|
||||||
|
this.stop();
|
||||||
|
this.paused = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 暂停
|
||||||
|
stop() {
|
||||||
|
this.cancelAnimationFrame(this.rAF);
|
||||||
|
},
|
||||||
|
// 重新开始(暂停的情况下)
|
||||||
|
resume() {
|
||||||
|
this.startTime = null;
|
||||||
|
this.localDuration = this.remaining;
|
||||||
|
this.localStartVal = this.printVal;
|
||||||
|
this.requestAnimationFrame(this.count);
|
||||||
|
},
|
||||||
|
// 重置
|
||||||
|
reset() {
|
||||||
|
this.startTime = null;
|
||||||
|
this.cancelAnimationFrame(this.rAF);
|
||||||
|
this.displayValue = this.formatNumber(this.startVal);
|
||||||
|
},
|
||||||
|
count(timestamp) {
|
||||||
|
if (!this.startTime) this.startTime = timestamp;
|
||||||
|
this.timestamp = timestamp;
|
||||||
|
const progress = timestamp - this.startTime;
|
||||||
|
this.remaining = this.localDuration - progress;
|
||||||
|
if (this.useEasing) {
|
||||||
|
if (this.countDown) {
|
||||||
|
this.printVal = this.localStartVal - this.easingFn(progress, 0, this.localStartVal - this.endVal, this.localDuration);
|
||||||
|
} else {
|
||||||
|
this.printVal = this.easingFn(progress, this.localStartVal, this.endVal - this.localStartVal, this.localDuration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.countDown) {
|
||||||
|
this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration);
|
||||||
|
} else {
|
||||||
|
this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.countDown) {
|
||||||
|
this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
|
||||||
|
} else {
|
||||||
|
this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
|
||||||
|
}
|
||||||
|
this.displayValue = this.formatNumber(this.printVal);
|
||||||
|
if (progress < this.localDuration) {
|
||||||
|
this.rAF = this.requestAnimationFrame(this.count);
|
||||||
|
} else {
|
||||||
|
this.$emit('end');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 判断是否数字
|
||||||
|
isNumber(val) {
|
||||||
|
return !isNaN(parseFloat(val));
|
||||||
|
},
|
||||||
|
formatNumber(num) {
|
||||||
|
// 将num转为Number类型,因为其值可能为字符串数值,调用toFixed会报错
|
||||||
|
num = Number(num);
|
||||||
|
num = num.toFixed(Number(this.decimals));
|
||||||
|
num += '';
|
||||||
|
const x = num.split('.');
|
||||||
|
let x1 = x[0];
|
||||||
|
const x2 = x.length > 1 ? this.decimal + x[1] : '';
|
||||||
|
const rgx = /(\d+)(\d{3})/;
|
||||||
|
if (this.separator && !this.isNumber(this.separator)) {
|
||||||
|
while (rgx.test(x1)) {
|
||||||
|
x1 = x1.replace(rgx, '$1' + this.separator + '$2');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return x1 + x2;
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.cancelAnimationFrame(this.rAF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-count-num {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
153
node_modules/uview-ui/components/u-divider/u-divider.vue
generated
vendored
Normal file
153
node_modules/uview-ui/components/u-divider/u-divider.vue
generated
vendored
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-divider" :style="{
|
||||||
|
height: height == 'auto' ? 'auto' : height + 'rpx',
|
||||||
|
backgroundColor: bgColor,
|
||||||
|
marginBottom: marginBottom + 'rpx',
|
||||||
|
marginTop: marginTop + 'rpx'
|
||||||
|
}" @tap="click">
|
||||||
|
<view class="u-divider-line" :class="[type ? 'u-divider-line--bordercolor--' + type : '']" :style="[lineStyle]"></view>
|
||||||
|
<view v-if="useSlot" class="u-divider-text" :style="{
|
||||||
|
color: color,
|
||||||
|
fontSize: fontSize + 'rpx'
|
||||||
|
}"><slot /></view>
|
||||||
|
<view class="u-divider-line" :class="[type ? 'u-divider-line--bordercolor--' + type : '']" :style="[lineStyle]"></view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* divider 分割线
|
||||||
|
* @description 区隔内容的分割线,一般用于页面底部"没有更多"的提示。
|
||||||
|
* @tutorial https://www.uviewui.com/components/divider.html
|
||||||
|
* @property {String Number} half-width 文字左或右边线条宽度,数值或百分比,数值时单位为rpx
|
||||||
|
* @property {String} border-color 线条颜色,优先级高于type(默认#dcdfe6)
|
||||||
|
* @property {String} color 文字颜色(默认#909399)
|
||||||
|
* @property {String Number} fontSize 字体大小,单位rpx(默认26)
|
||||||
|
* @property {String} bg-color 整个divider的背景颜色(默认呢#ffffff)
|
||||||
|
* @property {String Number} height 整个divider的高度,单位rpx(默认40)
|
||||||
|
* @property {String} type 将线条设置主题色(默认primary)
|
||||||
|
* @property {Boolean} useSlot 是否使用slot传入内容,如果不传入,中间不会有空隙(默认true)
|
||||||
|
* @property {String Number} margin-top 与前一个组件的距离,单位rpx(默认0)
|
||||||
|
* @property {String Number} margin-bottom 与后一个组件的距离,单位rpx(0)
|
||||||
|
* @event {Function} click divider组件被点击时触发
|
||||||
|
* @example <u-divider color="#fa3534">长河落日圆</u-divider>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-divider',
|
||||||
|
props: {
|
||||||
|
// 单一边divider横线的宽度(数值),单位rpx。或者百分比
|
||||||
|
halfWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 150
|
||||||
|
},
|
||||||
|
// divider横线的颜色,如设置,
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#dcdfe6'
|
||||||
|
},
|
||||||
|
// 主题色,可以是primary|info|success|warning|error之一值
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'primary'
|
||||||
|
},
|
||||||
|
// 文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#909399'
|
||||||
|
},
|
||||||
|
// 文字大小,单位rpx
|
||||||
|
fontSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 26
|
||||||
|
},
|
||||||
|
// 整个divider的背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
},
|
||||||
|
// 整个divider的高度单位rpx
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
// 上边距
|
||||||
|
marginTop: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 下边距
|
||||||
|
marginBottom: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否使用slot传入内容,如果不用slot传入内容,先的中间就不会有空隙
|
||||||
|
useSlot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
lineStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(String(this.halfWidth).indexOf('%') != -1) style.width = this.halfWidth;
|
||||||
|
else style.width = this.halfWidth + 'rpx';
|
||||||
|
// borderColor优先级高于type值
|
||||||
|
if(this.borderColor) style.borderColor = this.borderColor;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
.u-divider {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-divider-line {
|
||||||
|
border-bottom: 1px solid $u-border-color;
|
||||||
|
transform: scale(1, 0.5);
|
||||||
|
transform-origin: center;
|
||||||
|
|
||||||
|
&--bordercolor--primary {
|
||||||
|
border-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bordercolor--success {
|
||||||
|
border-color: $u-type-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bordercolor--error {
|
||||||
|
border-color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bordercolor--info {
|
||||||
|
border-color: $u-type-info;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bordercolor--warning {
|
||||||
|
border-color: $u-type-warning;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-divider-text {
|
||||||
|
white-space: nowrap;
|
||||||
|
padding: 0 16rpx;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
132
node_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue
generated
vendored
Normal file
132
node_modules/uview-ui/components/u-dropdown-item/u-dropdown-item.vue
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-dropdown-item" v-if="active" @touchmove.stop.prevent="() => {}" @tap.stop.prevent="() => {}">
|
||||||
|
<block v-if="!$slots.default && !$slots.$default">
|
||||||
|
<scroll-view scroll-y="true" :style="{
|
||||||
|
height: $u.addUnit(height)
|
||||||
|
}">
|
||||||
|
<view class="u-dropdown-item__options">
|
||||||
|
<u-cell-group>
|
||||||
|
<u-cell-item @click="cellClick(item.value)" :arrow="false" :title="item.label" v-for="(item, index) in options"
|
||||||
|
:key="index" :title-style="{
|
||||||
|
color: value == item.value ? activeColor : inactiveColor
|
||||||
|
}">
|
||||||
|
<u-icon v-if="value == item.value" name="checkbox-mark" :color="activeColor" size="32"></u-icon>
|
||||||
|
</u-cell-item>
|
||||||
|
</u-cell-group>
|
||||||
|
</view>
|
||||||
|
</scroll-view>
|
||||||
|
</block>
|
||||||
|
<slot v-else />
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* dropdown-item 下拉菜单
|
||||||
|
* @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
|
||||||
|
* @tutorial http://uviewui.com/components/dropdown.html
|
||||||
|
* @property {String | Number} v-model 双向绑定选项卡选择值
|
||||||
|
* @property {String} title 菜单项标题
|
||||||
|
* @property {Array[Object]} options 选项数据,如果传入了默认slot,此参数无效
|
||||||
|
* @property {Boolean} disabled 是否禁用此选项卡(默认false)
|
||||||
|
* @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
|
||||||
|
* @property {String | Number} height 弹窗下拉内容的高度(内容超出将会滚动)(默认auto)
|
||||||
|
* @example <u-dropdown-item title="标题"></u-dropdown-item>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-dropdown-item',
|
||||||
|
props: {
|
||||||
|
// 当前选中项的value值
|
||||||
|
value: {
|
||||||
|
type: [Number, String, Array],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 菜单项标题
|
||||||
|
title: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 选项数据,如果传入了默认slot,此参数无效
|
||||||
|
options: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否禁用此菜单项
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 下拉弹窗的高度
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
active: false, // 当前项是否处于展开状态
|
||||||
|
activeColor: '#2979ff', // 激活时左边文字和右边对勾图标的颜色
|
||||||
|
inactiveColor: '#606266', // 未激活时左边文字和右边对勾图标的颜色
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 监听props是否发生了变化,有些值需要传递给父组件u-dropdown,无法双向绑定
|
||||||
|
propsChange() {
|
||||||
|
return `${this.title}-${this.disabled}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
propsChange(n) {
|
||||||
|
// 当值变化时,通知父组件重新初始化,让父组件执行每个子组件的init()方法
|
||||||
|
// 将所有子组件数据重新整理一遍
|
||||||
|
if (this.parent) this.parent.init();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 父组件的实例
|
||||||
|
this.parent = false;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// 获取父组件u-dropdown
|
||||||
|
let parent = this.$u.$parent.call(this, 'u-dropdown');
|
||||||
|
if (parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
// 将子组件的激活颜色配置为父组件设置的激活和未激活时的颜色
|
||||||
|
this.activeColor = parent.activeColor;
|
||||||
|
this.inactiveColor = parent.inactiveColor;
|
||||||
|
// 将本组件的this,放入到父组件的children数组中,让父组件可以操作本(子)组件的方法和属性
|
||||||
|
// push进去前,显判断是否已经存在了本实例,因为在子组件内部数据变化时,会通过父组件重新初始化子组件
|
||||||
|
let exist = parent.children.find(val => {
|
||||||
|
return this === val;
|
||||||
|
})
|
||||||
|
if (!exist) parent.children.push(this);
|
||||||
|
if (parent.children.length == 1) this.active = true;
|
||||||
|
// 父组件无法监听children的变化,故将子组件的title,传入父组件的menuList数组中
|
||||||
|
parent.menuList.push({
|
||||||
|
title: this.title,
|
||||||
|
disabled: this.disabled
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// cell被点击
|
||||||
|
cellClick(value) {
|
||||||
|
// 修改通过v-model绑定的值
|
||||||
|
this.$emit('input', value);
|
||||||
|
// 通知父组件(u-dropdown)收起菜单
|
||||||
|
this.parent.close();
|
||||||
|
// 发出事件,抛出当前勾选项的value
|
||||||
|
this.$emit('change', value);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
</style>
|
||||||
298
node_modules/uview-ui/components/u-dropdown/u-dropdown.vue
generated
vendored
Normal file
298
node_modules/uview-ui/components/u-dropdown/u-dropdown.vue
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-dropdown">
|
||||||
|
<view class="u-dropdown__menu" :style="{
|
||||||
|
height: $u.addUnit(height)
|
||||||
|
}" :class="{
|
||||||
|
'u-border-bottom': borderBottom
|
||||||
|
}">
|
||||||
|
<view class="u-dropdown__menu__item" v-for="(item, index) in menuList" :key="index" @tap.stop="menuClick(index)">
|
||||||
|
<view class="u-flex">
|
||||||
|
<text class="u-dropdown__menu__item__text" :style="{
|
||||||
|
color: item.disabled ? '#c0c4cc' : (index === current || highlightIndex == index) ? activeColor : inactiveColor,
|
||||||
|
fontSize: $u.addUnit(titleSize)
|
||||||
|
}">{{item.title}}</text>
|
||||||
|
<view class="u-dropdown__menu__item__arrow" :class="{
|
||||||
|
'u-dropdown__menu__item__arrow--rotate': index === current
|
||||||
|
}">
|
||||||
|
<u-icon :custom-style="{display: 'flex'}" :name="menuIcon" :size="$u.addUnit(menuIconSize)" :color="index === current || highlightIndex == index ? activeColor : '#c0c4cc'"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-dropdown__content" :style="[contentStyle, {
|
||||||
|
transition: `opacity ${duration / 1000}s linear`,
|
||||||
|
top: $u.addUnit(height),
|
||||||
|
height: contentHeight + 'px'
|
||||||
|
}]"
|
||||||
|
@tap="maskClick" @touchmove.stop.prevent>
|
||||||
|
<view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]">
|
||||||
|
<slot></slot>
|
||||||
|
</view>
|
||||||
|
<view class="u-dropdown__content__mask"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* dropdown 下拉菜单
|
||||||
|
* @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
|
||||||
|
* @tutorial http://uviewui.com/components/dropdown.html
|
||||||
|
* @property {String} active-color 标题和选项卡选中的颜色(默认#2979ff)
|
||||||
|
* @property {String} inactive-color 标题和选项卡未选中的颜色(默认#606266)
|
||||||
|
* @property {Boolean} close-on-click-mask 点击遮罩是否关闭菜单(默认true)
|
||||||
|
* @property {Boolean} close-on-click-self 点击当前激活项标题是否关闭菜单(默认true)
|
||||||
|
* @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
|
||||||
|
* @property {String | Number} height 标题菜单的高度,单位任意(默认80)
|
||||||
|
* @property {String | Number} border-radius 菜单展开内容下方的圆角值,单位任意(默认0)
|
||||||
|
* @property {Boolean} border-bottom 标题菜单是否显示下边框(默认false)
|
||||||
|
* @property {String | Number} title-size 标题的字体大小,单位任意,数值默认为rpx单位(默认28)
|
||||||
|
* @event {Function} open 下拉菜单被打开时触发
|
||||||
|
* @event {Function} close 下拉菜单被关闭时触发
|
||||||
|
* @example <u-dropdown></u-dropdown>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-dropdown',
|
||||||
|
props: {
|
||||||
|
// 菜单标题和选项的激活态颜色
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
},
|
||||||
|
// 菜单标题和选项的未激活态颜色
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#606266'
|
||||||
|
},
|
||||||
|
// 点击遮罩是否关闭菜单
|
||||||
|
closeOnClickMask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 点击当前激活项标题是否关闭菜单
|
||||||
|
closeOnClickSelf: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 过渡时间
|
||||||
|
duration: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 300
|
||||||
|
},
|
||||||
|
// 标题菜单的高度,单位任意,数值默认为rpx单位
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 80
|
||||||
|
},
|
||||||
|
// 是否显示下边框
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 标题的字体大小
|
||||||
|
titleSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 28
|
||||||
|
},
|
||||||
|
// 下拉出来的内容部分的圆角值
|
||||||
|
borderRadius: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 菜单右侧的icon图标
|
||||||
|
menuIcon: {
|
||||||
|
type: String,
|
||||||
|
default: 'arrow-down'
|
||||||
|
},
|
||||||
|
// 菜单右侧图标的大小
|
||||||
|
menuIconSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 26
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
showDropdown: true, // 是否打开下来菜单,
|
||||||
|
menuList: [], // 显示的菜单
|
||||||
|
active: false, // 下拉菜单的状态
|
||||||
|
// 当前是第几个菜单处于激活状态,小程序中此处不能写成false或者"",否则后续将current赋值为0,
|
||||||
|
// 无能的TX没有使用===而是使用==判断,导致程序认为前后二者没有变化,从而不会触发视图更新
|
||||||
|
current: 99999,
|
||||||
|
// 外层内容的样式,初始时处于底层,且透明
|
||||||
|
contentStyle: {
|
||||||
|
zIndex: -1,
|
||||||
|
opacity: 0
|
||||||
|
},
|
||||||
|
// 让某个菜单保持高亮的状态
|
||||||
|
highlightIndex: 99999,
|
||||||
|
contentHeight: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 下拉出来部分的样式
|
||||||
|
popupStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 进行Y轴位移,展开状态时,恢复原位。收齐状态时,往上位移100%,进行隐藏
|
||||||
|
style.transform = `translateY(${this.active ? 0 : '-100%'})`
|
||||||
|
style['transition-duration'] = this.duration / 1000 + 's';
|
||||||
|
style.borderRadius = `0 0 ${this.$u.addUnit(this.borderRadius)} ${this.$u.addUnit(this.borderRadius)}`;
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 引用所有子组件(u-dropdown-item)的this,不能在data中声明变量,否则在微信小程序会造成循环引用而报错
|
||||||
|
this.children = [];
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getContentHeight();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
init() {
|
||||||
|
// 当某个子组件内容变化时,触发父组件的init,父组件再让每一个子组件重新初始化一遍
|
||||||
|
// 以保证数据的正确性
|
||||||
|
this.menuList = [];
|
||||||
|
this.children.map(child => {
|
||||||
|
child.init();
|
||||||
|
})
|
||||||
|
},
|
||||||
|
// 点击菜单
|
||||||
|
menuClick(index) {
|
||||||
|
// 判断是否被禁用
|
||||||
|
if (this.menuList[index].disabled) return;
|
||||||
|
// 如果点击时的索引和当前激活项索引相同,意味着点击了激活项,需要收起下拉菜单
|
||||||
|
if (index === this.current && this.closeOnClickSelf) {
|
||||||
|
this.close();
|
||||||
|
// 等动画结束后,再移除下拉菜单中的内容,否则直接移除,也就没有下拉菜单收起的效果了
|
||||||
|
setTimeout(() => {
|
||||||
|
this.children[index].active = false;
|
||||||
|
}, this.duration)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.open(index);
|
||||||
|
},
|
||||||
|
// 打开下拉菜单
|
||||||
|
open(index) {
|
||||||
|
// 重置高亮索引,否则会造成多个菜单同时高亮
|
||||||
|
// this.highlightIndex = 9999;
|
||||||
|
// 展开时,设置下拉内容的样式
|
||||||
|
this.contentStyle = {
|
||||||
|
zIndex: 11,
|
||||||
|
}
|
||||||
|
// 标记展开状态以及当前展开项的索引
|
||||||
|
this.active = true;
|
||||||
|
this.current = index;
|
||||||
|
// 历遍所有的子元素,将索引匹配的项标记为激活状态,因为子元素是通过v-if控制切换的
|
||||||
|
// 之所以不是因display: none,是因为nvue没有display这个属性
|
||||||
|
this.children.map((val, idx) => {
|
||||||
|
val.active = index == idx ? true : false;
|
||||||
|
})
|
||||||
|
this.$emit('open', this.current);
|
||||||
|
},
|
||||||
|
// 设置下拉菜单处于收起状态
|
||||||
|
close() {
|
||||||
|
this.$emit('close', this.current);
|
||||||
|
// 设置为收起状态,同时current归位,设置为空字符串
|
||||||
|
this.active = false;
|
||||||
|
this.current = 99999;
|
||||||
|
// 下拉内容的样式进行调整,不透明度设置为0
|
||||||
|
this.contentStyle = {
|
||||||
|
zIndex: -1,
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 点击遮罩
|
||||||
|
maskClick() {
|
||||||
|
// 如果不允许点击遮罩,直接返回
|
||||||
|
if (!this.closeOnClickMask) return;
|
||||||
|
this.close();
|
||||||
|
},
|
||||||
|
// 外部手动设置某个菜单高亮
|
||||||
|
highlight(index = undefined) {
|
||||||
|
this.highlightIndex = index !== undefined ? index : 99999;
|
||||||
|
},
|
||||||
|
// 获取下拉菜单内容的高度
|
||||||
|
getContentHeight() {
|
||||||
|
// 这里的原理为,因为dropdown组件是相对定位的,它的下拉出来的内容,必须给定一个高度
|
||||||
|
// 才能让遮罩占满菜单一下,直到屏幕底部的高度
|
||||||
|
// this.$u.sys()为uView封装的获取设备信息的方法
|
||||||
|
let windowHeight = this.$u.sys().windowHeight;
|
||||||
|
this.$uGetRect('.u-dropdown__menu').then(res => {
|
||||||
|
// 这里获取的是dropdown的尺寸,在H5上,uniapp获取尺寸是有bug的(以前提出修复过,后来又出现了此bug,目前hx2.8.11版本)
|
||||||
|
// H5端bug表现为元素尺寸的top值为导航栏底部到到元素的上边沿的距离,但是元素的bottom值确是导航栏顶部到元素底部的距离
|
||||||
|
// 二者是互相矛盾的,本质原因是H5端导航栏非原生,uni的开发者大意造成
|
||||||
|
// 这里取菜单栏的botton值合理的,不能用res.top,否则页面会造成滚动
|
||||||
|
this.contentHeight = windowHeight - res.bottom;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-dropdown {
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&__menu {
|
||||||
|
@include vue-flex;
|
||||||
|
position: relative;
|
||||||
|
z-index: 11;
|
||||||
|
height: 80rpx;
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
flex: 1;
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__arrow {
|
||||||
|
margin-left: 6rpx;
|
||||||
|
transition: transform .3s;
|
||||||
|
align-items: center;
|
||||||
|
@include vue-flex;
|
||||||
|
|
||||||
|
&--rotate {
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 8;
|
||||||
|
width: 100%;
|
||||||
|
left: 0px;
|
||||||
|
bottom: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
|
||||||
|
&__mask {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9;
|
||||||
|
background: rgba(0, 0, 0, .3);
|
||||||
|
width: 100%;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__popup {
|
||||||
|
position: relative;
|
||||||
|
z-index: 10;
|
||||||
|
transition: all 0.3s;
|
||||||
|
transform: translate3D(0, -100%, 0);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
||||||
193
node_modules/uview-ui/components/u-empty/u-empty.vue
generated
vendored
Normal file
193
node_modules/uview-ui/components/u-empty/u-empty.vue
generated
vendored
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-empty" v-if="show" :style="{
|
||||||
|
marginTop: marginTop + 'rpx'
|
||||||
|
}">
|
||||||
|
<u-icon
|
||||||
|
:name="src ? src : 'empty-' + mode"
|
||||||
|
:custom-style="iconStyle"
|
||||||
|
:label="text ? text : icons[mode]"
|
||||||
|
label-pos="bottom"
|
||||||
|
:label-color="color"
|
||||||
|
:label-size="fontSize"
|
||||||
|
:size="iconSize"
|
||||||
|
:color="iconColor"
|
||||||
|
margin-top="14"
|
||||||
|
></u-icon>
|
||||||
|
<view class="u-slot-wrap">
|
||||||
|
<slot name="bottom"></slot>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* empty 内容为空
|
||||||
|
* @description 该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景, 我们精心挑选了十几个场景的图标,方便您使用。
|
||||||
|
* @tutorial https://www.uviewui.com/components/empty.html
|
||||||
|
* @property {String} color 文字颜色(默认#c0c4cc)
|
||||||
|
* @property {String} text 文字提示(默认“无内容”)
|
||||||
|
* @property {String} src 自定义图标路径,如定义,mode参数会失效
|
||||||
|
* @property {String Number} font-size 提示文字的大小,单位rpx(默认28)
|
||||||
|
* @property {String} mode 内置的图标,见官网说明(默认data)
|
||||||
|
* @property {String Number} img-width 图标的宽度,单位rpx(默认240)
|
||||||
|
* @property {String} img-height 图标的高度,单位rpx(默认auto)
|
||||||
|
* @property {String Number} margin-top 组件距离上一个元素之间的距离(默认0)
|
||||||
|
* @property {Boolean} show 是否显示组件(默认true)
|
||||||
|
* @event {Function} click 点击组件时触发
|
||||||
|
* @event {Function} close 点击关闭按钮时触发
|
||||||
|
* @example <u-empty text="所谓伊人,在水一方" mode="list"></u-empty>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-empty",
|
||||||
|
props: {
|
||||||
|
// 图标路径
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 提示文字
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 文字颜色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: '#c0c4cc'
|
||||||
|
},
|
||||||
|
// 图标的颜色
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#c0c4cc'
|
||||||
|
},
|
||||||
|
// 图标的大小
|
||||||
|
iconSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 120
|
||||||
|
},
|
||||||
|
// 文字大小,单位rpx
|
||||||
|
fontSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 26
|
||||||
|
},
|
||||||
|
// 选择预置的图标类型
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'data'
|
||||||
|
},
|
||||||
|
// 图标宽度,单位rpx
|
||||||
|
imgWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 120
|
||||||
|
},
|
||||||
|
// 图标高度,单位rpx
|
||||||
|
imgHeight: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
// 是否显示组件
|
||||||
|
show: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 组件距离上一个元素之间的距离
|
||||||
|
marginTop: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
icons: {
|
||||||
|
car: '购物车为空',
|
||||||
|
page: '页面不存在',
|
||||||
|
search: '没有搜索结果',
|
||||||
|
address: '没有收货地址',
|
||||||
|
wifi: '没有WiFi',
|
||||||
|
order: '订单为空',
|
||||||
|
coupon: '没有优惠券',
|
||||||
|
favor: '暂无收藏',
|
||||||
|
permission: '无权限',
|
||||||
|
history: '无历史记录',
|
||||||
|
news: '无新闻列表',
|
||||||
|
message: '消息列表为空',
|
||||||
|
list: '列表为空',
|
||||||
|
data: '数据为空'
|
||||||
|
},
|
||||||
|
// icons: [{
|
||||||
|
// icon: 'car',
|
||||||
|
// text: '购物车为空'
|
||||||
|
// },{
|
||||||
|
// icon: 'page',
|
||||||
|
// text: '页面不存在'
|
||||||
|
// },{
|
||||||
|
// icon: 'search',
|
||||||
|
// text: '没有搜索结果'
|
||||||
|
// },{
|
||||||
|
// icon: 'address',
|
||||||
|
// text: '没有收货地址'
|
||||||
|
// },{
|
||||||
|
// icon: 'wifi',
|
||||||
|
// text: '没有WiFi'
|
||||||
|
// },{
|
||||||
|
// icon: 'order',
|
||||||
|
// text: '订单为空'
|
||||||
|
// },{
|
||||||
|
// icon: 'coupon',
|
||||||
|
// text: '没有优惠券'
|
||||||
|
// },{
|
||||||
|
// icon: 'favor',
|
||||||
|
// text: '暂无收藏'
|
||||||
|
// },{
|
||||||
|
// icon: 'permission',
|
||||||
|
// text: '无权限'
|
||||||
|
// },{
|
||||||
|
// icon: 'history',
|
||||||
|
// text: '无历史记录'
|
||||||
|
// },{
|
||||||
|
// icon: 'news',
|
||||||
|
// text: '无新闻列表'
|
||||||
|
// },{
|
||||||
|
// icon: 'message',
|
||||||
|
// text: '消息列表为空'
|
||||||
|
// },{
|
||||||
|
// icon: 'list',
|
||||||
|
// text: '列表为空'
|
||||||
|
// },{
|
||||||
|
// icon: 'data',
|
||||||
|
// text: '数据为空'
|
||||||
|
// }],
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-empty {
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-image {
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-slot-wrap {
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 20rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
384
node_modules/uview-ui/components/u-field/u-field.vue
generated
vendored
Normal file
384
node_modules/uview-ui/components/u-field/u-field.vue
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-field" :class="{'u-border-top': borderTop, 'u-border-bottom': borderBottom }">
|
||||||
|
<view class="u-field-inner" :class="[type == 'textarea' ? 'u-textarea-inner' : '', 'u-label-postion-' + labelPosition]">
|
||||||
|
<view class="u-label" :class="[required ? 'u-required' : '']" :style="{
|
||||||
|
justifyContent: justifyContent,
|
||||||
|
flex: labelPosition == 'left' ? `0 0 ${labelWidth}rpx` : '1'
|
||||||
|
}">
|
||||||
|
<view class="u-icon-wrap" v-if="icon">
|
||||||
|
<u-icon size="32" :custom-style="iconStyle" :name="icon" :color="iconColor" class="u-icon"></u-icon>
|
||||||
|
</view>
|
||||||
|
<slot name="icon"></slot>
|
||||||
|
<text class="u-label-text" :class="[this.$slots.icon || icon ? 'u-label-left-gap' : '']">{{ label }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="fild-body">
|
||||||
|
<view class="u-flex-1 u-flex" :style="[inputWrapStyle]">
|
||||||
|
<textarea v-if="type == 'textarea'" class="u-flex-1 u-textarea-class" :style="[fieldStyle]" :value="value"
|
||||||
|
:placeholder="placeholder" :placeholderStyle="placeholderStyle" :disabled="disabled" :maxlength="inputMaxlength"
|
||||||
|
:focus="focus" :autoHeight="autoHeight" :fixed="fixed" @input="onInput" @blur="onBlur" @focus="onFocus" @confirm="onConfirm"
|
||||||
|
@tap="fieldClick" />
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
:style="[fieldStyle]"
|
||||||
|
:type="type"
|
||||||
|
class="u-flex-1 u-field__input-wrap"
|
||||||
|
:value="value"
|
||||||
|
:password="password || this.type === 'password'"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:placeholderStyle="placeholderStyle"
|
||||||
|
:disabled="disabled"
|
||||||
|
:maxlength="inputMaxlength"
|
||||||
|
:focus="focus"
|
||||||
|
:confirmType="confirmType"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="onBlur"
|
||||||
|
@input="onInput"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
@tap="fieldClick"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
<u-icon :size="clearSize" v-if="clearable && value != '' && focused" name="close-circle-fill" color="#c0c4cc" class="u-clear-icon" @click="onClear"/>
|
||||||
|
<view class="u-button-wrap"><slot name="right" /></view>
|
||||||
|
<u-icon v-if="rightIcon" @click="rightIconClick" :name="rightIcon" color="#c0c4cc" :style="[rightIconStyle]" size="26" class="u-arror-right" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view v-if="errorMessage !== false && errorMessage != ''" class="u-error-message" :style="{
|
||||||
|
paddingLeft: labelWidth + 'rpx'
|
||||||
|
}">{{ errorMessage }}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* field 输入框
|
||||||
|
* @description 借助此组件,可以实现表单的输入, 有"text"和"textarea"类型的,此外,借助uView的picker和actionSheet组件可以快速实现上拉菜单,时间,地区选择等, 为表单解决方案的利器。
|
||||||
|
* @tutorial https://www.uviewui.com/components/field.html
|
||||||
|
* @property {String} type 输入框的类型(默认text)
|
||||||
|
* @property {String} icon label左边的图标,限uView的图标名称
|
||||||
|
* @property {Object} icon-style 左边图标的样式,对象形式
|
||||||
|
* @property {Boolean} right-icon 输入框右边的图标名称,限uView的图标名称(默认false)
|
||||||
|
* @property {Boolean} required 是否必填,左边您显示红色"*"号(默认false)
|
||||||
|
* @property {String} label 输入框左边的文字提示
|
||||||
|
* @property {Boolean} password 是否密码输入方式(用点替换文字),type为text时有效(默认false)
|
||||||
|
* @property {Boolean} clearable 是否显示右侧清空内容的图标控件(输入框有内容,且获得焦点时才显示),点击可清空输入框内容(默认true)
|
||||||
|
* @property {Number String} label-width label的宽度,单位rpx(默认130)
|
||||||
|
* @property {String} label-align label的文字对齐方式(默认left)
|
||||||
|
* @property {Object} field-style 自定义输入框的样式,对象形式
|
||||||
|
* @property {Number | String} clear-size 清除图标的大小,单位rpx(默认30)
|
||||||
|
* @property {String} input-align 输入框内容对齐方式(默认left)
|
||||||
|
* @property {Boolean} border-bottom 是否显示field的下边框(默认true)
|
||||||
|
* @property {Boolean} border-top 是否显示field的上边框(默认false)
|
||||||
|
* @property {String} icon-color 左边通过icon配置的图标的颜色(默认#606266)
|
||||||
|
* @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true)
|
||||||
|
* @property {String Boolean} error-message 显示的错误提示内容,如果为空字符串或者false,则不显示错误信息
|
||||||
|
* @property {String} placeholder 输入框的提示文字
|
||||||
|
* @property {String} placeholder-style placeholder的样式(内联样式,字符串),如"color: #ddd"
|
||||||
|
* @property {Boolean} focus 是否自动获得焦点(默认false)
|
||||||
|
* @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false)
|
||||||
|
* @property {Boolean} disabled 是否不可输入(默认false)
|
||||||
|
* @property {Number String} maxlength 最大输入长度,设置为 -1 的时候不限制最大长度(默认140)
|
||||||
|
* @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type="text"时生效(默认done)
|
||||||
|
* @event {Function} input 输入框内容发生变化时触发
|
||||||
|
* @event {Function} focus 输入框获得焦点时触发
|
||||||
|
* @event {Function} blur 输入框失去焦点时触发
|
||||||
|
* @event {Function} confirm 点击完成按钮时触发
|
||||||
|
* @event {Function} right-icon-click 通过right-icon生成的图标被点击时触发
|
||||||
|
* @event {Function} click 输入框被点击或者通过right-icon生成的图标被点击时触发,这样设计是考虑到传递右边的图标,一般都为需要弹出"picker"等操作时的场景,点击倒三角图标,理应发出此事件,见上方说明
|
||||||
|
* @example <u-field v-model="mobile" label="手机号" required :error-message="errorMessage"></u-field>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name:"u-field",
|
||||||
|
props: {
|
||||||
|
icon: String,
|
||||||
|
rightIcon: String,
|
||||||
|
// arrowDirection: {
|
||||||
|
// type: String,
|
||||||
|
// default: 'right'
|
||||||
|
// },
|
||||||
|
required: Boolean,
|
||||||
|
label: String,
|
||||||
|
password: Boolean,
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 左边标题的宽度单位rpx
|
||||||
|
labelWidth: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 130
|
||||||
|
},
|
||||||
|
// 对齐方式,left|center|right
|
||||||
|
labelAlign: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
inputAlign: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
iconColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#606266'
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
errorMessage: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
placeholder: String,
|
||||||
|
placeholderStyle: String,
|
||||||
|
focus: Boolean,
|
||||||
|
fixed: Boolean,
|
||||||
|
value: [Number, String],
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 140
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String,
|
||||||
|
default: 'done'
|
||||||
|
},
|
||||||
|
// lable的位置,可选为 left-左边,top-上边
|
||||||
|
labelPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// 输入框的自定义样式
|
||||||
|
fieldStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 清除按钮的大小
|
||||||
|
clearSize: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
// lable左边的图标样式,对象形式
|
||||||
|
iconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否显示上边框
|
||||||
|
borderTop: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示下边框
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否自动去除两端的空格
|
||||||
|
trim: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
focused: false,
|
||||||
|
itemIndex: 0,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
inputWrapStyle() {
|
||||||
|
let style = {};
|
||||||
|
style.textAlign = this.inputAlign;
|
||||||
|
// 判断lable的位置,如果是left的话,让input左边两边有间隙
|
||||||
|
if(this.labelPosition == 'left') {
|
||||||
|
style.margin = `0 8rpx`;
|
||||||
|
} else {
|
||||||
|
// 如果lable是top的,input的左边就没必要有间隙了
|
||||||
|
style.marginRight = `8rpx`;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
rightIconStyle() {
|
||||||
|
let style = {};
|
||||||
|
if (this.arrowDirection == 'top') style.transform = 'roate(-90deg)';
|
||||||
|
if (this.arrowDirection == 'bottom') style.transform = 'roate(90deg)';
|
||||||
|
else style.transform = 'roate(0deg)';
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
labelStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.labelAlign == 'left') style.justifyContent = 'flext-start';
|
||||||
|
if(this.labelAlign == 'center') style.justifyContent = 'center';
|
||||||
|
if(this.labelAlign == 'right') style.justifyContent = 'flext-end';
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
// uni不支持在computed中写style.justifyContent = 'center'的形式,故用此方法
|
||||||
|
justifyContent() {
|
||||||
|
if(this.labelAlign == 'left') return 'flex-start';
|
||||||
|
if(this.labelAlign == 'center') return 'center';
|
||||||
|
if(this.labelAlign == 'right') return 'flex-end';
|
||||||
|
},
|
||||||
|
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
|
||||||
|
inputMaxlength() {
|
||||||
|
return Number(this.maxlength)
|
||||||
|
},
|
||||||
|
// label的位置
|
||||||
|
fieldInnerStyle() {
|
||||||
|
let style = {};
|
||||||
|
if(this.labelPosition == 'left') {
|
||||||
|
style.flexDirection = 'row';
|
||||||
|
} else {
|
||||||
|
style.flexDirection = 'column';
|
||||||
|
}
|
||||||
|
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onInput(event) {
|
||||||
|
let value = event.detail.value;
|
||||||
|
// 判断是否去除空格
|
||||||
|
if(this.trim) value = this.$u.trim(value);
|
||||||
|
this.$emit('input', value);
|
||||||
|
},
|
||||||
|
onFocus(event) {
|
||||||
|
this.focused = true;
|
||||||
|
this.$emit('focus', event);
|
||||||
|
},
|
||||||
|
onBlur(event) {
|
||||||
|
// 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
|
||||||
|
// 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
|
||||||
|
setTimeout(() => {
|
||||||
|
this.focused = false;
|
||||||
|
}, 100)
|
||||||
|
this.$emit('blur', event);
|
||||||
|
},
|
||||||
|
onConfirm(e) {
|
||||||
|
this.$emit('confirm', e.detail.value);
|
||||||
|
},
|
||||||
|
onClear(event) {
|
||||||
|
this.$emit('input', '');
|
||||||
|
},
|
||||||
|
rightIconClick() {
|
||||||
|
this.$emit('right-icon-click');
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
fieldClick() {
|
||||||
|
this.$emit('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-field {
|
||||||
|
font-size: 28rpx;
|
||||||
|
padding: 20rpx 28rpx;
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
color: $u-main-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-field-inner {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-textarea-inner {
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-textarea-class {
|
||||||
|
min-height: 96rpx;
|
||||||
|
width: auto;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fild-body {
|
||||||
|
@include vue-flex;
|
||||||
|
flex: 1;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-arror-right {
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-label-text {
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-label-left-gap {
|
||||||
|
margin-left: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-label-postion-top {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-label {
|
||||||
|
width: 130rpx;
|
||||||
|
flex: 1 1 130rpx;
|
||||||
|
text-align: left;
|
||||||
|
position: relative;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-required::before {
|
||||||
|
content: '*';
|
||||||
|
position: absolute;
|
||||||
|
left: -16rpx;
|
||||||
|
font-size: 14px;
|
||||||
|
color: $u-type-error;
|
||||||
|
height: 9px;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-field__input-wrap {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
font-size: 28rpx;
|
||||||
|
height: 48rpx;
|
||||||
|
flex: 1;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-clear-icon {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-error-message {
|
||||||
|
color: $u-type-error;
|
||||||
|
font-size: 26rpx;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder-style {
|
||||||
|
color: rgb(150, 151, 153);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-input-class {
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-button-wrap {
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
431
node_modules/uview-ui/components/u-form-item/u-form-item.vue
generated
vendored
Normal file
431
node_modules/uview-ui/components/u-form-item/u-form-item.vue
generated
vendored
Normal file
@@ -0,0 +1,431 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-form-item" :class="{'u-border-bottom': elBorderBottom, 'u-form-item__border-bottom--error': validateState === 'error' && showError('border-bottom')}">
|
||||||
|
<view class="u-form-item__body" :style="{
|
||||||
|
flexDirection: elLabelPosition == 'left' ? 'row' : 'column'
|
||||||
|
}">
|
||||||
|
<!-- 微信小程序中,将一个参数设置空字符串,结果会变成字符串"true" -->
|
||||||
|
<view class="u-form-item--left" :style="{
|
||||||
|
width: uLabelWidth,
|
||||||
|
flex: `0 0 ${uLabelWidth}`,
|
||||||
|
marginBottom: elLabelPosition == 'left' ? 0 : '10rpx',
|
||||||
|
}">
|
||||||
|
<!-- 为了块对齐 -->
|
||||||
|
<view class="u-form-item--left__content" v-if="required || leftIcon || label">
|
||||||
|
<!-- nvue不支持伪元素before -->
|
||||||
|
<text v-if="required" class="u-form-item--left__content--required">*</text>
|
||||||
|
<view class="u-form-item--left__content__icon" v-if="leftIcon">
|
||||||
|
<u-icon :name="leftIcon" :custom-style="leftIconStyle"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="u-form-item--left__content__label" :style="[elLabelStyle, {
|
||||||
|
'justify-content': elLabelAlign == 'left' ? 'flex-start' : elLabelAlign == 'center' ? 'center' : 'flex-end'
|
||||||
|
}]">
|
||||||
|
{{label}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-form-item--right u-flex">
|
||||||
|
<view class="u-form-item--right__content">
|
||||||
|
<view class="u-form-item--right__content__slot ">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
<view class="u-form-item--right__content__icon u-flex" v-if="$slots.right || rightIcon">
|
||||||
|
<u-icon :custom-style="rightIconStyle" v-if="rightIcon" :name="rightIcon"></u-icon>
|
||||||
|
<slot name="right" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-form-item__message" v-if="validateState === 'error' && showError('message')" :style="{
|
||||||
|
paddingLeft: elLabelPosition == 'left' ? $u.addUnit(elLabelWidth) : '0',
|
||||||
|
}">{{validateMessage}}</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Emitter from '../../libs/util/emitter.js';
|
||||||
|
import schema from '../../libs/util/async-validator';
|
||||||
|
// 去除警告信息
|
||||||
|
schema.warning = function() {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* form-item 表单item
|
||||||
|
* @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
|
||||||
|
* @tutorial http://uviewui.com/components/form.html
|
||||||
|
* @property {String} label 左侧提示文字
|
||||||
|
* @property {Object} prop 表单域model对象的属性名,在使用 validate、resetFields 方法的情况下,该属性是必填的
|
||||||
|
* @property {Boolean} border-bottom 是否显示表单域的下划线边框
|
||||||
|
* @property {String} label-position 表单域提示文字的位置,left-左侧,top-上方
|
||||||
|
* @property {String Number} label-width 提示文字的宽度,单位rpx(默认90)
|
||||||
|
* @property {Object} label-style lable的样式,对象形式
|
||||||
|
* @property {String} label-align lable的对齐方式
|
||||||
|
* @property {String} right-icon 右侧自定义字体图标(限uView内置图标)或图片地址
|
||||||
|
* @property {String} left-icon 左侧自定义字体图标(限uView内置图标)或图片地址
|
||||||
|
* @property {Object} left-icon-style 左侧图标的样式,对象形式
|
||||||
|
* @property {Object} right-icon-style 右侧图标的样式,对象形式
|
||||||
|
* @property {Boolean} required 是否显示左边的"*"号,这里仅起展示作用,如需校验必填,请通过rules配置必填规则(默认false)
|
||||||
|
* @example <u-form-item label="姓名"><u-input v-model="form.name" /></u-form-item>
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'u-form-item',
|
||||||
|
mixins: [Emitter],
|
||||||
|
inject: {
|
||||||
|
uForm: {
|
||||||
|
default () {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
// input的label提示语
|
||||||
|
label: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 绑定的值
|
||||||
|
prop: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示表单域的下划线边框
|
||||||
|
borderBottom: {
|
||||||
|
type: [String, Boolean],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// label的位置,left-左边,top-上边
|
||||||
|
labelPosition: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// label的宽度,单位rpx
|
||||||
|
labelWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// lable的样式,对象形式
|
||||||
|
labelStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// lable字体的对齐方式
|
||||||
|
labelAlign: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 右侧图标
|
||||||
|
rightIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 左侧图标
|
||||||
|
leftIcon: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 左侧图标的样式
|
||||||
|
leftIconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 左侧图标的样式
|
||||||
|
rightIconStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否显示左边的必填星号,只作显示用,具体校验必填的逻辑,请在rules中配置
|
||||||
|
required: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
initialValue: '', // 存储的默认值
|
||||||
|
// isRequired: false, // 是否必填,由于人性化考虑,必填"*"号通过props的required配置,不再通过rules的规则自动生成
|
||||||
|
validateState: '', // 是否校验成功
|
||||||
|
validateMessage: '', // 校验失败的提示语
|
||||||
|
// 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色,
|
||||||
|
errorType: ['message'],
|
||||||
|
fieldValue: '', // 获取当前子组件input的输入的值
|
||||||
|
// 父组件的参数,在computed计算中,无法得知this.parent发生变化,故将父组件的参数值,放到data中
|
||||||
|
parentData: {
|
||||||
|
borderBottom: true,
|
||||||
|
labelWidth: 90,
|
||||||
|
labelPosition: 'left',
|
||||||
|
labelStyle: {},
|
||||||
|
labelAlign: 'left',
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
validateState(val) {
|
||||||
|
this.broadcastInputError();
|
||||||
|
},
|
||||||
|
// 监听u-form组件的errorType的变化
|
||||||
|
"uForm.errorType"(val) {
|
||||||
|
this.errorType = val;
|
||||||
|
this.broadcastInputError();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 计算后的label宽度,由于需要多个判断,故放到computed中
|
||||||
|
uLabelWidth() {
|
||||||
|
// 如果用户设置label为空字符串(微信小程序空字符串最终会变成字符串的'true'),意味着要将label的位置宽度设置为auto
|
||||||
|
return this.elLabelPosition == 'left' ? (this.label === 'true' || this.label === '' ? 'auto' : this.$u.addUnit(this
|
||||||
|
.elLabelWidth)) : '100%';
|
||||||
|
},
|
||||||
|
showError() {
|
||||||
|
return type => {
|
||||||
|
// 如果errorType数组中含有none,或者toast提示类型
|
||||||
|
if (this.errorType.indexOf('none') >= 0) return false;
|
||||||
|
else if (this.errorType.indexOf(type) >= 0) return true;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// label的宽度
|
||||||
|
elLabelWidth() {
|
||||||
|
// label默认宽度为90,优先使用本组件的值,如果没有(如果设置为0,也算是配置了值,依然起效),则用u-form的值
|
||||||
|
return (this.labelWidth != 0 || this.labelWidth != '') ? this.labelWidth : (this.parentData.labelWidth ? this.parentData
|
||||||
|
.labelWidth :
|
||||||
|
90);
|
||||||
|
},
|
||||||
|
// label的样式
|
||||||
|
elLabelStyle() {
|
||||||
|
return Object.keys(this.labelStyle).length ? this.labelStyle : (this.parentData.labelStyle ? this.parentData.labelStyle :
|
||||||
|
{});
|
||||||
|
},
|
||||||
|
// label的位置,左侧或者上方
|
||||||
|
elLabelPosition() {
|
||||||
|
return this.labelPosition ? this.labelPosition : (this.parentData.labelPosition ? this.parentData.labelPosition :
|
||||||
|
'left');
|
||||||
|
},
|
||||||
|
// label的对齐方式
|
||||||
|
elLabelAlign() {
|
||||||
|
return this.labelAlign ? this.labelAlign : (this.parentData.labelAlign ? this.parentData.labelAlign : 'left');
|
||||||
|
},
|
||||||
|
// label的下划线
|
||||||
|
elBorderBottom() {
|
||||||
|
// 子组件的borderBottom默认为空字符串,如果不等于空字符串,意味着子组件设置了值,优先使用子组件的值
|
||||||
|
return this.borderBottom !== '' ? this.borderBottom : this.parentData.borderBottom ? this.parentData.borderBottom :
|
||||||
|
true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
broadcastInputError() {
|
||||||
|
// 子组件发出事件,第三个参数为true或者false,true代表有错误
|
||||||
|
this.broadcast('u-input', 'on-form-item-error', this.validateState === 'error' && this.showError('border'));
|
||||||
|
},
|
||||||
|
// 判断是否需要required校验
|
||||||
|
setRules() {
|
||||||
|
let that = this;
|
||||||
|
// 由于人性化考虑,必填"*"号通过props的required配置,不再通过rules的规则自动生成
|
||||||
|
// 从父组件u-form拿到当前u-form-item需要验证 的规则
|
||||||
|
// let rules = this.getRules();
|
||||||
|
// if (rules.length) {
|
||||||
|
// this.isRequired = rules.some(rule => {
|
||||||
|
// // 如果有必填项,就返回,没有的话,就是undefined
|
||||||
|
// return rule.required;
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
// blur事件
|
||||||
|
this.$on('on-form-blur', that.onFieldBlur);
|
||||||
|
// change事件
|
||||||
|
this.$on('on-form-change', that.onFieldChange);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 从u-form的rules属性中,取出当前u-form-item的校验规则
|
||||||
|
getRules() {
|
||||||
|
// 父组件的所有规则
|
||||||
|
let rules = this.parent.rules;
|
||||||
|
rules = rules ? rules[this.prop] : [];
|
||||||
|
// 保证返回的是一个数组形式
|
||||||
|
return [].concat(rules || []);
|
||||||
|
},
|
||||||
|
|
||||||
|
// blur事件时进行表单校验
|
||||||
|
onFieldBlur() {
|
||||||
|
this.validation('blur');
|
||||||
|
},
|
||||||
|
|
||||||
|
// change事件进行表单校验
|
||||||
|
onFieldChange() {
|
||||||
|
this.validation('change');
|
||||||
|
},
|
||||||
|
|
||||||
|
// 过滤出符合要求的rule规则
|
||||||
|
getFilteredRule(triggerType = '') {
|
||||||
|
let rules = this.getRules();
|
||||||
|
// 整体验证表单时,triggerType为空字符串,此时返回所有规则进行验证
|
||||||
|
if (!triggerType) return rules;
|
||||||
|
// 历遍判断规则是否有对应的事件,比如blur,change触发等的事件
|
||||||
|
// 使用indexOf判断,是因为某些时候设置的验证规则的trigger属性可能为多个,比如['blur','change']
|
||||||
|
// 某些场景可能的判断规则,可能不存在trigger属性,故先判断是否存在此属性
|
||||||
|
return rules.filter(res => res.trigger && res.trigger.indexOf(triggerType) !== -1);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 校验数据
|
||||||
|
validation(trigger, callback = () => {}) {
|
||||||
|
// 检验之间,先获取需要校验的值
|
||||||
|
this.fieldValue = this.parent.model[this.prop];
|
||||||
|
// blur和change是否有当前方式的校验规则
|
||||||
|
let rules = this.getFilteredRule(trigger);
|
||||||
|
// 判断是否有验证规则,如果没有规则,也调用回调方法,否则父组件u-form会因为
|
||||||
|
// 对count变量的统计错误而无法进入上一层的回调
|
||||||
|
if (!rules || rules.length === 0) {
|
||||||
|
return callback('');
|
||||||
|
}
|
||||||
|
// 设置当前的装填,标识为校验中
|
||||||
|
this.validateState = 'validating';
|
||||||
|
// 调用async-validator的方法
|
||||||
|
let validator = new schema({
|
||||||
|
[this.prop]: rules
|
||||||
|
});
|
||||||
|
validator.validate({
|
||||||
|
[this.prop]: this.fieldValue
|
||||||
|
}, {
|
||||||
|
firstFields: true
|
||||||
|
}, (errors, fields) => {
|
||||||
|
// 记录状态和报错信息
|
||||||
|
this.validateState = !errors ? 'success' : 'error';
|
||||||
|
this.validateMessage = errors ? errors[0].message : '';
|
||||||
|
// 调用回调方法
|
||||||
|
callback(this.validateMessage);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 清空当前的u-form-item
|
||||||
|
resetField() {
|
||||||
|
this.parent.model[this.prop] = this.initialValue;
|
||||||
|
// 设置为`success`状态,只是为了清空错误标记
|
||||||
|
this.validateState = 'success';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 组件创建完成时,将当前实例保存到u-form中
|
||||||
|
mounted() {
|
||||||
|
// 支付宝、头条小程序不支持provide/inject,所以使用这个方法获取整个父组件,在created定义,避免循环应用
|
||||||
|
this.parent = this.$u.$parent.call(this, 'u-form');
|
||||||
|
if (this.parent) {
|
||||||
|
// 历遍parentData中的属性,将parent中的同名属性赋值给parentData
|
||||||
|
Object.keys(this.parentData).map(key => {
|
||||||
|
this.parentData[key] = this.parent[key];
|
||||||
|
});
|
||||||
|
// 如果没有传入prop,或者uForm为空(如果u-form-input单独使用,就不会有uForm注入),就不进行校验
|
||||||
|
if (this.prop) {
|
||||||
|
// 将本实例添加到父组件中
|
||||||
|
this.parent.fields.push(this);
|
||||||
|
this.errorType = this.parent.errorType;
|
||||||
|
// 设置初始值
|
||||||
|
this.initialValue = this.fieldValue;
|
||||||
|
// 添加表单校验,这里必须要写在$nextTick中,因为u-form的rules是通过ref手动传入的
|
||||||
|
// 不在$nextTick中的话,可能会造成执行此处代码时,父组件还没通过ref把规则给u-form,导致规则为空
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.setRules();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 组件销毁前,将实例从u-form的缓存中移除
|
||||||
|
beforeDestroy() {
|
||||||
|
// 如果当前没有prop的话表示当前不要进行删除(因为没有注入)
|
||||||
|
if (this.parent && this.prop) {
|
||||||
|
this.parent.fields.map((item, index) => {
|
||||||
|
if (item === this) this.parent.fields.splice(index, 1);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-form-item {
|
||||||
|
@include vue-flex;
|
||||||
|
// align-items: flex-start;
|
||||||
|
padding: 20rpx 0;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
box-sizing: border-box;
|
||||||
|
line-height: $u-form-item-height;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__border-bottom--error:after {
|
||||||
|
border-color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__body {
|
||||||
|
@include vue-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--left {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
position: relative;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-right: 10rpx;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
margin-right: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--required {
|
||||||
|
position: absolute;
|
||||||
|
left: -16rpx;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: $u-type-error;
|
||||||
|
padding-top: 6rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&__slot {
|
||||||
|
flex: 1;
|
||||||
|
/* #ifndef MP */
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
color: $u-light-color;
|
||||||
|
font-size: 30rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__message {
|
||||||
|
font-size: 24rpx;
|
||||||
|
line-height: 24rpx;
|
||||||
|
color: $u-type-error;
|
||||||
|
margin-top: 12rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
134
node_modules/uview-ui/components/u-form/u-form.vue
generated
vendored
Normal file
134
node_modules/uview-ui/components/u-form/u-form.vue
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-form"><slot /></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* form 表单
|
||||||
|
* @description 此组件一般用于表单场景,可以配置Input输入框,Select弹出框,进行表单验证等。
|
||||||
|
* @tutorial http://uviewui.com/components/form.html
|
||||||
|
* @property {Object} model 表单数据对象
|
||||||
|
* @property {Boolean} border-bottom 是否显示表单域的下划线边框
|
||||||
|
* @property {String} label-position 表单域提示文字的位置,left-左侧,top-上方
|
||||||
|
* @property {String Number} label-width 提示文字的宽度,单位rpx(默认90)
|
||||||
|
* @property {Object} label-style lable的样式,对象形式
|
||||||
|
* @property {String} label-align lable的对齐方式
|
||||||
|
* @property {Object} rules 通过ref设置,见官网说明
|
||||||
|
* @property {Array} error-type 错误的提示方式,数组形式,见上方说明(默认['message'])
|
||||||
|
* @example <u-form :model="form" ref="uForm"></u-form>
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'u-form',
|
||||||
|
props: {
|
||||||
|
// 当前form的需要验证字段的集合
|
||||||
|
model: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 验证规则
|
||||||
|
// rules: {
|
||||||
|
// type: [Object, Function, Array],
|
||||||
|
// default() {
|
||||||
|
// return {};
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// 有错误时的提示方式,message-提示信息,border-如果input设置了边框,变成呈红色,
|
||||||
|
// border-bottom-下边框呈现红色,none-无提示
|
||||||
|
errorType: {
|
||||||
|
type: Array,
|
||||||
|
default() {
|
||||||
|
return ['message', 'toast']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 是否显示表单域的下划线边框
|
||||||
|
borderBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// label的位置,left-左边,top-上边
|
||||||
|
labelPosition: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// label的宽度,单位rpx
|
||||||
|
labelWidth: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 90
|
||||||
|
},
|
||||||
|
// lable字体的对齐方式
|
||||||
|
labelAlign: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// lable的样式,对象形式
|
||||||
|
labelStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
uForm: this
|
||||||
|
};
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rules: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 存储当前form下的所有u-form-item的实例
|
||||||
|
// 不能定义在data中,否则微信小程序会造成循环引用而报错
|
||||||
|
this.fields = [];
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
setRules(rules) {
|
||||||
|
this.rules = rules;
|
||||||
|
},
|
||||||
|
// 清空所有u-form-item组件的内容,本质上是调用了u-form-item组件中的resetField()方法
|
||||||
|
resetFields() {
|
||||||
|
this.fields.map(field => {
|
||||||
|
field.resetField();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// 校验全部数据
|
||||||
|
validate(callback) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
// 对所有的u-form-item进行校验
|
||||||
|
let valid = true; // 默认通过
|
||||||
|
let count = 0; // 用于标记是否检查完毕
|
||||||
|
let errorArr = []; // 存放错误信息
|
||||||
|
this.fields.map(field => {
|
||||||
|
// 调用每一个u-form-item实例的validation的校验方法
|
||||||
|
field.validation('', error => {
|
||||||
|
// 如果任意一个u-form-item校验不通过,就意味着整个表单不通过
|
||||||
|
if (error) {
|
||||||
|
valid = false;
|
||||||
|
errorArr.push(error);
|
||||||
|
}
|
||||||
|
// 当历遍了所有的u-form-item时,调用promise的then方法
|
||||||
|
if (++count === this.fields.length) {
|
||||||
|
resolve(valid); // 进入promise的then方法
|
||||||
|
// 判断是否设置了toast的提示方式,只提示最前面的表单域的第一个错误信息
|
||||||
|
if(this.errorType.indexOf('none') === -1 && this.errorType.indexOf('toast') >= 0 && errorArr.length) {
|
||||||
|
this.$u.toast(errorArr[0]);
|
||||||
|
}
|
||||||
|
// 调用回调方法
|
||||||
|
if (typeof callback == 'function') callback(valid);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
</style>
|
||||||
52
node_modules/uview-ui/components/u-full-screen/u-full-screen.vue
generated
vendored
Normal file
52
node_modules/uview-ui/components/u-full-screen/u-full-screen.vue
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<template>
|
||||||
|
<u-modal v-model="show" :show-cancel-button="true" confirm-text="升级" title="发现新版本" @cancel="cancel" @confirm="confirm">
|
||||||
|
<view class="u-update-content">
|
||||||
|
<rich-text :nodes="content"></rich-text>
|
||||||
|
</view>
|
||||||
|
</u-modal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
show: false,
|
||||||
|
content: `
|
||||||
|
1. 修复badge组件的size参数无效问题<br>
|
||||||
|
2. 新增Modal模态框组件<br>
|
||||||
|
3. 新增压窗屏组件,可以在APP上以弹窗的形式遮盖导航栏和底部tabbar<br>
|
||||||
|
4. 修复键盘组件在微信小程序上遮罩无效的问题
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onReady() {
|
||||||
|
this.show = true;
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
cancel() {
|
||||||
|
this.closeModal();
|
||||||
|
},
|
||||||
|
confirm() {
|
||||||
|
this.closeModal();
|
||||||
|
},
|
||||||
|
closeModal() {
|
||||||
|
uni.navigateBack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-full-content {
|
||||||
|
background-color: #00C777;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-update-content {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: $u-content-color;
|
||||||
|
line-height: 1.7;
|
||||||
|
padding: 30rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
54
node_modules/uview-ui/components/u-gap/u-gap.vue
generated
vendored
Normal file
54
node_modules/uview-ui/components/u-gap/u-gap.vue
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-gap" :style="[gapStyle]"></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* gap 间隔槽
|
||||||
|
* @description 该组件一般用于内容块之间的用一个灰色块隔开的场景,方便用户风格统一,减少工作量
|
||||||
|
* @tutorial https://www.uviewui.com/components/gap.html
|
||||||
|
* @property {String} bg-color 背景颜色(默认#f3f4f6)
|
||||||
|
* @property {String Number} height 分割槽高度,单位rpx(默认30)
|
||||||
|
* @property {String Number} margin-top 与前一个组件的距离,单位rpx(默认0)
|
||||||
|
* @property {String Number} margin-bottom 与后一个组件的距离,单位rpx(0)
|
||||||
|
* @example <u-gap height="80" bg-color="#bbb"></u-gap>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-gap",
|
||||||
|
props: {
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: 'transparent ' // 背景透明
|
||||||
|
},
|
||||||
|
// 高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 30
|
||||||
|
},
|
||||||
|
// 与上一个组件的距离
|
||||||
|
marginTop: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 与下一个组件的距离
|
||||||
|
marginBottom: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
gapStyle() {
|
||||||
|
return {
|
||||||
|
backgroundColor: this.bgColor,
|
||||||
|
height: this.height + 'rpx',
|
||||||
|
marginTop: this.marginTop + 'rpx',
|
||||||
|
marginBottom: this.marginBottom + 'rpx'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
</style>
|
||||||
126
node_modules/uview-ui/components/u-grid-item/u-grid-item.vue
generated
vendored
Normal file
126
node_modules/uview-ui/components/u-grid-item/u-grid-item.vue
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-grid-item" :hover-class="parentData.hoverClass"
|
||||||
|
:hover-stay-time="200" @tap="click" :style="{
|
||||||
|
background: bgColor,
|
||||||
|
width: width,
|
||||||
|
}">
|
||||||
|
<view class="u-grid-item-box" :style="[customStyle]" :class="[parentData.border ? 'u-border-right u-border-bottom' : '']">
|
||||||
|
<slot />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* gridItem 提示
|
||||||
|
* @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。搭配u-grid使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/grid.html
|
||||||
|
* @property {String} bg-color 宫格的背景颜色(默认#ffffff)
|
||||||
|
* @property {String Number} index 点击宫格时,返回的值
|
||||||
|
* @property {Object} custom-style 自定义样式,对象形式
|
||||||
|
* @event {Function} click 点击宫格触发
|
||||||
|
* @example <u-grid-item></u-grid-item>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-grid-item",
|
||||||
|
props: {
|
||||||
|
// 背景颜色
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ffffff'
|
||||||
|
},
|
||||||
|
// 点击时返回的index
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义样式,对象形式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {
|
||||||
|
padding: '30rpx 0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
parentData: {
|
||||||
|
hoverClass: '', // 按下去的时候,是否显示背景灰色
|
||||||
|
col: 3, // 父组件划分的宫格数
|
||||||
|
border: true, // 是否显示边框,根据父组件决定
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 父组件的实例
|
||||||
|
this.updateParentData();
|
||||||
|
// this.parent在updateParentData()中定义
|
||||||
|
this.parent.children.push(this);
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 每个grid-item的宽度
|
||||||
|
width() {
|
||||||
|
return 100 / Number(this.parentData.col) + '%';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 获取父组件的参数
|
||||||
|
updateParentData() {
|
||||||
|
// 此方法写在mixin中
|
||||||
|
this.getParentData('u-grid');
|
||||||
|
},
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index);
|
||||||
|
this.parent && this.parent.click(this.index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-grid-item {
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: #fff;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
/* #ifdef MP */
|
||||||
|
position: relative;
|
||||||
|
float: left;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-grid-item-hover {
|
||||||
|
background: #f7f7f7 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-grid-marker-box {
|
||||||
|
position: absolute;
|
||||||
|
/* #ifndef APP-NVUE */
|
||||||
|
display: inline-flex;
|
||||||
|
/* #endif */
|
||||||
|
line-height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-grid-marker-wrap {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-grid-item-box {
|
||||||
|
padding: 30rpx 0;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
108
node_modules/uview-ui/components/u-grid/u-grid.vue
generated
vendored
Normal file
108
node_modules/uview-ui/components/u-grid/u-grid.vue
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-grid" :class="{'u-border-top u-border-left': border}" :style="[gridStyle]"><slot /></view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* grid 宫格布局
|
||||||
|
* @description 宫格组件一般用于同时展示多个同类项目的场景,可以给宫格的项目设置徽标组件(badge),或者图标等,也可以扩展为左右滑动的轮播形式。
|
||||||
|
* @tutorial https://www.uviewui.com/components/grid.html
|
||||||
|
* @property {String Number} col 宫格的列数(默认3)
|
||||||
|
* @property {Boolean} border 是否显示宫格的边框(默认true)
|
||||||
|
* @property {Boolean} hover-class 点击宫格的时候,是否显示按下的灰色背景(默认false)
|
||||||
|
* @event {Function} click 点击宫格触发
|
||||||
|
* @example <u-grid :col="3" @click="click"></u-grid>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-grid',
|
||||||
|
props: {
|
||||||
|
// 分成几列
|
||||||
|
col: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 3
|
||||||
|
},
|
||||||
|
// 是否显示边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 宫格对齐方式,表现为数量少的时候,靠左,居中,还是靠右
|
||||||
|
align: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
// 宫格按压时的样式类,"none"为无效果
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: 'u-hover-class'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
// 当父组件需要子组件需要共享的参数发生了变化,手动通知子组件
|
||||||
|
parentData() {
|
||||||
|
if(this.children.length) {
|
||||||
|
this.children.map(child => {
|
||||||
|
// 判断子组件(u-radio)如果有updateParentData方法的话,就就执行(执行的结果是子组件重新从父组件拉取了最新的值)
|
||||||
|
typeof(child.updateParentData) == 'function' && child.updateParentData();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 如果将children定义在data中,在微信小程序会造成循环引用而报错
|
||||||
|
this.children = [];
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 计算父组件的值是否发生变化
|
||||||
|
parentData() {
|
||||||
|
return [this.hoverClass, this.col, this.size, this.border];
|
||||||
|
},
|
||||||
|
// 宫格对齐方式
|
||||||
|
gridStyle() {
|
||||||
|
let style = {};
|
||||||
|
switch(this.align) {
|
||||||
|
case 'left':
|
||||||
|
style.justifyContent = 'flex-start';
|
||||||
|
break;
|
||||||
|
case 'center':
|
||||||
|
style.justifyContent = 'center';
|
||||||
|
break;
|
||||||
|
case 'right':
|
||||||
|
style.justifyContent = 'flex-end';
|
||||||
|
break;
|
||||||
|
default: style.justifyContent = 'flex-start';
|
||||||
|
};
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click(index) {
|
||||||
|
this.$emit('click', index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-grid {
|
||||||
|
width: 100%;
|
||||||
|
/* #ifdef MP */
|
||||||
|
position: relative;
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: hidden;
|
||||||
|
/* #endif */
|
||||||
|
|
||||||
|
/* #ifndef MP */
|
||||||
|
@include vue-flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
/* #endif */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
336
node_modules/uview-ui/components/u-icon/u-icon.vue
generated
vendored
Normal file
336
node_modules/uview-ui/components/u-icon/u-icon.vue
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
<template>
|
||||||
|
<view :style="[customStyle]" class="u-icon" @tap="click" :class="['u-icon--' + labelPos]">
|
||||||
|
<image class="u-icon__img" v-if="isImg" :src="name" :mode="imgMode" :style="[imgStyle]"></image>
|
||||||
|
<text v-else class="u-icon__icon" :class="customClass" :style="[iconStyle]" :hover-class="hoverClass"
|
||||||
|
@touchstart="touchstart">
|
||||||
|
<text v-if="showDecimalIcon" :style="[decimalIconStyle]" :class="decimalIconClass" :hover-class="hoverClass"
|
||||||
|
class="u-icon__decimal">
|
||||||
|
</text>
|
||||||
|
</text>
|
||||||
|
<!-- 这里进行空字符串判断,如果仅仅是v-if="label",可能会出现传递0的时候,结果也无法显示 -->
|
||||||
|
<text v-if="label !== ''" class="u-icon__label" :style="{
|
||||||
|
color: labelColor,
|
||||||
|
fontSize: $u.addUnit(labelSize),
|
||||||
|
marginLeft: labelPos == 'right' ? $u.addUnit(marginLeft) : 0,
|
||||||
|
marginTop: labelPos == 'bottom' ? $u.addUnit(marginTop) : 0,
|
||||||
|
marginRight: labelPos == 'left' ? $u.addUnit(marginRight) : 0,
|
||||||
|
marginBottom: labelPos == 'top' ? $u.addUnit(marginBottom) : 0,
|
||||||
|
}">{{ label }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* icon 图标
|
||||||
|
* @description 基于字体的图标集,包含了大多数常见场景的图标。
|
||||||
|
* @tutorial https://www.uviewui.com/components/icon.html
|
||||||
|
* @property {String} name 图标名称,见示例图标集
|
||||||
|
* @property {String} color 图标颜色(默认inherit)
|
||||||
|
* @property {String | Number} size 图标字体大小,单位rpx(默认32)
|
||||||
|
* @property {String | Number} label-size label字体大小,单位rpx(默认28)
|
||||||
|
* @property {String} label 图标右侧的label文字(默认28)
|
||||||
|
* @property {String} label-pos label文字相对于图标的位置,只能right或bottom(默认right)
|
||||||
|
* @property {String} label-color label字体颜色(默认#606266)
|
||||||
|
* @property {Object} custom-style icon的样式,对象形式
|
||||||
|
* @property {String} custom-prefix 自定义字体图标库时,需要写上此值
|
||||||
|
* @property {String | Number} margin-left label在右侧时与图标的距离,单位rpx(默认6)
|
||||||
|
* @property {String | Number} margin-top label在下方时与图标的距离,单位rpx(默认6)
|
||||||
|
* @property {String | Number} margin-bottom label在上方时与图标的距离,单位rpx(默认6)
|
||||||
|
* @property {String | Number} margin-right label在左侧时与图标的距离,单位rpx(默认6)
|
||||||
|
* @property {String} label-pos label相对于图标的位置,只能right或bottom(默认right)
|
||||||
|
* @property {String} index 一个用于区分多个图标的值,点击图标时通过click事件传出
|
||||||
|
* @property {String} hover-class 图标按下去的样式类,用法同uni的view组件的hover-class参数,详情见官网
|
||||||
|
* @property {String} width 显示图片小图标时的宽度
|
||||||
|
* @property {String} height 显示图片小图标时的高度
|
||||||
|
* @property {String} top 图标在垂直方向上的定位
|
||||||
|
* @property {String} top 图标在垂直方向上的定位
|
||||||
|
* @property {String} top 图标在垂直方向上的定位
|
||||||
|
* @property {Boolean} show-decimal-icon 是否为DecimalIcon
|
||||||
|
* @property {String} inactive-color 背景颜色,可接受主题色,仅Decimal时有效
|
||||||
|
* @property {String | Number} percent 显示的百分比,仅Decimal时有效
|
||||||
|
* @event {Function} click 点击图标时触发
|
||||||
|
* @example <u-icon name="photo" color="#2979ff" size="28"></u-icon>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-icon',
|
||||||
|
props: {
|
||||||
|
// 图标类名
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 图标颜色,可接受主题色
|
||||||
|
color: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 字体大小,单位rpx
|
||||||
|
size: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 'inherit'
|
||||||
|
},
|
||||||
|
// 是否显示粗体
|
||||||
|
bold: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 点击图标的时候传递事件出去的index(用于区分点击了哪一个)
|
||||||
|
index: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 触摸图标时的类名
|
||||||
|
hoverClass: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 自定义扩展前缀,方便用户扩展自己的图标库
|
||||||
|
customPrefix: {
|
||||||
|
type: String,
|
||||||
|
default: 'uicon'
|
||||||
|
},
|
||||||
|
// 图标右边或者下面的文字
|
||||||
|
label: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// label的位置,只能右边或者下边
|
||||||
|
labelPos: {
|
||||||
|
type: String,
|
||||||
|
default: 'right'
|
||||||
|
},
|
||||||
|
// label的大小
|
||||||
|
labelSize: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '28'
|
||||||
|
},
|
||||||
|
// label的颜色
|
||||||
|
labelColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#606266'
|
||||||
|
},
|
||||||
|
// label与图标的距离(横向排列)
|
||||||
|
marginLeft: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '6'
|
||||||
|
},
|
||||||
|
// label与图标的距离(竖向排列)
|
||||||
|
marginTop: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '6'
|
||||||
|
},
|
||||||
|
// label与图标的距离(竖向排列)
|
||||||
|
marginRight: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '6'
|
||||||
|
},
|
||||||
|
// label与图标的距离(竖向排列)
|
||||||
|
marginBottom: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '6'
|
||||||
|
},
|
||||||
|
// 图片的mode
|
||||||
|
imgMode: {
|
||||||
|
type: String,
|
||||||
|
default: 'widthFix'
|
||||||
|
},
|
||||||
|
// 自定义样式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 用于显示图片小图标时,图片的宽度
|
||||||
|
width: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 用于显示图片小图标时,图片的高度
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 用于解决某些情况下,让图标垂直居中的用途
|
||||||
|
top: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否为DecimalIcon
|
||||||
|
showDecimalIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 背景颜色,可接受主题色,仅Decimal时有效
|
||||||
|
inactiveColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#ececec'
|
||||||
|
},
|
||||||
|
// 显示的百分比,仅Decimal时有效
|
||||||
|
percent: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: '50'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
customClass() {
|
||||||
|
let classes = []
|
||||||
|
classes.push(this.customPrefix + '-' + this.name)
|
||||||
|
// uView的自定义图标类名为u-iconfont
|
||||||
|
if (this.customPrefix == 'uicon') {
|
||||||
|
classes.push('u-iconfont')
|
||||||
|
} else {
|
||||||
|
classes.push(this.customPrefix)
|
||||||
|
}
|
||||||
|
// 主题色,通过类配置
|
||||||
|
if (this.showDecimalIcon && this.inactiveColor && this.$u.config.type.includes(this.inactiveColor)) {
|
||||||
|
classes.push('u-icon__icon--' + this.inactiveColor)
|
||||||
|
} else if (this.color && this.$u.config.type.includes(this.color)) classes.push('u-icon__icon--' + this.color)
|
||||||
|
// 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
|
||||||
|
// 故需将其拆成一个字符串的形式,通过空格隔开各个类名
|
||||||
|
//#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
|
||||||
|
classes = classes.join(' ')
|
||||||
|
//#endif
|
||||||
|
return classes
|
||||||
|
},
|
||||||
|
iconStyle() {
|
||||||
|
let style = {}
|
||||||
|
style = {
|
||||||
|
fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size),
|
||||||
|
fontWeight: this.bold ? 'bold' : 'normal',
|
||||||
|
// 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
|
||||||
|
top: this.$u.addUnit(this.top)
|
||||||
|
}
|
||||||
|
// 非主题色值时,才当作颜色值
|
||||||
|
if (this.showDecimalIcon && this.inactiveColor && !this.$u.config.type.includes(this.inactiveColor)) {
|
||||||
|
style.color = this.inactiveColor
|
||||||
|
} else if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color
|
||||||
|
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
// 判断传入的name属性,是否图片路径,只要带有"/"均认为是图片形式
|
||||||
|
isImg() {
|
||||||
|
return this.name.indexOf('/') !== -1
|
||||||
|
},
|
||||||
|
imgStyle() {
|
||||||
|
let style = {}
|
||||||
|
// 如果设置width和height属性,则优先使用,否则使用size属性
|
||||||
|
style.width = this.width ? this.$u.addUnit(this.width) : this.$u.addUnit(this.size)
|
||||||
|
style.height = this.height ? this.$u.addUnit(this.height) : this.$u.addUnit(this.size)
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
decimalIconStyle() {
|
||||||
|
let style = {}
|
||||||
|
style = {
|
||||||
|
fontSize: this.size == 'inherit' ? 'inherit' : this.$u.addUnit(this.size),
|
||||||
|
fontWeight: this.bold ? 'bold' : 'normal',
|
||||||
|
// 某些特殊情况需要设置一个到顶部的距离,才能更好的垂直居中
|
||||||
|
top: this.$u.addUnit(this.top),
|
||||||
|
width: this.percent + '%'
|
||||||
|
}
|
||||||
|
// 非主题色值时,才当作颜色值
|
||||||
|
if (this.color && !this.$u.config.type.includes(this.color)) style.color = this.color
|
||||||
|
return style
|
||||||
|
},
|
||||||
|
decimalIconClass() {
|
||||||
|
let classes = []
|
||||||
|
classes.push(this.customPrefix + '-' + this.name)
|
||||||
|
// uView的自定义图标类名为u-iconfont
|
||||||
|
if (this.customPrefix == 'uicon') {
|
||||||
|
classes.push('u-iconfont')
|
||||||
|
} else {
|
||||||
|
classes.push(this.customPrefix)
|
||||||
|
}
|
||||||
|
// 主题色,通过类配置
|
||||||
|
if (this.color && this.$u.config.type.includes(this.color)) classes.push('u-icon__icon--' + this.color)
|
||||||
|
else classes.push('u-icon__icon--primary')
|
||||||
|
// 阿里,头条,百度小程序通过数组绑定类名时,无法直接使用[a, b, c]的形式,否则无法识别
|
||||||
|
// 故需将其拆成一个字符串的形式,通过空格隔开各个类名
|
||||||
|
//#ifdef MP-ALIPAY || MP-TOUTIAO || MP-BAIDU
|
||||||
|
classes = classes.join(' ')
|
||||||
|
//#endif
|
||||||
|
return classes
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
click() {
|
||||||
|
this.$emit('click', this.index)
|
||||||
|
},
|
||||||
|
touchstart() {
|
||||||
|
this.$emit('touchstart', this.index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
@import '../../iconfont.css';
|
||||||
|
|
||||||
|
.u-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&--left {
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--right {
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--top {
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--bottom {
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__icon {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&--primary {
|
||||||
|
color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--success {
|
||||||
|
color: $u-type-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
color: $u-type-error;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--warning {
|
||||||
|
color: $u-type-warning;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--info {
|
||||||
|
color: $u-type-info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__decimal {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__img {
|
||||||
|
height: auto;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__label {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
267
node_modules/uview-ui/components/u-image/u-image.vue
generated
vendored
Normal file
267
node_modules/uview-ui/components/u-image/u-image.vue
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
|||||||
|
<template>
|
||||||
|
<view class="u-image" @tap="onClick" :style="[wrapStyle, backgroundStyle]">
|
||||||
|
<image
|
||||||
|
v-if="!isError"
|
||||||
|
:src="src"
|
||||||
|
:mode="mode"
|
||||||
|
@error="onErrorHandler"
|
||||||
|
@load="onLoadHandler"
|
||||||
|
:lazy-load="lazyLoad"
|
||||||
|
class="u-image__image"
|
||||||
|
:show-menu-by-longpress="showMenuByLongpress"
|
||||||
|
:style="{
|
||||||
|
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius)
|
||||||
|
}"
|
||||||
|
></image>
|
||||||
|
<view
|
||||||
|
v-if="showLoading && loading"
|
||||||
|
class="u-image__loading"
|
||||||
|
:style="{
|
||||||
|
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius),
|
||||||
|
backgroundColor: this.bgColor
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot v-if="$slots.loading" name="loading" />
|
||||||
|
<u-icon v-else :name="loadingIcon" :width="width" :height="height"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view
|
||||||
|
v-if="showError && isError && !loading"
|
||||||
|
class="u-image__error"
|
||||||
|
:style="{
|
||||||
|
borderRadius: shape == 'circle' ? '50%' : $u.addUnit(borderRadius)
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot v-if="$slots.error" name="error" />
|
||||||
|
<u-icon v-else :name="errorIcon" :width="width" :height="height"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* Image 图片
|
||||||
|
* @description 此组件为uni-app的image组件的加强版,在继承了原有功能外,还支持淡入动画、加载中、加载失败提示、圆角值和形状等。
|
||||||
|
* @tutorial https://uviewui.com/components/image.html
|
||||||
|
* @property {String} src 图片地址
|
||||||
|
* @property {String} mode 裁剪模式,见官网说明
|
||||||
|
* @property {String | Number} width 宽度,单位任意,如果为数值,则为rpx单位(默认100%)
|
||||||
|
* @property {String | Number} height 高度,单位任意,如果为数值,则为rpx单位(默认 auto)
|
||||||
|
* @property {String} shape 图片形状,circle-圆形,square-方形(默认square)
|
||||||
|
* @property {String | Number} border-radius 圆角值,单位任意,如果为数值,则为rpx单位(默认 0)
|
||||||
|
* @property {Boolean} lazy-load 是否懒加载,仅微信小程序、App、百度小程序、字节跳动小程序有效(默认 true)
|
||||||
|
* @property {Boolean} show-menu-by-longpress 是否开启长按图片显示识别小程序码菜单,仅微信小程序有效(默认 false)
|
||||||
|
* @property {String} loading-icon 加载中的图标,或者小图片(默认 photo)
|
||||||
|
* @property {String} error-icon 加载失败的图标,或者小图片(默认 error-circle)
|
||||||
|
* @property {Boolean} show-loading 是否显示加载中的图标或者自定义的slot(默认 true)
|
||||||
|
* @property {Boolean} show-error 是否显示加载错误的图标或者自定义的slot(默认 true)
|
||||||
|
* @property {Boolean} fade 是否需要淡入效果(默认 true)
|
||||||
|
* @property {String Number} width 传入图片路径时图片的宽度
|
||||||
|
* @property {String Number} height 传入图片路径时图片的高度
|
||||||
|
* @property {Boolean} webp 只支持网络资源,只对微信小程序有效(默认 false)
|
||||||
|
* @property {String | Number} duration 搭配fade参数的过渡时间,单位ms(默认 500)
|
||||||
|
* @event {Function} click 点击图片时触发
|
||||||
|
* @event {Function} error 图片加载失败时触发
|
||||||
|
* @event {Function} load 图片加载成功时触发
|
||||||
|
* @example <u-image width="100%" height="300rpx" :src="src"></u-image>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-image',
|
||||||
|
props: {
|
||||||
|
// 图片地址
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 裁剪模式
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'aspectFill'
|
||||||
|
},
|
||||||
|
// 宽度,单位任意
|
||||||
|
width: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: '100%'
|
||||||
|
},
|
||||||
|
// 高度,单位任意
|
||||||
|
height: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 'auto'
|
||||||
|
},
|
||||||
|
// 图片形状,circle-圆形,square-方形
|
||||||
|
shape: {
|
||||||
|
type: String,
|
||||||
|
default: 'square'
|
||||||
|
},
|
||||||
|
// 圆角,单位任意
|
||||||
|
borderRadius: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 是否懒加载,微信小程序、App、百度小程序、字节跳动小程序
|
||||||
|
lazyLoad: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 开启长按图片显示识别微信小程序码菜单
|
||||||
|
showMenuByLongpress: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 加载中的图标,或者小图片
|
||||||
|
loadingIcon: {
|
||||||
|
type: String,
|
||||||
|
default: 'photo'
|
||||||
|
},
|
||||||
|
// 加载失败的图标,或者小图片
|
||||||
|
errorIcon: {
|
||||||
|
type: String,
|
||||||
|
default: 'error-circle'
|
||||||
|
},
|
||||||
|
// 是否显示加载中的图标或者自定义的slot
|
||||||
|
showLoading: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示加载错误的图标或者自定义的slot
|
||||||
|
showError: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否需要淡入效果
|
||||||
|
fade: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 只支持网络资源,只对微信小程序有效
|
||||||
|
webp: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 过渡时间,单位ms
|
||||||
|
duration: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: 500
|
||||||
|
},
|
||||||
|
// 背景颜色,用于深色页面加载图片时,为了和背景色融合
|
||||||
|
bgColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#f3f4f6'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
// 图片是否加载错误,如果是,则显示错误占位图
|
||||||
|
isError: false,
|
||||||
|
// 初始化组件时,默认为加载中状态
|
||||||
|
loading: true,
|
||||||
|
// 不透明度,为了实现淡入淡出的效果
|
||||||
|
opacity: 1,
|
||||||
|
// 过渡时间,因为props的值无法修改,故需要一个中间值
|
||||||
|
durationTime: this.duration,
|
||||||
|
// 图片加载完成时,去掉背景颜色,因为如果是png图片,就会显示灰色的背景
|
||||||
|
backgroundStyle: {}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
src: {
|
||||||
|
immediate: true,
|
||||||
|
handler (n) {
|
||||||
|
if(!n) {
|
||||||
|
// 如果传入null或者'',或者false,或者undefined,标记为错误状态
|
||||||
|
this.isError = true;
|
||||||
|
this.loading = false;
|
||||||
|
} else {
|
||||||
|
this.isError = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
wrapStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 通过调用addUnit()方法,如果有单位,如百分比,px单位等,直接返回,如果是纯粹的数值,则加上rpx单位
|
||||||
|
style.width = this.$u.addUnit(this.width);
|
||||||
|
style.height = this.$u.addUnit(this.height);
|
||||||
|
// 如果是配置了圆形,设置50%的圆角,否则按照默认的配置值
|
||||||
|
style.borderRadius = this.shape == 'circle' ? '50%' : this.$u.addUnit(this.borderRadius);
|
||||||
|
// 如果设置圆角,必须要有hidden,否则可能圆角无效
|
||||||
|
style.overflow = this.borderRadius > 0 ? 'hidden' : 'visible';
|
||||||
|
if (this.fade) {
|
||||||
|
style.opacity = this.opacity;
|
||||||
|
style.transition = `opacity ${Number(this.durationTime) / 1000}s ease-in-out`;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 点击图片
|
||||||
|
onClick() {
|
||||||
|
this.$emit('click');
|
||||||
|
},
|
||||||
|
// 图片加载失败
|
||||||
|
onErrorHandler(err) {
|
||||||
|
this.loading = false;
|
||||||
|
this.isError = true;
|
||||||
|
this.$emit('error', err);
|
||||||
|
},
|
||||||
|
// 图片加载完成,标记loading结束
|
||||||
|
onLoadHandler() {
|
||||||
|
this.loading = false;
|
||||||
|
this.isError = false;
|
||||||
|
this.$emit('load');
|
||||||
|
// 如果不需要动画效果,就不执行下方代码,同时移除加载时的背景颜色
|
||||||
|
// 否则无需fade效果时,png图片依然能看到下方的背景色
|
||||||
|
if (!this.fade) return this.removeBgColor();
|
||||||
|
// 原来opacity为1(不透明,是为了显示占位图),改成0(透明,意味着该元素显示的是背景颜色,默认的灰色),再改成1,是为了获得过渡效果
|
||||||
|
this.opacity = 0;
|
||||||
|
// 这里设置为0,是为了图片展示到背景全透明这个过程时间为0,延时之后延时之后重新设置为duration,是为了获得背景透明(灰色)
|
||||||
|
// 到图片展示的过程中的淡入效果
|
||||||
|
this.durationTime = 0;
|
||||||
|
// 延时50ms,否则在浏览器H5,过渡效果无效
|
||||||
|
setTimeout(() => {
|
||||||
|
this.durationTime = this.duration;
|
||||||
|
this.opacity = 1;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.removeBgColor();
|
||||||
|
}, this.durationTime);
|
||||||
|
}, 50);
|
||||||
|
},
|
||||||
|
// 移除图片的背景色
|
||||||
|
removeBgColor() {
|
||||||
|
// 淡入动画过渡完成后,将背景设置为透明色,否则png图片会看到灰色的背景
|
||||||
|
this.backgroundStyle = {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
@import '../../libs/css/style.components.scss';
|
||||||
|
|
||||||
|
.u-image {
|
||||||
|
position: relative;
|
||||||
|
transition: opacity 0.5s ease-in-out;
|
||||||
|
|
||||||
|
&__image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__loading,
|
||||||
|
&__error {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
@include vue-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: $u-bg-color;
|
||||||
|
color: $u-tips-color;
|
||||||
|
font-size: 46rpx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
89
node_modules/uview-ui/components/u-index-anchor/u-index-anchor.vue
generated
vendored
Normal file
89
node_modules/uview-ui/components/u-index-anchor/u-index-anchor.vue
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 支付宝小程序使用$u.getRect()获取组件的根元素尺寸,所以在外面套一个"壳" -->
|
||||||
|
<view>
|
||||||
|
<view class="u-index-anchor-wrapper" :id="$u.guid()" :style="[wrapperStyle]">
|
||||||
|
<view class="u-index-anchor " :class="[active ? 'u-index-anchor--active' : '']" :style="[customAnchorStyle]">
|
||||||
|
<slot v-if="useSlot" />
|
||||||
|
<block v-else>
|
||||||
|
<text>{{ index }}</text>
|
||||||
|
</block>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* indexAnchor 索引列表锚点
|
||||||
|
* @description 通过折叠面板收纳内容区域,搭配<u-index-anchor>使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/indexList.html#indexanchor-props
|
||||||
|
* @property {Boolean} use-slot 是否使用自定义内容的插槽(默认false)
|
||||||
|
* @property {String Number} index 索引字符,如果定义了use-slot,此参数自动失效
|
||||||
|
* @property {Object} custStyle 自定义样式,对象形式,如"{color: 'red'}"
|
||||||
|
* @event {Function} default 锚点位置显示内容,默认为索引字符
|
||||||
|
* @example <u-index-anchor :index="item" />
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-index-anchor",
|
||||||
|
props: {
|
||||||
|
useSlot: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
index: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default () {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
active: false,
|
||||||
|
wrapperStyle: {},
|
||||||
|
anchorStyle: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.parent = false;
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.parent = this.$u.$parent.call(this, 'u-index-list');
|
||||||
|
if(this.parent) {
|
||||||
|
this.parent.children.push(this);
|
||||||
|
this.parent.updateData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
customAnchorStyle() {
|
||||||
|
return Object.assign(this.anchorStyle, this.customStyle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-index-anchor {
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 14rpx 24rpx;
|
||||||
|
color: #606266;
|
||||||
|
width: 100%;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 28rpx;
|
||||||
|
line-height: 1.2;
|
||||||
|
background-color: rgb(245, 245, 245);
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-index-anchor--active {
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
color: #2979ff;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
315
node_modules/uview-ui/components/u-index-list/u-index-list.vue
generated
vendored
Normal file
315
node_modules/uview-ui/components/u-index-list/u-index-list.vue
generated
vendored
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 支付宝小程序使用$u.getRect()获取组件的根元素尺寸,所以在外面套一个"壳" -->
|
||||||
|
<view>
|
||||||
|
<view class="u-index-bar">
|
||||||
|
<slot />
|
||||||
|
<view v-if="showSidebar" class="u-index-bar__sidebar" @touchstart.stop.prevent="onTouchMove" @touchmove.stop.prevent="onTouchMove"
|
||||||
|
@touchend.stop.prevent="onTouchStop" @touchcancel.stop.prevent="onTouchStop">
|
||||||
|
<view v-for="(item, index) in indexList" :key="index" class="u-index-bar__index" :style="{zIndex: zIndex + 1, color: activeAnchorIndex === index ? activeColor : ''}"
|
||||||
|
:data-index="index">
|
||||||
|
{{ item }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="u-indexed-list-alert" v-if="touchmove && indexList[touchmoveIndex]" :style="{
|
||||||
|
zIndex: alertZIndex
|
||||||
|
}">
|
||||||
|
<text>{{indexList[touchmoveIndex]}}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var indexList = function() {
|
||||||
|
var indexList = [];
|
||||||
|
var charCodeOfA = 'A'.charCodeAt(0);
|
||||||
|
for (var i = 0; i < 26; i++) {
|
||||||
|
indexList.push(String.fromCharCode(charCodeOfA + i));
|
||||||
|
}
|
||||||
|
return indexList;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* indexList 索引列表
|
||||||
|
* @description 通过折叠面板收纳内容区域,搭配<u-index-anchor>使用
|
||||||
|
* @tutorial https://www.uviewui.com/components/indexList.html#indexanchor-props
|
||||||
|
* @property {Number String} scroll-top 当前滚动高度,自定义组件无法获得滚动条事件,所以依赖接入方传入
|
||||||
|
* @property {Array} index-list 索引字符列表,数组(默认A-Z)
|
||||||
|
* @property {Number String} z-index 锚点吸顶时的层级(默认965)
|
||||||
|
* @property {Boolean} sticky 是否开启锚点自动吸顶(默认true)
|
||||||
|
* @property {Number String} offset-top 锚点自动吸顶时与顶部的距离(默认0)
|
||||||
|
* @property {String} highlight-color 锚点和右边索引字符高亮颜色(默认#2979ff)
|
||||||
|
* @event {Function} select 选中右边索引字符时触发
|
||||||
|
* @example <u-index-list :scrollTop="scrollTop"></u-index-list>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-index-list",
|
||||||
|
props: {
|
||||||
|
sticky: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
scrollTop: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
offsetTop: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
indexList: {
|
||||||
|
type: Array,
|
||||||
|
default () {
|
||||||
|
return indexList()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
activeColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#2979ff'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// #ifdef H5
|
||||||
|
this.stickyOffsetTop = this.offsetTop ? uni.upx2px(this.offsetTop) : 44;
|
||||||
|
// #endif
|
||||||
|
// #ifndef H5
|
||||||
|
this.stickyOffsetTop = this.offsetTop ? uni.upx2px(this.offsetTop) : 0;
|
||||||
|
// #endif
|
||||||
|
// 只能在created生命周期定义children,如果在data定义,会因为循环引用而报错
|
||||||
|
this.children = [];
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activeAnchorIndex: 0,
|
||||||
|
showSidebar: true,
|
||||||
|
// children: [],
|
||||||
|
touchmove: false,
|
||||||
|
touchmoveIndex: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
scrollTop() {
|
||||||
|
this.updateData()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 弹出toast的z-index值
|
||||||
|
alertZIndex() {
|
||||||
|
return this.$u.zIndex.toast;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
updateData() {
|
||||||
|
this.timer && clearTimeout(this.timer);
|
||||||
|
this.timer = setTimeout(() => {
|
||||||
|
this.showSidebar = !!this.children.length;
|
||||||
|
this.setRect().then(() => {
|
||||||
|
this.onScroll();
|
||||||
|
});
|
||||||
|
}, 0);
|
||||||
|
},
|
||||||
|
setRect() {
|
||||||
|
return Promise.all([
|
||||||
|
this.setAnchorsRect(),
|
||||||
|
this.setListRect(),
|
||||||
|
this.setSiderbarRect()
|
||||||
|
]);
|
||||||
|
},
|
||||||
|
setAnchorsRect() {
|
||||||
|
return Promise.all(this.children.map((anchor, index) => anchor
|
||||||
|
.$uGetRect('.u-index-anchor-wrapper')
|
||||||
|
.then((rect) => {
|
||||||
|
Object.assign(anchor, {
|
||||||
|
height: rect.height,
|
||||||
|
top: rect.top
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
},
|
||||||
|
setListRect() {
|
||||||
|
return this.$uGetRect('.u-index-bar').then((rect) => {
|
||||||
|
Object.assign(this, {
|
||||||
|
height: rect.height,
|
||||||
|
top: rect.top + this.scrollTop
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
setSiderbarRect() {
|
||||||
|
return this.$uGetRect('.u-index-bar__sidebar').then(rect => {
|
||||||
|
this.sidebar = {
|
||||||
|
height: rect.height,
|
||||||
|
top: rect.top
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getActiveAnchorIndex() {
|
||||||
|
const {
|
||||||
|
children
|
||||||
|
} = this;
|
||||||
|
const {
|
||||||
|
sticky
|
||||||
|
} = this;
|
||||||
|
for (let i = this.children.length - 1; i >= 0; i--) {
|
||||||
|
const preAnchorHeight = i > 0 ? children[i - 1].height : 0;
|
||||||
|
const reachTop = sticky ? preAnchorHeight : 0;
|
||||||
|
if (reachTop >= children[i].top) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
},
|
||||||
|
onScroll() {
|
||||||
|
const {
|
||||||
|
children = []
|
||||||
|
} = this;
|
||||||
|
if (!children.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {
|
||||||
|
sticky,
|
||||||
|
stickyOffsetTop,
|
||||||
|
zIndex,
|
||||||
|
scrollTop,
|
||||||
|
activeColor
|
||||||
|
} = this;
|
||||||
|
const active = this.getActiveAnchorIndex();
|
||||||
|
this.activeAnchorIndex = active;
|
||||||
|
if (sticky) {
|
||||||
|
let isActiveAnchorSticky = false;
|
||||||
|
if (active !== -1) {
|
||||||
|
isActiveAnchorSticky =
|
||||||
|
children[active].top <= 0;
|
||||||
|
}
|
||||||
|
children.forEach((item, index) => {
|
||||||
|
if (index === active) {
|
||||||
|
let wrapperStyle = '';
|
||||||
|
let anchorStyle = {
|
||||||
|
color: `${activeColor}`
|
||||||
|
};
|
||||||
|
if (isActiveAnchorSticky) {
|
||||||
|
wrapperStyle = {
|
||||||
|
height: `${children[index].height}px`
|
||||||
|
};
|
||||||
|
anchorStyle = {
|
||||||
|
position: 'fixed',
|
||||||
|
top: `${stickyOffsetTop}px`,
|
||||||
|
zIndex: `${zIndex ? zIndex : this.$u.zIndex.indexListSticky}`,
|
||||||
|
color: `${activeColor}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
item.active = active;
|
||||||
|
item.wrapperStyle = wrapperStyle;
|
||||||
|
item.anchorStyle = anchorStyle;
|
||||||
|
} else if (index === active - 1) {
|
||||||
|
const currentAnchor = children[index];
|
||||||
|
const currentOffsetTop = currentAnchor.top;
|
||||||
|
const targetOffsetTop = index === children.length - 1 ?
|
||||||
|
this.top :
|
||||||
|
children[index + 1].top;
|
||||||
|
const parentOffsetHeight = targetOffsetTop - currentOffsetTop;
|
||||||
|
const translateY = parentOffsetHeight - currentAnchor.height;
|
||||||
|
const anchorStyle = {
|
||||||
|
position: 'relative',
|
||||||
|
transform: `translate3d(0, ${translateY}px, 0)`,
|
||||||
|
zIndex: `${zIndex ? zIndex : this.$u.zIndex.indexListSticky}`,
|
||||||
|
color: `${activeColor}`
|
||||||
|
};
|
||||||
|
item.active = active;
|
||||||
|
item.anchorStyle = anchorStyle;
|
||||||
|
} else {
|
||||||
|
item.active = false;
|
||||||
|
item.anchorStyle = '';
|
||||||
|
item.wrapperStyle = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onTouchMove(event) {
|
||||||
|
this.touchmove = true;
|
||||||
|
const sidebarLength = this.children.length;
|
||||||
|
const touch = event.touches[0];
|
||||||
|
const itemHeight = this.sidebar.height / sidebarLength;
|
||||||
|
let clientY = 0;
|
||||||
|
clientY = touch.clientY;
|
||||||
|
let index = Math.floor((clientY - this.sidebar.top) / itemHeight);
|
||||||
|
if (index < 0) {
|
||||||
|
index = 0;
|
||||||
|
} else if (index > sidebarLength - 1) {
|
||||||
|
index = sidebarLength - 1;
|
||||||
|
}
|
||||||
|
this.touchmoveIndex = index;
|
||||||
|
this.scrollToAnchor(index);
|
||||||
|
},
|
||||||
|
onTouchStop() {
|
||||||
|
this.touchmove = false;
|
||||||
|
this.scrollToAnchorIndex = null;
|
||||||
|
},
|
||||||
|
scrollToAnchor(index) {
|
||||||
|
if (this.scrollToAnchorIndex === index) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.scrollToAnchorIndex = index;
|
||||||
|
const anchor = this.children.find((item) => item.index === this.indexList[index]);
|
||||||
|
if (anchor) {
|
||||||
|
this.$emit('select', anchor.index);
|
||||||
|
uni.pageScrollTo({
|
||||||
|
duration: 0,
|
||||||
|
scrollTop: anchor.top + this.scrollTop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-index-bar {
|
||||||
|
position: relative
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-index-bar__sidebar {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
right: 0;
|
||||||
|
@include vue-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
text-align: center;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
user-select: none;
|
||||||
|
z-index: 99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-index-bar__index {
|
||||||
|
font-weight: 500;
|
||||||
|
padding: 8rpx 18rpx;
|
||||||
|
font-size: 22rpx;
|
||||||
|
line-height: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-indexed-list-alert {
|
||||||
|
position: fixed;
|
||||||
|
width: 120rpx;
|
||||||
|
height: 120rpx;
|
||||||
|
right: 90rpx;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -60rpx;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
font-size: 50rpx;
|
||||||
|
color: #fff;
|
||||||
|
background-color: rgba(0, 0, 0, 0.65);
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0;
|
||||||
|
z-index: 9999999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-indexed-list-alert text {
|
||||||
|
line-height: 50rpx;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
387
node_modules/uview-ui/components/u-input/u-input.vue
generated
vendored
Normal file
387
node_modules/uview-ui/components/u-input/u-input.vue
generated
vendored
Normal file
@@ -0,0 +1,387 @@
|
|||||||
|
<template>
|
||||||
|
<view
|
||||||
|
class="u-input"
|
||||||
|
:class="{
|
||||||
|
'u-input--border': border,
|
||||||
|
'u-input--error': validateState
|
||||||
|
}"
|
||||||
|
:style="{
|
||||||
|
padding: `0 ${border ? 20 : 0}rpx`,
|
||||||
|
borderColor: borderColor,
|
||||||
|
textAlign: inputAlign
|
||||||
|
}"
|
||||||
|
@tap.stop="inputClick"
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
v-if="type == 'textarea'"
|
||||||
|
class="u-input__input u-input__textarea"
|
||||||
|
:style="[getStyle]"
|
||||||
|
:value="defaultValue"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:placeholderStyle="placeholderStyle"
|
||||||
|
:disabled="disabled"
|
||||||
|
:maxlength="inputMaxlength"
|
||||||
|
:fixed="fixed"
|
||||||
|
:focus="focus"
|
||||||
|
:autoHeight="autoHeight"
|
||||||
|
:selection-end="uSelectionEnd"
|
||||||
|
:selection-start="uSelectionStart"
|
||||||
|
:cursor-spacing="getCursorSpacing"
|
||||||
|
:show-confirm-bar="showConfirmbar"
|
||||||
|
@input="handleInput"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@focus="onFocus"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
v-else
|
||||||
|
class="u-input__input"
|
||||||
|
:type="type == 'password' ? 'text' : type"
|
||||||
|
:style="[getStyle]"
|
||||||
|
:value="defaultValue"
|
||||||
|
:password="type == 'password' && !showPassword"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
:placeholderStyle="placeholderStyle"
|
||||||
|
:disabled="disabled || type === 'select'"
|
||||||
|
:maxlength="inputMaxlength"
|
||||||
|
:focus="focus"
|
||||||
|
:confirmType="confirmType"
|
||||||
|
:cursor-spacing="getCursorSpacing"
|
||||||
|
:selection-end="uSelectionEnd"
|
||||||
|
:selection-start="uSelectionStart"
|
||||||
|
:show-confirm-bar="showConfirmbar"
|
||||||
|
@focus="onFocus"
|
||||||
|
@blur="handleBlur"
|
||||||
|
@input="handleInput"
|
||||||
|
@confirm="onConfirm"
|
||||||
|
/>
|
||||||
|
<view class="u-input__right-icon u-flex">
|
||||||
|
<view class="u-input__right-icon__clear u-input__right-icon__item" @tap="onClear" v-if="clearable && value != '' && focused">
|
||||||
|
<u-icon size="32" name="close-circle-fill" color="#c0c4cc"/>
|
||||||
|
</view>
|
||||||
|
<view class="u-input__right-icon__clear u-input__right-icon__item" v-if="passwordIcon && type == 'password'">
|
||||||
|
<u-icon size="32" :name="!showPassword ? 'eye' : 'eye-fill'" color="#c0c4cc" @click="showPassword = !showPassword"/>
|
||||||
|
</view>
|
||||||
|
<view class="u-input__right-icon--select u-input__right-icon__item" v-if="type == 'select'" :class="{
|
||||||
|
'u-input__right-icon--select--reverse': selectOpen
|
||||||
|
}">
|
||||||
|
<u-icon name="arrow-down-fill" size="26" color="#c0c4cc"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import Emitter from '../../libs/util/emitter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* input 输入框
|
||||||
|
* @description 此组件为一个输入框,默认没有边框和样式,是专门为配合表单组件u-form而设计的,利用它可以快速实现表单验证,输入内容,下拉选择等功能。
|
||||||
|
* @tutorial http://uviewui.com/components/input.html
|
||||||
|
* @property {String} type 模式选择,见官网说明
|
||||||
|
* @property {Boolean} clearable 是否显示右侧的清除图标(默认true)
|
||||||
|
* @property {} v-model 用于双向绑定输入框的值
|
||||||
|
* @property {String} input-align 输入框文字的对齐方式(默认left)
|
||||||
|
* @property {String} placeholder placeholder显示值(默认 '请输入内容')
|
||||||
|
* @property {Boolean} disabled 是否禁用输入框(默认false)
|
||||||
|
* @property {String Number} maxlength 输入框的最大可输入长度(默认140)
|
||||||
|
* @property {String Number} selection-start 光标起始位置,自动聚焦时有效,需与selection-end搭配使用(默认-1)
|
||||||
|
* @property {String Number} maxlength 光标结束位置,自动聚焦时有效,需与selection-start搭配使用(默认-1)
|
||||||
|
* @property {String Number} cursor-spacing 指定光标与键盘的距离,单位px(默认0)
|
||||||
|
* @property {String} placeholderStyle placeholder的样式,字符串形式,如"color: red;"(默认 "color: #c0c4cc;")
|
||||||
|
* @property {String} confirm-type 设置键盘右下角按钮的文字,仅在type为text时生效(默认done)
|
||||||
|
* @property {Object} custom-style 自定义输入框的样式,对象形式
|
||||||
|
* @property {Boolean} focus 是否自动获得焦点(默认false)
|
||||||
|
* @property {Boolean} fixed 如果type为textarea,且在一个"position:fixed"的区域,需要指明为true(默认false)
|
||||||
|
* @property {Boolean} password-icon type为password时,是否显示右侧的密码查看图标(默认true)
|
||||||
|
* @property {Boolean} border 是否显示边框(默认false)
|
||||||
|
* @property {String} border-color 输入框的边框颜色(默认#dcdfe6)
|
||||||
|
* @property {Boolean} auto-height 是否自动增高输入区域,type为textarea时有效(默认true)
|
||||||
|
* @property {String Number} height 高度,单位rpx(text类型时为70,textarea时为100)
|
||||||
|
* @example <u-input v-model="value" :type="type" :border="border" />
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: 'u-input',
|
||||||
|
mixins: [Emitter],
|
||||||
|
props: {
|
||||||
|
value: {
|
||||||
|
type: [String, Number],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 输入框的类型,textarea,text,number
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
default: 'text'
|
||||||
|
},
|
||||||
|
inputAlign: {
|
||||||
|
type: String,
|
||||||
|
default: 'left'
|
||||||
|
},
|
||||||
|
placeholder: {
|
||||||
|
type: String,
|
||||||
|
default: '请输入内容'
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
maxlength: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 140
|
||||||
|
},
|
||||||
|
placeholderStyle: {
|
||||||
|
type: String,
|
||||||
|
default: 'color: #c0c4cc;'
|
||||||
|
},
|
||||||
|
confirmType: {
|
||||||
|
type: String,
|
||||||
|
default: 'done'
|
||||||
|
},
|
||||||
|
// 输入框的自定义样式
|
||||||
|
customStyle: {
|
||||||
|
type: Object,
|
||||||
|
default() {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 如果 textarea 是在一个 position:fixed 的区域,需要显示指定属性 fixed 为 true
|
||||||
|
fixed: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否自动获得焦点
|
||||||
|
focus: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 密码类型时,是否显示右侧的密码图标
|
||||||
|
passwordIcon: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// input|textarea是否显示边框
|
||||||
|
border: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 输入框的边框颜色
|
||||||
|
borderColor: {
|
||||||
|
type: String,
|
||||||
|
default: '#dcdfe6'
|
||||||
|
},
|
||||||
|
autoHeight: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// type=select时,旋转右侧的图标,标识当前处于打开还是关闭select的状态
|
||||||
|
// open-打开,close-关闭
|
||||||
|
selectOpen: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 高度,单位rpx
|
||||||
|
height: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否可清空
|
||||||
|
clearable: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 指定光标与键盘的距离,单位 px
|
||||||
|
cursorSpacing: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: 0
|
||||||
|
},
|
||||||
|
// 光标起始位置,自动聚焦时有效,需与selection-end搭配使用
|
||||||
|
selectionStart: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
// 光标结束位置,自动聚焦时有效,需与selection-start搭配使用
|
||||||
|
selectionEnd: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: -1
|
||||||
|
},
|
||||||
|
// 是否自动去除两端的空格
|
||||||
|
trim: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示键盘上方带有”完成“按钮那一栏
|
||||||
|
showConfirmbar:{
|
||||||
|
type:Boolean,
|
||||||
|
default:true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
defaultValue: this.value,
|
||||||
|
inputHeight: 70, // input的高度
|
||||||
|
textareaHeight: 100, // textarea的高度
|
||||||
|
validateState: false, // 当前input的验证状态,用于错误时,边框是否改为红色
|
||||||
|
focused: false, // 当前是否处于获得焦点的状态
|
||||||
|
showPassword: false, // 是否预览密码
|
||||||
|
lastValue: '', // 用于头条小程序,判断@input中,前后的值是否发生了变化,因为头条中文下,按下键没有输入内容,也会触发@input时间
|
||||||
|
};
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
value(nVal, oVal) {
|
||||||
|
this.defaultValue = nVal;
|
||||||
|
// 当值发生变化,且为select类型时(此时input被设置为disabled,不会触发@input事件),模拟触发@input事件
|
||||||
|
if(nVal != oVal && this.type == 'select') this.handleInput({
|
||||||
|
detail: {
|
||||||
|
value: nVal
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 因为uniapp的input组件的maxlength组件必须要数值,这里转为数值,给用户可以传入字符串数值
|
||||||
|
inputMaxlength() {
|
||||||
|
return Number(this.maxlength);
|
||||||
|
},
|
||||||
|
getStyle() {
|
||||||
|
let style = {};
|
||||||
|
// 如果没有自定义高度,就根据type为input还是textare来分配一个默认的高度
|
||||||
|
style.minHeight = this.height ? this.height + 'rpx' : this.type == 'textarea' ?
|
||||||
|
this.textareaHeight + 'rpx' : this.inputHeight + 'rpx';
|
||||||
|
style = Object.assign(style, this.customStyle);
|
||||||
|
return style;
|
||||||
|
},
|
||||||
|
//
|
||||||
|
getCursorSpacing() {
|
||||||
|
return Number(this.cursorSpacing);
|
||||||
|
},
|
||||||
|
// 光标起始位置
|
||||||
|
uSelectionStart() {
|
||||||
|
return String(this.selectionStart);
|
||||||
|
},
|
||||||
|
// 光标结束位置
|
||||||
|
uSelectionEnd() {
|
||||||
|
return String(this.selectionEnd);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
// 监听u-form-item发出的错误事件,将输入框边框变红色
|
||||||
|
this.$on('on-form-item-error', this.onFormItemError);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
/**
|
||||||
|
* change 事件
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
handleInput(event) {
|
||||||
|
let value = event.detail.value;
|
||||||
|
// 判断是否去除空格
|
||||||
|
if(this.trim) value = this.$u.trim(value);
|
||||||
|
// vue 原生的方法 return 出去
|
||||||
|
this.$emit('input', value);
|
||||||
|
// 当前model 赋值
|
||||||
|
this.defaultValue = value;
|
||||||
|
// 过一个生命周期再发送事件给u-form-item,否则this.$emit('input')更新了父组件的值,但是微信小程序上
|
||||||
|
// 尚未更新到u-form-item,导致获取的值为空,从而校验混论
|
||||||
|
// 这里不能延时时间太短,或者使用this.$nextTick,否则在头条上,会造成混乱
|
||||||
|
setTimeout(() => {
|
||||||
|
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
if(this.$u.trim(value) == this.lastValue) return ;
|
||||||
|
this.lastValue = value;
|
||||||
|
// #endif
|
||||||
|
// 将当前的值发送到 u-form-item 进行校验
|
||||||
|
this.dispatch('u-form-item', 'on-form-change', value);
|
||||||
|
}, 40)
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* blur 事件
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
handleBlur(event) {
|
||||||
|
// 最开始使用的是监听图标@touchstart事件,自从hx2.8.4后,此方法在微信小程序出错
|
||||||
|
// 这里改为监听点击事件,手点击清除图标时,同时也发生了@blur事件,导致图标消失而无法点击,这里做一个延时
|
||||||
|
setTimeout(() => {
|
||||||
|
this.focused = false;
|
||||||
|
}, 100)
|
||||||
|
// vue 原生的方法 return 出去
|
||||||
|
this.$emit('blur', event.detail.value);
|
||||||
|
setTimeout(() => {
|
||||||
|
// 头条小程序由于自身bug,导致中文下,每按下一个键(尚未完成输入),都会触发一次@input,导致错误,这里进行判断处理
|
||||||
|
// #ifdef MP-TOUTIAO
|
||||||
|
if(this.$u.trim(value) == this.lastValue) return ;
|
||||||
|
this.lastValue = value;
|
||||||
|
// #endif
|
||||||
|
// 将当前的值发送到 u-form-item 进行校验
|
||||||
|
this.dispatch('u-form-item', 'on-form-blur', event.detail.value);
|
||||||
|
}, 40)
|
||||||
|
},
|
||||||
|
onFormItemError(status) {
|
||||||
|
this.validateState = status;
|
||||||
|
},
|
||||||
|
onFocus(event) {
|
||||||
|
this.focused = true;
|
||||||
|
this.$emit('focus');
|
||||||
|
},
|
||||||
|
onConfirm(e) {
|
||||||
|
this.$emit('confirm', e.detail.value);
|
||||||
|
},
|
||||||
|
onClear(event) {
|
||||||
|
this.$emit('input', '');
|
||||||
|
},
|
||||||
|
inputClick() {
|
||||||
|
this.$emit('click');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-input {
|
||||||
|
position: relative;
|
||||||
|
flex: 1;
|
||||||
|
@include vue-flex;
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
//height: $u-form-item-height;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__textarea {
|
||||||
|
width: auto;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: $u-main-color;
|
||||||
|
padding: 10rpx 0;
|
||||||
|
line-height: normal;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--border {
|
||||||
|
border-radius: 6rpx;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid $u-form-item-border-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--error {
|
||||||
|
border-color: $u-type-error!important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__right-icon {
|
||||||
|
|
||||||
|
&__item {
|
||||||
|
margin-left: 10rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--select {
|
||||||
|
transition: transform .4s;
|
||||||
|
|
||||||
|
&--reverse {
|
||||||
|
transform: rotate(-180deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
217
node_modules/uview-ui/components/u-keyboard/u-keyboard.vue
generated
vendored
Normal file
217
node_modules/uview-ui/components/u-keyboard/u-keyboard.vue
generated
vendored
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
<template>
|
||||||
|
<u-popup class="" :mask="mask" :maskCloseAble="maskCloseAble" mode="bottom" :popup="false" v-model="value" length="auto"
|
||||||
|
:safeAreaInsetBottom="safeAreaInsetBottom" @close="popupClose" :zIndex="uZIndex">
|
||||||
|
<slot />
|
||||||
|
<view class="u-tooltip" v-if="tooltip">
|
||||||
|
<view class="u-tooltip-item u-tooltip-cancel" hover-class="u-tooltip-cancel-hover" @tap="onCancel">
|
||||||
|
{{cancelBtn ? cancelText : ''}}
|
||||||
|
</view>
|
||||||
|
<view v-if="showTips" class="u-tooltip-item u-tooltip-tips">
|
||||||
|
{{tips ? tips : mode == 'number' ? '数字键盘' : mode == 'card' ? '身份证键盘' : '车牌号键盘'}}
|
||||||
|
</view>
|
||||||
|
<view v-if="confirmBtn" @tap="onConfirm" class="u-tooltip-item u-tooltips-submit" hover-class="u-tooltips-submit-hover">
|
||||||
|
{{confirmBtn ? confirmText : ''}}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<block v-if="mode == 'number' || mode == 'card'">
|
||||||
|
<u-number-keyboard :random="random" @backspace="backspace" @change="change" :mode="mode" :dotEnabled="dotEnabled"></u-number-keyboard>
|
||||||
|
</block>
|
||||||
|
<block v-else>
|
||||||
|
<u-car-keyboard :random="random" @backspace="backspace" @change="change"></u-car-keyboard>
|
||||||
|
</block>
|
||||||
|
</u-popup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
/**
|
||||||
|
* keyboard 键盘
|
||||||
|
* @description 此为uViw自定义的键盘面板,内含了数字键盘,车牌号键,身份证号键盘3中模式,都有可以打乱按键顺序的选项。
|
||||||
|
* @tutorial https://www.uviewui.com/components/keyboard.html
|
||||||
|
* @property {String} mode 键盘类型,见官网基本使用的说明(默认number)
|
||||||
|
* @property {Boolean} dot-enabled 是否显示"."按键,只在mode=number时有效(默认true)
|
||||||
|
* @property {Boolean} tooltip 是否显示键盘顶部工具条(默认true)
|
||||||
|
* @property {String} tips 工具条中间的提示文字,见上方基本使用的说明,如不需要,请传""空字符
|
||||||
|
* @property {Boolean} cancel-btn 是否显示工具条左边的"取消"按钮(默认true)
|
||||||
|
* @property {Boolean} confirm-btn 是否显示工具条右边的"完成"按钮(默认true)
|
||||||
|
* @property {Boolean} mask 是否显示遮罩(默认true)
|
||||||
|
* @property {String} confirm-text 确认按钮的文字
|
||||||
|
* @property {String} cancel-text 取消按钮的文字
|
||||||
|
* @property {Number String} z-index 弹出键盘的z-index值(默认1075)
|
||||||
|
* @property {Boolean} random 是否打乱键盘按键的顺序(默认false)
|
||||||
|
* @property {Boolean} safe-area-inset-bottom 是否开启底部安全区适配(默认false)
|
||||||
|
* @property {Boolean} mask-close-able 是否允许点击遮罩收起键盘(默认true)
|
||||||
|
* @event {Function} change 按键被点击(不包含退格键被点击)
|
||||||
|
* @event {Function} cancel 键盘顶部工具条左边的"取消"按钮被点击
|
||||||
|
* @event {Function} confirm 键盘顶部工具条右边的"完成"按钮被点击
|
||||||
|
* @event {Function} backspace 键盘退格键被点击
|
||||||
|
* @example <u-keyboard mode="number" v-model="show"></u-keyboard>
|
||||||
|
*/
|
||||||
|
export default {
|
||||||
|
name: "u-keyboard",
|
||||||
|
props: {
|
||||||
|
// 键盘的类型,number-数字键盘,card-身份证键盘,car-车牌号键盘
|
||||||
|
mode: {
|
||||||
|
type: String,
|
||||||
|
default: 'number'
|
||||||
|
},
|
||||||
|
// 是否显示键盘的"."符号
|
||||||
|
dotEnabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示顶部工具条
|
||||||
|
tooltip: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示工具条中间的提示
|
||||||
|
showTips: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 工具条中间的提示文字
|
||||||
|
tips: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 是否显示工具条左边的"取消"按钮
|
||||||
|
cancelBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否显示工具条右边的"完成"按钮
|
||||||
|
confirmBtn: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 是否打乱键盘按键的顺序
|
||||||
|
random: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否开启底部安全区适配,开启的话,会在iPhoneX机型底部添加一定的内边距
|
||||||
|
safeAreaInsetBottom: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否允许通过点击遮罩关闭键盘
|
||||||
|
maskCloseAble: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// 通过双向绑定控制键盘的弹出与收起
|
||||||
|
value: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
// 是否显示遮罩,某些时候数字键盘时,用户希望看到自己的数值,所以可能不想要遮罩
|
||||||
|
mask: {
|
||||||
|
type: Boolean,
|
||||||
|
default: true
|
||||||
|
},
|
||||||
|
// z-index值
|
||||||
|
zIndex: {
|
||||||
|
type: [Number, String],
|
||||||
|
default: ''
|
||||||
|
},
|
||||||
|
// 取消按钮的文字
|
||||||
|
cancelText: {
|
||||||
|
type: String,
|
||||||
|
default: '取消'
|
||||||
|
},
|
||||||
|
// 确认按钮的文字
|
||||||
|
confirmText: {
|
||||||
|
type: String,
|
||||||
|
default: '确认'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
//show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
uZIndex() {
|
||||||
|
return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
change(e) {
|
||||||
|
this.$emit('change', e);
|
||||||
|
},
|
||||||
|
// 键盘关闭
|
||||||
|
popupClose() {
|
||||||
|
// 通过发送input这个特殊的事件名,可以修改父组件传给props的value的变量,也即双向绑定
|
||||||
|
this.$emit('input', false);
|
||||||
|
},
|
||||||
|
// 输入完成
|
||||||
|
onConfirm() {
|
||||||
|
this.popupClose();
|
||||||
|
this.$emit('confirm');
|
||||||
|
},
|
||||||
|
// 取消输入
|
||||||
|
onCancel() {
|
||||||
|
this.popupClose();
|
||||||
|
this.$emit('cancel');
|
||||||
|
},
|
||||||
|
// 退格键
|
||||||
|
backspace() {
|
||||||
|
this.$emit('backspace');
|
||||||
|
},
|
||||||
|
// 关闭键盘
|
||||||
|
// close() {
|
||||||
|
// this.show = false;
|
||||||
|
// },
|
||||||
|
// // 打开键盘
|
||||||
|
// open() {
|
||||||
|
// this.show = true;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
@import "../../libs/css/style.components.scss";
|
||||||
|
|
||||||
|
.u-keyboard {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1003;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltip {
|
||||||
|
@include vue-flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltip-item {
|
||||||
|
color: #333333;
|
||||||
|
flex: 0 0 33.333333%;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20rpx 10rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltips-submit {
|
||||||
|
text-align: right;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-wrap: 0;
|
||||||
|
padding-right: 40rpx;
|
||||||
|
color: $u-type-primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltip-cancel {
|
||||||
|
text-align: left;
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-wrap: 0;
|
||||||
|
padding-left: 40rpx;
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltips-submit-hover {
|
||||||
|
color: $u-type-success;
|
||||||
|
}
|
||||||
|
|
||||||
|
.u-tooltip-cancel-hover {
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user