提交 3da6e402 作者: wk

第一次提交

父级 e8ef97ef
/unpackage/
{ // launch.json 配置了启动调试时相关设置,configurations下节点名称可为 app-plus/h5/mp-weixin/mp-baidu/mp-alipay/mp-qq/mp-toutiao/mp-360/
// launchtype项可配置值为local或remote, local代表前端连本地云函数,remote代表前端连云端云函数
"version": "0.0",
"configurations": [{
"default" :
{
"launchtype" : "local"
},
"mp-weixin" :
{
"launchtype" : "local"
},
"type" : "uniCloud"
}
]
}
<script>
export default {
onLaunch: function() {
console.log('App Launch')
},
onShow: function() {
console.log('App Show')
},
onHide: function() {
console.log('App Hide')
}
}
</script>
<style>
/*每个页面公共css */
page {
background-color: #F5F5F5;
}
</style>
import {
buildParam
} from "./param.js"
const params = {
}
export default buildParam(params)
let base = "https://console-api.waspring.com/"
// let base = "https://console-api.wringcloud.com/"
const http = (params) => {
return new Promise((resolve, reject) => {
uni.request({
url: base + params.url,
method: params.method,
data: params.data,
header: {
'access_token': uni.getStorageSync('token') || '',
"token": uni.getStorageSync('token') || ''
},
success(res) {
uni.hideLoading()
let result = res.data
if (result.code == 0) {
resolve(result)
} else if (result.code == 10201) { //token失效
getApp().globalData.isLoginAgain = true
uni.navigateTo({
url: "/pages/wxLogin/wxLogin"
})
} else if (result.code == 33199) {
resolve(result)
}
},
fail(err) {
reject(err)
}
})
})
}
export {
http
}
import {
http
} from "./http.js"
function buildParam(params) {
const data = {}
for (let prop in params) {
data[prop] = (options) => {
return request(options, params[prop])
}
}
return data
}
function request(options, setting) {
if (typeof options === 'object') {
Object.assign(setting, options)
}
return http(setting)
}
export {
buildParam
}
const $config = {
pwdTemplateNo: "SMS_166720076",
loginTemplateNo: "SMS_133860272",
systemCode: "college",
authCode: "494BBE85-A6AD-392F-5628-12B39F649333", //开发CED4DE04-BA74-81DF-E51E-9864E4FD0DCB 测试:494BBE85-A6AD-392F-5628-12B39F649333 正式:D0539533-E169-5338-8ED7-3FAD554F4F62
pageSize: 20,
isPage: 1,
smsCfg: "college"
}
export default $config
# 轮播组件
# 基础式
<ls-swiper :list="base_lsit" imgKey="imgUrl" :loop="true" :dots='true' :autoplay='true' @clickItem="clickItem()" />
# 链式
<ls-swiper :list="list" imgKey="imgUrl" imgWidth="300" previousMargin="20" nextMargin='20'/>
# 卡片式
<ls-swiper :list="base_lsit" imgKey="imgUrl" :crown="true" :loop="true" :shadow='true' height='130' previousMargin="120" nextMargin='120' imgRadius="5" />
# props
参数名 | 说明 | 类型 | 默认值
-----------------|-------------------------------------------------- -|-------------|------------
list | 轮播数据 | Array | 必输
imgKey | 轮播数据key(图片url属性) | String | 必输 (自定义模式,非必输)
autoplay | 是否自动播放 | Boolean | false
loop | 是否循环 | Boolean | false
autoplay | 是否自动播放 | Boolean | false
dots | 是否显示轮播点 | Boolean | false
crown | 卡片特效 (中间突出,两边缩放特效) | Boolean | false
interval | 播放时间间隔 | Number | 2000
duration | 滑动速度 | Number | 1500
bottom | 轮播点下边距 | Number | 10 (单位:px,设计图建议以375px为准)
height | 高度 | Number | 200 (单位:px,设计图建议以375px为准)
previousMargin | 图片前边距 | Number | 0 (单位:px,设计图建议以375px为准)
nextMargin | 图片后间距 | Number | 0 (单位:px,设计图建议以375px为准)
imgRadius | 图片圆角 | Number | 0 (单位:px,设计图建议以375px为准)
imgWidth | 图片宽度 | String | 100%
@clickItem | 点击事件 | Function |
@change | 切换事件 | Function |
# 自定义
<ls-swiper :list="list">
<template v-slot="{data}">
xxx
</template>
</ls-swiper>
如有其他需求,可在插槽内编写自定义内容, 自动覆盖原图片样式。
\ No newline at end of file
<template>
<view class="wrap">
<swiper class="swiper" :style="{height: height *2 + 'rpx'}" :autoplay="autoplay" :interval="interval"
:duration="duration" :circular='loop' @change='change' :previous-margin='previousMargin + "rpx"'
:next-margin='nextMargin + "rpx"'>
<swiper-item v-for="(item,index) in list" :key='index' @click="$emit('clickItem',item)">
<view v-if="list && list.length>0" class="item"
:class="[!crown ? '' : current==index ? 'crown-active':'crown']">
<image v-if="!slots" class="item-img" :class="[imgShadow?'imgShadow':'']" :src="item[imgKey]"
:style="{ borderRadius: imgRadius + 'px',width:imgWidth}" mode=""></image>
<slot v-else :data='item'></slot>
</view>
</swiper-item>
</swiper>
<view class="dots flex" :style="{bottom: bottom * 2 + 'rpx'}" v-if="dots">
<view class="dot" :class="[current == i ? 'curr-dot' : '']" v-for="(d,i) in list" :key='i'>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
list: {
type: Array,
default: () => []
},
// 轮播图片key
imgKey: {
type: String,
required: true
},
// 高度
height: {
type: Number,
default: 200
},
// 图片圆角
imgRadius: {
type: Number,
default: 0
},
// 图片阴影
imgShadow: {
type: Boolean,
default: false
},
// 前边距
previousMargin: {
type: Number,
default: 0
},
// 后边距
nextMargin: {
type: Number,
default: 0
},
// 图片宽度
imgWidth: {
type: String,
default: '100%'
},
// 是否循环
loop: {
type: Boolean,
default: false
},
// 自动播放
autoplay: {
type: Boolean,
default: false
},
// 播放时间间隔
interval: {
type: Number,
default: 2000
},
// 滑动速度
duration: {
type: Number,
default: 1200
},
// 显示指示点
dots: {
type: Boolean,
default: false
},
// 轮播点下边距
bottom: {
type: Number,
default: 10
},
// 卡片特效
crown: {
type: Boolean,
default: false
},
},
data() {
return {
current: 0,
slots: false
};
},
watch: {
// 判断异步数据源,是否使用插槽自定义样式
list: {
handler(val) {
if (val.length > 0 && this.$slots.default) {
this.slots = true
}
},
immediate: true,
}
},
methods: {
change(event) {
let current = event.detail.current
this.current = current
this.$emit('change', this.list[current])
}
}
}
</script>
<style lang="scss" scoped>
.wrap {
position: relative;
background-color: #04A097;
.crown {
transform: scale(0.93, 0.85);
}
.item {
height: 100%;
transition: 1.2s;
}
.item-img {
width: 100%;
height: 100%;
}
.imgShadow {
height: calc(100% - 10px);
margin-bottom: 10px;
box-shadow: 0 6px 6px rgba(0, 0, 0, .15);
}
.crown-active {
transform: scale(1);
}
.dots {
display: flex;
position: absolute;
left: 50%;
transform: translateX(-50%);
.dot {
width: 6rpx;
height: 6rpx;
border-radius: 50%;
background-color: #D6D6D6;
margin-right: 8rpx;
}
.curr-dot {
height: 6rpx;
width: 22rpx;
border-radius: 6rpx;
background-color: #fff;
}
}
}
</style>
<template>
<view class="navbar-home">
<view class="navbar-content">
<view :style="{height:statusBarHeight+'px'}"></view>
<view class="navbar-v-navbar" :style="{width:screenWidth+'px',height:titlebarHeight+'px'}">
<view class="navbar-v-content">
<view class="navbar-v-back" v-if="showBack" @click="finish">
<image src="../../static/ic_arrow_back.png" style="width: 24px;height: 24px;"></image>
</view>
<view class="navbar-v-title">{{title}}</view>
</view>
</view>
</view>
<view :style="{height:statusBarHeight + titlebarHeight +'px'}"></view>
</view>
</template>
<script>
export default {
props: {
title: {
type: String,
default: '首页'
},
showBack: {
type: Boolean,
default: false
}
},
data() {
return {
screenWidth: 325,
statusBarHeight: 20,
titlebarHeight: 45
};
},
created() {
const info = uni.getSystemInfoSync()
this.screenWidth = info.screenWidth
this.statusBarHeight = info.statusBarHeight
console.log(info);
//#ifdef MP-WEIXIN
const menu = uni.getMenuButtonBoundingClientRect()
this.titlebarHeight = (menu.bottom - info.statusBarHeight) + (menu.top - info.statusBarHeight)
console.log(menu.bottom);
this.screenWidth = menu.left
//#endif
console.log(this.titlebarHeight);
},
methods: {
// // 返回app列表页
// back(){
// uni.redirectTo({
// url:'../app-list/app-list'
// })
// },
// finish() {
// uni.navigateBack({
// delta: 1
// })
// }
},
}
</script>
<style lang="scss">
.navbar-home {
.navbar-content {
position: fixed;
top: 0;
left: 0;
margin-bottom: 16px;
width: 100%;
.navbar-v-navbar {
display: flex;
justify-content: center;
align-items: center;
height: 45px;
width: 100%;
box-sizing: border-box;
.navbar-v-content {
display: flex;
align-items: center;
width: 100%;
padding: 10px;
box-sizing: border-box;
.navbar-v-back {
display: flex;
align-items: center;
justify-content: center;
}
.navbar-v-title {
font-family: "PingFang SC";
font-weight: 400;
font-size: 34rpx;
text-align: left;
color: #fff;
}
}
}
}
}
</style>
<template>
<view>
<view class="tabbar-container" :class="isIpx?'IpxBot':''">
<view class="tabbar-item" v-for="(item,index) in tabList" :class="[item.centerItem ? 'center-item' : '']"
@click="changeItem(item)" :key="index">
<view class="item-top" :style="{padding: item.id == 2?0:'10rpx'}">
<image :src="tabId==item.id?item.selectIcon:item.icon" mode=""></image>
</view>
<view class="item-bottom" :class="[tabId==item.id ? 'item-active' : '']">
<text>{{item.text}}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
props: {
currentPage: {
type: Number,
default: 0
}
},
data() {
return {
//适配IPhoneX
isIpx: true,
//底部Tab
tabId: 0,
tabList: [{
id: 0,
path: "/pages/index/index",
icon: "/static/home-sel.png",
selectIcon: "/static/home-sel.png",
text: "首页",
centerItem: false
}, {
id: 1,
path: "/pages/gallery/gallery",
icon: "/static/gallery.png",
selectIcon: "/static/gallery-sel.png",
text: "工作台",
centerItem: false
}, {
icon: "/static/scan.png",
selectIcon: "/static/scan.png",
centerItem: true
}, {
id: 2,
path: "/pages/monitor/monitor",
icon: "/static/monitor.png",
selectIcon: "/static/monitor-sel.png",
text: "监控台",
centerItem: false
}, {
id: 3,
path: "/pages/mine/mine",
icon: "/static/mine.png",
selectIcon: "/static/mine-sel.png",
text: "我的",
centerItem: false
}],
};
},
mounted() {
this.tabId = this.currentPage;
//隐藏原生tab
uni.hideTabBar();
},
created() {
// 判断为 iPhone X 给予底部距离
let that = this
uni.getSystemInfo({
success: function(res) {
if (res.model.indexOf('iPhone X') !== -1) {
that.isIpx = true;
}
}
})
},
methods: {
// tab 切换
changeItem(item) {
uni.switchTab({
url: item.path,
});
},
}
}
</script>
<style scoped>
view {
padding: 0;
margin: 0;
box-sizing: border-box;
}
.tabbar-container {
position: fixed;
bottom: 0;
left: 0;
width: 100%;
/* height: 100rpx; */
/* box-shadow: 0 0 5px #999; */
display: flex;
align-items: center;
padding: 5rpx 0;
color: #999999;
background-color: #FFFFFF;
}
.tabbar-container .tabbar-item {
width: 20%;
height: 104rpx;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
.tabbar-container .item-active {
color: #0B5794;
}
.tabbar-container .center-item {
display: block;
position: relative;
}
.tabbar-container .tabbar-item .item-top {
width: 70rpx;
height: 70rpx;
padding: 5rpx;
}
.tabbar-container .center-item .item-top {
flex-shrink: 0;
width: 130rpx;
height: 130rpx;
position: absolute;
top: -50rpx;
/* left: calc(50% - 70rpx); */
border-radius: 50%;
background-color: #FFFFFF;
}
.tabbar-container .tabbar-item .item-top image {
width: 100%;
height: 100%;
}
.tabbar-container .tabbar-item .item-bottom {
font-size: 25rpx;
width: 100%;
}
.tabbar-container .center-item .item-bottom {
position: absolute;
bottom: 2rpx;
}
/* 适配iPhone X */
.IpxBot {
padding-bottom: 30rpx !important;
}
</style>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<script>
var coverSupport = 'CSS' in window && typeof CSS.supports === 'function' && (CSS.supports('top: env(a)') ||
CSS.supports('top: constant(a)'))
document.write(
'<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' +
(coverSupport ? ', viewport-fit=cover' : '') + '" />')
</script>
<title></title>
<!--preload-links-->
<!--app-context-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/main.js"></script>
</body>
</html>
import App from './App'
// #ifndef VUE3
import Vue from 'vue'
import tabBar from 'components/uni-tabbar/uni-tabbar.vue'
Vue.component('tabBar', tabBar)
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
{
"name" : "site-uniapp",
"appid" : "__UNI__EB20610",
"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"
}
{
"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "uni-app",
"navigationStyle": "custom"
}
}, {
"path": "pages/login/wxLogin/wxLogin",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/login/login/login",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/gallery/gallery",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/monitor/monitor",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}, {
"path": "pages/mine/mine",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {},
"tabBar": {
"backgroundColor": "#FFFFFF",
"color": "#333333",
"selectedColor": "#3B73FE",
"list": [{
"pagePath": "pages/index/index"
},
{
"pagePath": "pages/gallery/gallery"
},
{
"pagePath": "pages/monitor/monitor"
}, {
"pagePath": "pages/mine/mine"
}
]
}
}
<template>
<view>
<uni-tabbar currentPage="1"></uni-tabbar>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>
<template>
<view class="content">
<view class="header-content">
<image src="../../static/home-head.png" class="header-image"></image>
<navbar :title="title"></navbar>
<!-- 天气 -->
<view class="weather-content" :style="{top:statusBarHeight+36+'px'}">
<view class="temp-content">
<view class="temp">25.6℃</view>
<view class="weather">多云转晴</view>
</view>
<view class="line"></view>
<view class="login-info-content">
<view class="login-info">XXXX,欢迎登陆</view>
<view class="address-content">
<image src="../../static/loc.png" class="loc-image"></image>
<view class="address">浙江省杭州市西湖区</view>
</view>
</view>
</view>
<view class="banner-content" :style="{top:statusBarHeight+116+'px'}">
<ls-swiper :list="banners" imgKey="url" :loop="true" :dots='true' :autoplay='true' height='142'
@clickItem="clickItem()" />
</view>
</view>
<!-- 工地头条 -->
<view class="top-new-content">
<image src="../../static/notice.png" class="image"></image>
<view class="title">工地头条</view>
<view class="new-content">关于食堂发放免费午餐的人员名单关于食堂发放免费午餐的人员名单</view>
<image src="../../static/right-arrow.png" class="right-arrow"></image>
</view>
<!-- 常用应用 -->
<view class="bus-content">
<view class="tab-content">
<view class="tab-item">
<view :class="isCommonSel?'tab-text-sel':'tab-text'">常用业务</view>
<view class="tab-line" v-if="isCommonSel"></view>
</view>
<view class="tab-item">
<view :class="isRecentlySel?'tab-text-sel':'tab-text'">最进访问业务</view>
<view class="tab-line" v-if="isRecentlySel"></view>
</view>
</view>
</view>
<uni-tabbar currentPage="0"></uni-tabbar>
</view>
</template>
<script>
export default {
data() {
return {
title: '欢迎XXX访问一点通',
banners: [],
statusBarHeight: 20,
isCommonSel: true,
isRecentlySel: false
}
},
onLoad() {
const info = uni.getSystemInfoSync()
this.statusBarHeight = info.statusBarHeight
},
methods: {
}
}
</script>
<style lang="scss">
.content {
display: flex;
flex-direction: column;
.scan-image {
position: fixed;
bottom: -50rpx;
z-index: 99;
height: 100rpx;
width: 100rpx;
}
.header-content {
position: relative;
top: 0;
left: 0;
.header-image {
width: 750rpx;
height: 504rpx;
position: absolute;
top: 0;
left: 0;
}
.weather-content {
position: absolute;
display: flex;
top: 120rpx;
align-items: center;
padding: 32rpx 44rpx;
left: 0;
flex-direction: row;
.temp-content {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-end;
.temp {
font-family: "Arial-BoldMT ";
font-weight: 400;
font-size: 36rpx;
text-align: left;
color: #fff;
}
.weather {
font-family: "MicrosoftYaHei-Bold ";
font-weight: 400;
font-size: 20rpx;
margin-top: 8rpx;
text-align: left;
color: #fff;
}
}
.line {
width: 0;
height: 50rpx;
background: transparent;
border: 2rpx solid #fff;
opacity: 0.4;
margin-left: 25rpx;
}
.login-info-content {
display: flex;
margin-left: 25rpx;
flex-direction: column;
.login-info {
font-family: "MicrosoftYaHei ";
font-weight: 400;
font-size: 32rpx;
text-align: left;
color: #fff;
}
.address-content {
display: flex;
flex-direction: row;
margin-top: 8rpx;
align-items: center;
.loc-image {
width: 16rpx;
height: 20rpx;
}
.address {
font-family: "MicrosoftYaHeiUI ";
font-weight: 400;
font-size: 24rpx;
margin-left: 10rpx;
text-align: left;
color: #fff;
}
}
}
}
.banner-content {
width: 694rpx;
display: flex;
position: absolute;
left: 28rpx;
border-radius: 30rpx;
border: 2rpx solid #707070;
}
}
.top-new-content {
display: flex;
flex-direction: row;
border-radius: 30rpx;
margin: 230px 30rpx 20rpx 30rpx;
background-color: #FFFFFF;
padding: 16rpx 30rpx;
align-items: center;
image {
width: 32rpx;
height: 28rpx;
}
.title {
font-family: "MicrosoftYaHeiUI-Bold";
font-weight: bold;
font-size: 26rpx;
margin-left: 16rpx;
color: #656565;
}
.new-content {
font-family: "MicrosoftYaHeiUI";
font-weight: 400;
flex: 1;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-left: 32rpx;
font-size: 24rpx;
color: #656565;
}
.right-arrow {
width: 13rpx;
height: 24rpx;
}
}
.bus-content {
display: flex;
flex-direction: column;
padding: 30rpx;
border-radius: 30rpx;
margin: 0 30rpx;
.tab-content {
display: flex;
flex-direction: row;
align-items: center;
.tab-item {
display: flex;
flex-direction: column;
flex: 1;
align-items: center;
.tab-text {
font-family: "PingFang SC";
font-weight: 400;
font-size: 32rpx;
text-align: center;
color: #333;
}
.tab-text-sel {
font-family: "PingFang SC";
font-weight: 400;
font-size: 32rpx;
text-align: center;
color: #3b73fe;
}
.tab-line {
margin-top: 10rpx;
width: 140rpx;
height: 2rpx;
background: #3b73fe;
}
}
}
}
}
</style>
<template>
<view>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>
<template>
<view>
<view v-if="isCanUse">
<view>
<view class='header'>
<image src='../../static/icon_wechat.jpg'></image>
</view>
<view class='content'>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<button class='bottom' type='primary' open-type="chooseAvatar" withCredentials="true" lang="zh_CN"
@tap="bindchooseavatar">
授权登录
</button>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
SessionKey: '',
unique_token: '',
nickName: null,
avatarUrl: null,
isCanUse: uni.getStorageSync('isCanUse') || true //默认为true
};
},
methods: {
//第一授权获取用户信息===》按钮触发
wxGetUserInfo() {
let _this = this;
try {
uni.getUserProfile({
desc: '授权获取用户信息',
success: function(infoRes) {
let nickName = infoRes.userInfo.nickName; //昵称
let avatarUrl = infoRes.userInfo.avatarUrl; //头像
console.log("授权登录", infoRes);
try {
uni.setStorageSync("nickname", nickName);
uni.setStorageSync("avatarUrl", avatarUrl);
if (_this.unique_token !== '') {
_this.checkBind()
} else {
uni.showToast({
title: "授权失败",
icon: 'none'
})
}
} catch (e) {}
},
fail(res) {}
});
} catch (e) {
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
let nickName = infoRes.userInfo.nickName; //昵称
let avatarUrl = infoRes.userInfo.avatarUrl; //头像
console.log("授权登录", nickName);
try {
uni.setStorageSync("nickname", nickName);
uni.setStorageSync("avatarUrl", avatarUrl);
if (_this.unique_token !== '') {
_this.checkBind()
} else {
uni.showToast({
title: "授权失败",
icon: 'none'
})
}
} catch (e) {}
},
fail(res) {}
});
}
}, //登录
checkBind: function() {
this.$http.consolePost({
url: "/api/v1/system/p_user_third/check_bind_by_unique_token",
data: {
unique_token: this.unique_token
},
header: {}
}).then((res) => {
let code = res.data.code
if (code == 0) { //已绑定直接登录
this.directLogin()
} else if (code == 33199) { //未绑定 去绑定
this.showMadel()
} else { //其他错误
uni.showToast({
title: res.data.msg,
icon: 'none'
})
}
})
},
showMadel: function() {
let _this = this
uni.showModal({
title: '提示',
content: '您还未授权绑定账号',
showCancel: true,
confirmText: "去绑定",
confirmColor: '#1890FF',
success: res => {
if (res.confirm) {
uni.redirectTo({
url: `../bind-login/bind-login?unique_token=${_this.unique_token}`
})
}
}
})
},
directLogin: function() {
this.$http.consolePost({
url: "/api/v1/system/p_user_third/do_login",
data: {
unique_token: this.unique_token
}
}).then((res) => {
let result = res.data
console.log("登录用户信息:", result);
if (result.code === 0) {
uni.setStorageSync("short_token", result.data.short_token)
this.setToken(result.data.access_token)
uni.setStorageSync("user_info", result.data)
uni.setStorageSync("company_id", result.data.comp_id)
uni.showToast({
title: "授权登录成功",
icon: 'none'
})
uni.switchTab({
url: "../desk-page/desk-page"
})
} else {
uni.showToast({
title: result.msg,
icon: 'none'
})
}
})
},
login() {
let _this = this;
uni.showLoading({
title: '加载中...'
});
// 1.wx获取登录用户code
uni.login({
provider: 'weixin',
success: function(loginRes) {
let code = loginRes.code;
//2.将用户登录code传递到后台置换用户SessionKey、OpenId等信息
_this.$http.consolePost({
url: "/api/v1/system/p_user_third/get_wx_mini_program_openid",
data: {
"js_code": code,
"system_no": _this.systemCode
},
header: {
"Content-Type": "application/json"
}
}).then((res) => {
// 获取openId
let result = res.data
console.log(result);
_this.unique_token = result.data.unique_token
})
},
});
},
},
onLoad() { //默认加载
this.login();
}
}
</script>
<style>
.header {
margin: 90rpx 0 90rpx 50rpx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650rpx;
height: 300rpx;
line-height: 450rpx;
}
.header image {
width: 200rpx;
height: 200rpx;
}
.content {
margin-left: 50rpx;
margin-bottom: 90rpx;
}
.content text {
display: block;
color: #9d9d9d;
margin-top: 40rpx;
}
.bottom {
border-radius: 80rpx;
margin: 70rpx 50rpx;
font-size: 35rpx;
}
</style>
<template>
<view>
<uni-tabbar currentPage="3"></uni-tabbar>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>
<template>
<view>
<uni-tabbar currentPage="2"></uni-tabbar>
</view>
</template>
<script>
export default {
data() {
return {
}
},
methods: {
}
}
</script>
<style>
</style>
static/loc.png

708 Bytes

/**
* 这里是uni-app内置的常用样式变量
*
* uni-app 官方扩展插件及插件市场(https://ext.dcloud.net.cn)上很多三方插件均使用了这些样式变量
* 如果你是插件开发者,建议你使用scss预处理,并在插件代码中直接使用这些变量(无需 import 这个文件),方便用户通过搭积木的方式开发整体风格一致的App
*
*/
/**
* 如果你是App开发者(插件使用者),你可以通过修改这些变量来定制自己的插件主题,实现自定义主题功能
*
* 如果你的项目同样使用了scss预处理,你也可以直接在你的 scss 代码中使用如下变量,同时无需 import 这个文件
*/
/* 颜色变量 */
/* 行为相关颜色 */
$uni-color-primary: #007aff;
$uni-color-success: #4cd964;
$uni-color-warning: #f0ad4e;
$uni-color-error: #dd524d;
/* 文字基本颜色 */
$uni-text-color:#333;//基本色
$uni-text-color-inverse:#fff;//反色
$uni-text-color-grey:#999;//辅助灰色,如加载更多的提示信息
$uni-text-color-placeholder: #808080;
$uni-text-color-disable:#c0c0c0;
/* 背景颜色 */
$uni-bg-color:#ffffff;
$uni-bg-color-grey:#f8f8f8;
$uni-bg-color-hover:#f1f1f1;//点击状态颜色
$uni-bg-color-mask:rgba(0, 0, 0, 0.4);//遮罩颜色
/* 边框颜色 */
$uni-border-color:#c8c7cc;
/* 尺寸变量 */
/* 文字尺寸 */
$uni-font-size-sm:12px;
$uni-font-size-base:14px;
$uni-font-size-lg:16;
/* 图片尺寸 */
$uni-img-size-sm:20px;
$uni-img-size-base:26px;
$uni-img-size-lg:40px;
/* Border Radius */
$uni-border-radius-sm: 2px;
$uni-border-radius-base: 3px;
$uni-border-radius-lg: 6px;
$uni-border-radius-circle: 50%;
/* 水平间距 */
$uni-spacing-row-sm: 5px;
$uni-spacing-row-base: 10px;
$uni-spacing-row-lg: 15px;
/* 垂直间距 */
$uni-spacing-col-sm: 4px;
$uni-spacing-col-base: 8px;
$uni-spacing-col-lg: 12px;
/* 透明度 */
$uni-opacity-disabled: 0.3; // 组件禁用态的透明度
/* 文章场景相关 */
$uni-color-title: #2C405A; // 文章标题颜色
$uni-font-size-title:20px;
$uni-color-subtitle: #555555; // 二级标题颜色
$uni-font-size-subtitle:26px;
$uni-color-paragraph: #3F536E; // 文章段落颜色
$uni-font-size-paragraph:15px;
## 1.2.3(2022-12-14)
修复外部不跳转页面修改current,组件不响应bug
## 1.2.2(2022-12-14)
新增click事件,click事件会优先于任何事件
## 1.2.1(2022-12-09)
修改文档使用说明,路由拦截有平台兼容性,暂时无法解决,平台原生不支持
## 1.2.0(2022-12-09)
新增插槽,可以自定义凸起导航,优化文档使用说明
## 1.1.9(2022-12-06)
修复iconPath图片路径为网络路径判断错误问题
## 1.1.7(2022-12-01)
优化部分机器计算错误问题
## 1.1.6(2022-12-01)
修改高度计算错误问题
## 1.1.5(2022-12-01)
修复各别设备上高度计算有误问题
## 1.1.4(2022-11-25)
修复vue2版本在微信小程序上不支持:style传入参数bug,优化参数错误逻辑
## 1.1.3(2022-11-24)
修复native模式borderStyle样式丢失问题
## 1.1.2(2022-11-24)
修改描述文档说明,修改插件描述信息
## 1.1.1(2022-11-24)
优化使用说明文档
## 1.1.0(2022-11-24)
极度简化native模式,页面只需要引入组件即可,任何操作都不需要
## 1.0.9(2022-11-24)
修复native模式下,fill忘记计算高度.
## 1.0.8(2022-11-24)
优化native模式,简化参数数量,使用更简单
## 1.0.7(2022-11-24)
新增native配置,可以兼容原生tabbar,新增beforeChange,可自行根据要求自己兼容路由守卫
## 1.0.6(2022-11-23)
修改文档描述错误
## 1.0.5(2022-11-23)
修复fill高度遗漏安全距离问题,文档使用说明优化更新
## 1.0.4(2022-11-23)
优化配置选项,提取当前选中项,新增fixed配置
## 1.0.3(2022-11-14)
添加上阴影效果,修复由于去除了上线条,造成如果内容如果是白色,tabbar会和内容高度重合的问题
## 1.0.2(2022-11-14)
修改说明文档,更加详细备注说明
## 1.0.1(2022-11-14)
新增当前选中项class名,方便用户直接样式覆盖
## 1.0.0(2022-11-14)
第一个自定义tabbar版本
<template>
<view class="m-tabbar-box" :style="tabbarBoxStyle">
<view v-if="fill || native" :style="tabbarFillStyle"></view>
<view id="m-tabbar" class="m-tabbar" :class="{'fixed': fixed || native}" :style="tabbarStyle">
<view class="m-tabbar__border" v-if="borderStyle === 'black' "></view>
<view class="m-tabbar__flex">
<view @click="tabChange(index)" v-for="(item, index) in tabbarList" :key="index" class="m-tabbar__item"
:class="{
'm-tabbar__item__active': index === currentIndex,
}">
<slot :name="`tabbar_index_${index}`">
<image :src="currentIndex === index ? item.selectedIconPath : item.iconPath"
class="m-tabbar__icon" />
<view class="m-tabbar__label"
:style="{'color': index === currentIndex ? tabbarConfig.selectedColor : tabbarConfig.color }">
{{ item.text }}
</view>
</slot>
</view>
</view>
</view>
</view>
</template>
<script>
const obj2strStyle = (obj) => {
let style = ''
for (let key in obj) {
style += `${key}:${obj[key]};`
}
return style
}
const padFirstSymbol = (str, smb) => {
if (str.startsWith(smb) || str.startsWith('http')) {
return str
}
return `/${str}`
}
const replaceTabbarList = (list) => {
if (!list.length > 0) {
return []
}
return list.map(item => {
if(item.iconPath){
item.iconPath = padFirstSymbol(item.iconPath, '/')
}
if(item.pagePath){
item.pagePath = padFirstSymbol(item.pagePath, '/')
}
if(item.selectedIconPath){
item.selectedIconPath = padFirstSymbol(item.selectedIconPath, '/')
}
return item
})
}
import PageConfig from '@/pages.json'
export default {
emits: ['change', 'click'],
props: {
current: {
type: [Number, String],
default: 0
},
tabbar: {
type: Object,
default () {
return {}
}
},
fixed: {
type: Boolean,
default: false
},
fill: {
type: Boolean,
default: false
},
zIndex: {
type: [Number, String],
default: 9999
},
native: {
type: Boolean,
default: false
},
safeBottom: {
type: Boolean,
default: true
},
beforeChange: {
type: Function,
default: null
}
},
data() {
return {
safeAreaInsetsBottom: 0,
currentIndex: 0,
tabbarHeight: 0,
beforeData: {},
}
},
watch: {
current(val) {
this.currentIndex = val * 1
}
},
computed: {
tabbarConfig() {
const {
native
} = this
if (native) {
const {
tabBar
} = PageConfig
if (!tabBar) {
console.error('Native mode, Pages.json no tabbar config')
return {
borderStyle: 'black',
list: []
}
}
return tabBar
}
return this.tabbar
},
tabbarList() {
const {
list
} = this.tabbarConfig
if(list){
return replaceTabbarList(list)
}
console.error('No tabbar config')
return []
},
borderStyle() {
const {
borderStyle
} = this.tabbarConfig
return borderStyle
},
tabbarBoxStyle() {
const {
zIndex
} = this
return obj2strStyle({
'z-index': zIndex,
})
},
tabbarFillStyle() {
const {
tabbarHeight,
safeAreaInsetsBottom
} = this
return obj2strStyle({
'height': `${tabbarHeight}rpx`,
'padding-bottom': `${safeAreaInsetsBottom}rpx`,
'opacity': 0
})
},
tabbarStyle() {
const {
safeAreaInsetsBottom
} = this
const {
backgroundColor
} = this.tabbarConfig
return obj2strStyle({
'background-color': backgroundColor || '#fff',
'padding-bottom': `${safeAreaInsetsBottom}rpx`
})
},
tabbarItemStyle() {
const {
currentIndex
} = this
const {
color,
selectedColor
} = this.tabbarConfig
return obj2strStyle({
'color': currentIndex ? selectedColor : color
})
}
},
mounted() {
const {
current,
safeBottom,
fill,
native,
tabbarList
} = this
this.currentIndex = current * 1
if (fill || native) {
this.getTabbarHeight()
}
if (native) {
const currentPage = getCurrentPages()[0].$page.fullPath
const currentIndex = tabbarList.findIndex(item => item.pagePath === currentPage)
this.currentIndex = currentIndex
if (tabbarList.length > 0) {
uni.hideTabBar()
}
}
},
methods: {
getTabbarHeight() {
const { safeBottom, native } = this
const {windowWidth, safeAreaInsets} = uni.getSystemInfoSync()
const ratio = 750 / windowWidth
if(safeBottom || native){
this.safeAreaInsetsBottom = safeAreaInsets.bottom * ratio
}
let query = wx.createSelectorQuery().in(this)
query.select('#m-tabbar').boundingClientRect(rect => {
if (rect) {
this.tabbarHeight = rect.height * ratio
}
}).exec()
},
tabChange(index) {
const {
currentIndex
} = this
this.$emit('click', index)
if (index === currentIndex) {
return
}
this.beforeData = {
newIndex: index,
oldIndex: currentIndex,
next: this.jumpPage
}
if (this.beforeChange) {
this.beforeChange(this.jumpPage)
} else {
this.jumpPage()
}
},
jumpPage() {
const {
native,
beforeData,
tabbarList: list
} = this
const {
newIndex: index
} = beforeData
if (list[index].pagePath) {
if (native) {
uni.switchTab({
url: list[index].pagePath
})
} else {
this.currentIndex = index
uni.reLaunch({
url: list[index].pagePath
})
}
}
this.$emit('change', index)
}
}
};
</script>
<style lang="scss" scoped>
.m-tabbar-box {
position: relative;
z-index: 9999;
}
.m-tabbar {
position: relative;
}
.m-tabbar.fixed {
position: fixed;
bottom: 0;
left: 0;
width: 100vw;
}
.m-tabbar__flex {
display: flex;
flex-direction: row;
}
.m-tabbar__border {
background-color: rgba(0, 0, 0, 0.33);
width: 100%;
height: 1rpx;
transform: scaleY(0.5);
}
.m-tabbar__item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
padding: 4px 0 2px;
}
.m-tabbar__icon {
display: block;
width: 48rpx;
height: 48rpx;
margin-bottom: 6rpx;
}
.m-tabbar__label {
font-size: 24rpx;
}
</style>
{
"id": "m-tabbar",
"displayName": "自定义tabbar、tabbar路由守卫、零配置tabbar、凸起导航",
"version": "1.2.3",
"description": "自定义tabbar,超高还原原生配置模式,一行代码自定义导航,自带tabbar路由守卫功能",
"keywords": [
"自定义tabbar,tabbar,自定义标签栏,tabbar路由守卫,零配置tabbar,路由守卫、凸起导航"
],
"repository": "",
"engines": {
"HBuilderX": "^3.3.1"
},
"dcloudext": {
"type": "component-vue",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"钉钉": "y",
"快手": "y",
"飞书": "y",
"京东": "y"
},
"快应用": {
"华为": "y",
"联盟": "y"
}
}
}
}
}
\ No newline at end of file
# m-tabbar自定义
## 使用说明,注意事项(必看)
> 我配套上传了一个案例包,如果不会使用的,建议下载阅读使用
自定义tabbar的情况下,不建议在一个页面内通过几个组件,用v-if切换去模拟各个页面,会存在各种不可控bug
> 如果是`if切换组件`的话,就是一个页面控制多个组件显示隐藏来实现。 如果组件封装的有问题,会出现组件之间的协调问题,请看情况使用。 还有一些原生的交互没有办法达到预期,会影响到原生体验。 比如下拉刷新,滚动加载更多,切换tabbar后滚动位置不能固定等
推荐使用自带的tabbar系统,同时隐藏原生的tabbar, 再引入自定导航栏,这样可以保证原有性能,同时又能自定义tabbar
在pages.json中正常定义tabbar配置和字段,使用`native`模式,组件会自动加载pages.json配置项,并自动判断当前选中项
> native模式,你不需要传入任何配置,直接页面引入即结束
# 快速使用
## 方式一、Native模式使用(推荐)
```
// native模式,无需配置其他项
<m-tabbar native></m-tabbar>
```
在各个tabbar页面引入tabbar组件,传入属性`native``native`模式下无需任何配置
组件会默认自动通过`uni.hideTabBar()`隐藏系统tabbar
## 方式二、普通页面使用(current默认从0开始)
```
// 普通页面模式
<m-tabbar fixed fill current="1" :tabbar="tabbar"></m-tabbar>
```
配置选项和`uniapp`的配置完全相同,直接复制过来, 默认传入`pagePath`后,直接使用`reLaunch`跳转
如果不想使用自带跳转模式,可以不传入`pagePath`,自行接管事件`change`来达到当前页面tab任意切换
### 1、提取tabbar配置
新建文件config/tabbar.js(默认你有config目录,根据自己情况而定)
```
export default {
color: "#161616",
selectedColor: "#161616",
borderStyle: "black",
backgroundColor: "#ffffff",
list: [{
pagePath: "/pages/index/index",
iconPath: "/static/tabbar/index.png",
selectedIconPath: "/static/tabbar/index_active.png",
text: "首页"
}, {
pagePath: "/pages/shop/index",
iconPath: "/static/tabbar/shop.png",
selectedIconPath: "/static/tabbar/shop_active.png",
text: "门店"
}, {
pagePath: "/pages/my/index",
iconPath: "/static/tabbar/my.png",
selectedIconPath: "/static/tabbar/my_active.png",
text: "我的"
}]
}
```
### 2、引入tabbar
#### VUE2引入
```
import TabbarConfig from '@/config/tabbar.js'
export default {
data(){
return {
tabbar: TabbarConfig
}
},
onLoad(){
// 没有开启native模式下,使用reLaunch跳转,会存在首页标志,需要隐藏
#ifdef MP-JD || MP-WEIXIN
uni.hideHomeButton()
#endif
}
}
```
#### VUE3 setup引入
```
import TabbarConfig from '@/config/tabbar.js'
import { reactive } from 'vue'
// 没有开启native模式下,使用reLaunch跳转,会存在首页标志,需要隐藏
#ifdef MP-JD || MP-WEIXIN
uni.hideHomeButton()
#endif
const tabbar = reactive(TabbarConfig)
```
### 3、页面使用
```
<m-tabbar fixed fill current="1" :tabbar="tabbar"></m-tabbar>
```
## 高级用法(beforeChange)(路由守卫)
有些特殊需求,我们在点击一个tabbar其他一项的时候,可能需要判断权限是否可以进入,那么我们在切换前做一下路由拦截`beforeChange`,如果达到自己的预期,就进行跳转
> uniapp 微信小程序不支持$listeners,只能使用prop方式传入, 部分平台不支持prop传入方法,有平台限制,详细请看(问题解答)[https://ask.dcloud.net.cn/question/70659]
### 页面使用传入beforeChange
```
// native模式,无需传入 fixed fill
<m-tabbar native :beforeChange="onBeforeChange"></m-tabbar>
// 普通页面模式
<m-tabbar fixed fill current="1" :tabbar="tabbar" :beforeChange="onBeforeChange"></m-tabbar>
```
### 进行事件判断监听
函数必选参数 next,当判断逻辑执行完毕后,满足条件的情况下执行 `next()`
```
methods: {
onBeforeChange(next){
console.log('before page2 switch')
setTimeout(()=>{
console.log('switch page2 end')
next()
}, 1000)
}
}
```
## 自定义凸起导航(插槽使用)
```
<m-tabbar native>
<template v-slot:tabbar_index_1> //插槽详细看文档,样式你自己写
<view class="custom_style">
<view class="custom_style_icon">+</view>
</view>
</template>
</m-tabbar>
<style lang="scss">
.custom_style{
color: #fff;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 24rpx;
&_icon{
background-color: #15357A;
font-size: 80rpx;
width: 120rpx;
height: 120rpx;
border-radius: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-top: -40rpx;
}
}
</style>
```
### 属性说明
| 属性名 | 类型 | 默认值 | 必填 | 说明 |
| ------- | ------- | ------- | ------- | ------- |
| current | Number,String | 0 | true | 默认选中第几项,0开始(普通模式) |
| tabbar | Object | {} | true | tabbar配置项 (普通模式) |
| fixed | Boolean | false | false | 是否定位在底部(普通模式) |
| fill | Boolean | false | false | 是否填充底部高度(如果开启fixed后,会出现tabbar遮盖内容问题,开启此属性,会自动填充高度,可单独使用)(普通模式) |
| safeBottom | Boolean | true | false | 是否自动规避iphoneX\XR等底部安全距离(普通模式) |
| zIndex | Number,String | 999 | false | 当前处于z-index层级 |
| native | Boolean | false | false | native模式,当前页面是系统原生tabbar页面(pages.json里面配置了tabBar) |
| beforeChange | Function | null | false | 导航切换前事件hooks,用于判断点击tabbar的时候,可以先执行自己定义的事件,达到预期后在跳转(类似router的路由守卫),方法需要调用next参数回调,部分平台不支持,存在兼容性 |
### 方法说明
| 方法名 | 返回值说明 |
| ------- | ------- |
| click | 当前选中index,无论什么请看下都会先触发click事件,方便自由定制更多方法 |
| change | 当前选中index(beforeChange会在change之前执行,只有执行next才会返回) |
### 插槽
| 插槽名 | 返回值说明 |
| ------- | ------- |
| tabbar_index_{index} | 插槽名字为tabbar_index_你要变化的index, 可以做到任意控制自己的导航,比如中心凸起,比如你想让第一个变化,index就是0,比如你tabbarList里面有5个item,你想让中间的凸起,那么index就是2,取下标 |
### 插件写的时候,没办法照顾到所有平台,欢迎点评指正,如有问题欢迎给我留言
#### 例如:
```
设备:iphone13
系统: ios13
使用环境平台: 微信小程序、app
使用vue版本 :vue3
问题描述: 提示什么什么错误
```
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
Please register or to comment