提交 8f7e5961 编写于 作者: hbcui1984's avatar hbcui1984

迁移登录模板

新地址:https://github.com/dcloudio/uni-template-login
上级 71c480f5
<script>
export default {
onLaunch: function () {
console.log('App Launch');
},
onShow: function () {
console.log('App Show');
},
onHide: function () {
console.log('App Hide');
}
}
</script>
<style>
/*每个页面公共css */
/* uni-app默认全局使用flex布局。因为flex布局有利于跨更多平台,尤其是采用原生渲染的平台。如不了解flex布局,请参考http://www.w3.org/TR/css3-flexbox/。如不使用flex布局,请删除或注释掉本行。*/
page {
min-height: 100%;
display: flex;
}
.content {
display: flex;
flex: 1;
flex-direction: column;
background-color: #efeff4;
padding: 20px;
}
.input-group {
background-color: #ffffff;
margin-top: 40px;
position: relative;
}
.input-group::before {
position: absolute;
right: 0;
top: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-group::after {
position: absolute;
right: 0;
bottom: 0;
left: 0;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.input-row {
display: flex;
flex-direction: row;
position: relative;
}
.input-row .title {
width: 20%;
height: 50px;
min-height: 50px;
padding: 15px 0;
padding-left: 30px;
line-height: 50px;
}
.input-row.border::after {
position: absolute;
right: 0;
bottom: 0;
left: 15px;
height: 1px;
content: '';
-webkit-transform: scaleY(.5);
transform: scaleY(.5);
background-color: #c8c7cc;
}
.btn-row {
margin-top: 50px;
padding: 20px;
}
button.primary {
background-color: #0faeff;
}
</style>
# UNI-APP 登录模板
![](https://img-cdn-qiniu.dcloud.net.cn/7E6B79E2-B469-4CF3-8F4D-7502E72C4CB8.png?imageView2/0/w/375)
![](https://img-cdn-qiniu.dcloud.net.cn/659AE293-95F8-46E1-AC1F-D62FE3B080DB.png?imageView2/0/w/375)
## 运行方式
将项目拖入[HbuilderX](http://www.dcloud.io/hbuilderx.html),直接运行即可
## 特点
* 兼容微信小程序和APP
* 适用于强制登录和非强制登录应用场景
* 使用vuex管理登录状态
* 包含账户密码登录和第三方登录方式(微信、微博、QQ)
## 注意事项
* 页面初始化完毕后马上跳转页面可能会失败,可以尝试延迟执行
代码已迁移,请移步[https://github.com/dcloudio/uni-template-login](https://github.com/dcloudio/uni-template-login)查看最新代码
@font-face {
font-family: uniicons;
font-weight: normal;
font-style: normal;
src: url('https://img-cdn-qiniu.dcloud.net.cn/fonts/uni.ttf?t=1536565627510') format('truetype');
}
.uni-icon {
font-family: uniicons;
font-size: 48upx;
font-weight: normal;
font-style: normal;
line-height: 1;
display: inline-block;
text-decoration: none;
-webkit-font-smoothing: antialiased;
}
.uni-icon.uni-active {
color: #007aff;
}
.uni-icon-contact:before {
content: '\e100';
}
.uni-icon-person:before {
content: '\e101';
}
.uni-icon-personadd:before {
content: '\e102';
}
.uni-icon-contact-filled:before {
content: '\e130';
}
.uni-icon-person-filled:before {
content: '\e131';
}
.uni-icon-personadd-filled:before {
content: '\e132';
}
.uni-icon-phone:before {
content: '\e200';
}
.uni-icon-email:before {
content: '\e201';
}
.uni-icon-chatbubble:before {
content: '\e202';
}
.uni-icon-chatboxes:before {
content: '\e203';
}
.uni-icon-phone-filled:before {
content: '\e230';
}
.uni-icon-email-filled:before {
content: '\e231';
}
.uni-icon-chatbubble-filled:before {
content: '\e232';
}
.uni-icon-chatboxes-filled:before {
content: '\e233';
}
.uni-icon-weibo:before {
content: '\e260';
}
.uni-icon-weixin:before {
content: '\e261';
}
.uni-icon-pengyouquan:before {
content: '\e262';
}
.uni-icon-chat:before {
content: '\e263';
}
.uni-icon-qq:before {
content: '\e264';
}
.uni-icon-videocam:before {
content: '\e300';
}
.uni-icon-camera:before {
content: '\e301';
}
.uni-icon-mic:before {
content: '\e302';
}
.uni-icon-location:before {
content: '\e303';
}
.uni-icon-mic-filled:before,
.uni-icon-speech:before {
content: '\e332';
}
.uni-icon-location-filled:before {
content: '\e333';
}
.uni-icon-micoff:before {
content: '\e360';
}
.uni-icon-image:before {
content: '\e363';
}
.uni-icon-map:before {
content: '\e364';
}
.uni-icon-compose:before {
content: '\e400';
}
.uni-icon-trash:before {
content: '\e401';
}
.uni-icon-upload:before {
content: '\e402';
}
.uni-icon-download:before {
content: '\e403';
}
.uni-icon-close:before {
content: '\e404';
}
.uni-icon-redo:before {
content: '\e405';
}
.uni-icon-undo:before {
content: '\e406';
}
.uni-icon-refresh:before {
content: '\e407';
}
.uni-icon-star:before {
content: '\e408';
}
.uni-icon-plus:before {
content: '\e409';
}
.uni-icon-minus:before {
content: '\e410';
}
.uni-icon-circle:before,
.uni-icon-checkbox:before {
content: '\e411';
}
.uni-icon-close-filled:before,
.uni-icon-clear:before {
content: '\e434';
}
.uni-icon-refresh-filled:before {
content: '\e437';
}
.uni-icon-star-filled:before {
content: '\e438';
}
.uni-icon-plus-filled:before {
content: '\e439';
}
.uni-icon-minus-filled:before {
content: '\e440';
}
.uni-icon-circle-filled:before {
content: '\e441';
}
.uni-icon-checkbox-filled:before {
content: '\e442';
}
.uni-icon-closeempty:before {
content: '\e460';
}
.uni-icon-refreshempty:before {
content: '\e461';
}
.uni-icon-reload:before {
content: '\e462';
}
.uni-icon-starhalf:before {
content: '\e463';
}
.uni-icon-spinner:before {
content: '\e464';
}
.uni-icon-spinner-cycle:before {
content: '\e465';
}
.uni-icon-search:before {
content: '\e466';
}
.uni-icon-plusempty:before {
content: '\e468';
}
.uni-icon-forward:before {
content: '\e470';
}
.uni-icon-back:before,
.uni-icon-left-nav:before {
content: '\e471';
}
.uni-icon-checkmarkempty:before {
content: '\e472';
}
.uni-icon-home:before {
content: '\e500';
}
.uni-icon-navigate:before {
content: '\e501';
}
.uni-icon-gear:before {
content: '\e502';
}
.uni-icon-paperplane:before {
content: '\e503';
}
.uni-icon-info:before {
content: '\e504';
}
.uni-icon-help:before {
content: '\e505';
}
.uni-icon-locked:before {
content: '\e506';
}
.uni-icon-more:before {
content: '\e507';
}
.uni-icon-flag:before {
content: '\e508';
}
.uni-icon-home-filled:before {
content: '\e530';
}
.uni-icon-gear-filled:before {
content: '\e532';
}
.uni-icon-info-filled:before {
content: '\e534';
}
.uni-icon-help-filled:before {
content: '\e535';
}
.uni-icon-more-filled:before {
content: '\e537';
}
.uni-icon-settings:before {
content: '\e560';
}
.uni-icon-list:before {
content: '\e562';
}
.uni-icon-bars:before {
content: '\e563';
}
.uni-icon-loop:before {
content: '\e565';
}
.uni-icon-paperclip:before {
content: '\e567';
}
.uni-icon-eye:before {
content: '\e568';
}
.uni-icon-arrowup:before {
content: '\e580';
}
.uni-icon-arrowdown:before {
content: '\e581';
}
.uni-icon-arrowleft:before {
content: '\e582';
}
.uni-icon-arrowright:before {
content: '\e583';
}
.uni-icon-arrowthinup:before {
content: '\e584';
}
.uni-icon-arrowthindown:before {
content: '\e585';
}
.uni-icon-arrowthinleft:before {
content: '\e586';
}
.uni-icon-arrowthinright:before {
content: '\e587';
}
.uni-icon-pulldown:before {
content: '\e588';
}
.uni-icon-scan:before {
content: "\e612";
}
<template>
<view class="uni-icon" :class="['uni-icon-'+type]" :style="{color:color,'font-size':fontSize}" @click="onClick()"></view>
</template>
<script>
export default {
props: {
/**
* 图标类型
*/
type: String,
/**
* 图标颜色
*/
color: String,
/**
* 图标大小
*/
size: Number
},
computed: {
fontSize() {
return `${this.size}px`
}
},
methods: {
onClick() {
this.$emit('click')
}
}
}
</script>
<style>
@import "./uni-icon.css";
</style>
<template>
<view class="uni-input-view">
<input :focus="focus_" :type="inputType" :value="value" @input="onInput" class="uni-input-input" :placeholder="placeholder"
:password="type==='password'&&!showPassword" @focus="onFocus" @blur="onBlur" />
<!-- 优先显示密码可见按钮 -->
<uni-icon v-if="clearable_&&!displayable_&&value.length" color="#666666" type="clear" size="20" @click="clear"></uni-icon>
<uni-icon v-if="displayable_" :color="showPassword?'#666666':'#cccccc'" type="eye" size="20" @click="display"></uni-icon>
</view>
</template>
<script>
import uniIcon from './uni-icon/uni-icon.vue'
export default {
components: {
uniIcon
},
props: {
/**
* 输入类型
*/
type: String,
/**
* 值
*/
value: String,
/**
* 占位符
*/
placeholder: String,
/**
* 是否显示清除按钮
*/
clearable: {
type: [Boolean, String],
default: false
},
/**
* 是否显示密码可见按钮
*/
displayable: {
type: [Boolean, String],
default: false
},
/**
* 自动获取焦点
*/
focus: {
type: [Boolean, String],
default: false
}
},
model: {
prop: 'value',
event: 'input'
},
data() {
return {
/**
* 显示密码明文
*/
showPassword: false,
/**
* 是否获取焦点
*/
isFocus: false
}
},
computed: {
inputType() {
const type = this.type
return type === 'password' ? 'text' : type
},
clearable_() {
return String(this.clearable) !== 'false'
},
displayable_() {
return String(this.displayable) !== 'false'
},
focus_() {
return String(this.focus) !== 'false'
}
},
methods: {
clear() {
this.value = ''
},
display() {
this.showPassword = !this.showPassword
},
onFocus() {
this.isFocus = true
},
onBlur() {
this.$nextTick(() => {
this.isFocus = false
})
},
onInput(e) {
this.$emit('input', e.target.value)
}
}
}
</script>
<style>
.uni-input-view {
display: flex;
flex-direction: row;
align-items: center;
width: 100%;
flex: 1;
padding: 0 10rpx;
}
.uni-input-input {
flex: 1;
width: 100%;
}
</style>
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false
Vue.prototype.$store = store
App.mpType = 'app'
const app = new Vue({
store,
...App
})
app.$mount()
{
"name" : "login-template",
"appid" : "__UNI__5430F3F",
"description": "登录模板",
"versionName": "1.0.0",
"versionCode": "100",
"app-plus": { /* 5+App特有相关 */
"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.READ_CONTACTS\"/>","<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.WRITE_CONTACTS\"/>","<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>","<uses-permission android:name=\"android.permission.CAMERA\"/>","<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>","<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>","<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>","<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.CALL_PHONE\"/>","<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>","<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>","<uses-feature android:name=\"android.hardware.camera\"/>","<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>","<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"]
},
"ios": { /* ios打包配置 */
},
"sdkConfigs": { /* SDK配置 */
}
}
},
"quickapp": { /* 快应用特有相关 */
},
"mp-weixin": { /* 小程序特有相关 */
"appid": "",
"setting" : {
"urlCheck" : true
}
}
}
{
"pages": [ //pages数组中第一项表示应用启动页,
{
"path": "pages/main/main",
"style": {
"navigationBarTitleText": "登录模板"
}
}, {
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录"
}
}, {
"path": "pages/reg/reg",
"style": {
"navigationBarTitleText": "注册"
}
}, {
"path": "pages/pwd/pwd",
"style": {
"navigationBarTitleText": "找回密码"
}
}, {
"path": "pages/user/user",
"style": {
"navigationBarTitleText": "我的"
}
}
],
"tabBar": {
"color": "#7a7e83",
"selectedColor": "#0faeff",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/main/main",
"text": "首页",
"iconPath": "static/img/home.png",
"selectedIconPath": "static/img/homeHL.png"
}, {
"pagePath": "pages/user/user",
"text": "我的",
"iconPath": "static/img/user.png",
"selectedIconPath": "static/img/userHL.png"
}]
},
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarBackgroundColor": "#0faeff",
"backgroundColor": "#fbf9fe"
}
}
<template>
<view class="content">
<view class="input-group">
<view class="input-row border">
<text class="title">账号:</text>
<uni-input class="uni-input" type="text" clearable focus v-model="account" placeholder="请输入账号"></uni-input>
</view>
<view class="input-row">
<text class="title">密码:</text>
<uni-input type="password" displayable v-model="password" placeholder="请输入密码"></uni-input>
</view>
</view>
<view class="btn-row">
<button type="primary" class="primary" @tap="bindLogin">登录</button>
</view>
<view class="action-row">
<navigator url="../reg/reg">注册账号</navigator>
<text>|</text>
<navigator url="../pwd/pwd">忘记密码</navigator>
</view>
<view class="oauth-row" v-if="hasProvider" v-bind:style="{top: positionTop + 'px'}">
<view class="oauth-image" v-for="provider in providerList" :key="provider.value">
<image :src="provider.image" @tap="oauth(provider.value)"></image>
</view>
</view>
</view>
</template>
<script>
import service from '../../service.js';
import {
mapState,
mapMutations
} from 'vuex'
import uniInput from '../../components/uni-input.vue'
export default {
components: {
uniInput
},
data() {
return {
providerList: [],
hasProvider: false,
account: '',
password: '',
positionTop: 0
}
},
computed: mapState(['forcedLogin']),
methods: {
...mapMutations(['login']),
initProvider() {
const filters = ['weixin', 'qq', 'sinaweibo'];
uni.getProvider({
service: 'oauth',
success: (res) => {
if (res.provider && res.provider.length) {
for (let i = 0; i < res.provider.length; i++) {
if (~filters.indexOf(res.provider[i])) {
this.providerList.push({
value: res.provider[i],
image: '../../static/img/' + res.provider[i] + '.png'
});
}
}
this.hasProvider = true;
}
},
fail: (err) => {
console.error('获取服务供应商失败:' + JSON.stringify(err));
}
});
},
initPosition() {
/**
* 使用 absolute 定位,并且设置 bottom 值进行定位。软键盘弹出时,底部会因为窗口变化而被顶上来。
* 反向使用 top 进行定位,可以避免此问题。
*/
this.positionTop = uni.getSystemInfoSync().windowHeight - 100;
},
bindLogin() {
/**
* 客户端对账号信息进行一些必要的校验。
* 实际开发中,根据业务需要进行处理,这里仅做示例。
*/
if (this.account.length < 5) {
uni.showToast({
icon: 'none',
title: '账号最短为 5 个字符'
});
return;
}
if (this.password.length < 6) {
uni.showToast({
icon: 'none',
title: '密码最短为 6 个字符'
});
return;
}
/**
* 下面简单模拟下服务端的处理
* 检测用户账号密码是否在已注册的用户列表中
* 实际开发中,使用 uni.request 将账号信息发送至服务端,客户端在回调函数中获取结果信息。
*/
const data = {
account: this.account,
password: this.password
};
const validUser = service.getUsers().some(function (user) {
return data.account === user.account && data.password === user.password;
});
if (validUser) {
this.toMain(this.account);
} else {
uni.showToast({
icon: 'none',
title: '用户账号或密码不正确',
});
}
},
oauth(value) {
uni.login({
provider: value,
success: (res) => {
uni.getUserInfo({
provider: value,
success: (infoRes) => {
/**
* 实际开发中,获取用户信息后,需要将信息上报至服务端。
* 服务端可以用 userInfo.openId 作为用户的唯一标识新增或绑定用户信息。
*/
this.toMain(infoRes.userInfo.nickName);
}
});
},
fail: (err) => {
console.error('授权登录失败:' + JSON.stringify(err));
}
});
},
toMain(userName) {
this.login(userName);
/**
* 强制登录时使用reLaunch方式跳转过来
* 返回首页也使用reLaunch方式
*/
if (this.forcedLogin) {
uni.reLaunch({
url: '../main/main',
});
} else {
uni.navigateBack();
}
}
},
onLoad() {
this.initPosition();
this.initProvider();
}
}
</script>
<style>
.action-row {
display: flex;
flex-direction: row;
justify-content: center;
}
.action-row navigator {
color: #007aff;
padding: 0 20px;
}
.oauth-row {
display: flex;
flex-direction: row;
justify-content: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.oauth-image {
width: 100px;
height: 100px;
border: 1px solid #dddddd;
border-radius: 100px;
margin: 0 40px;
background-color: #ffffff;
}
.oauth-image image {
width: 60px;
height: 60px;
margin: 20px;
}
</style>
<template>
<view class="content">
<view v-if="hasLogin" class="hello">
<view class="title">
您好 {{userName}},您已成功登录。
</view>
<view class="ul">
<view>这是 uni-app 带登录模板的示例App首页。</view>
<view>在 “我的” 中点击 “退出” 可以 “注销当前账户”</view>
</view>
</view>
<view v-if="!hasLogin" class="hello">
<view class="title">
您好 游客。
</view>
<view class="ul">
<view>这是 uni-app 带登录模板的示例App首页。</view>
<view>在 “我的” 中点击 “登录” 可以 “登录您的账户”</view>
</view>
</view>
</view>
</template>
<script>
import {
mapState
} from 'vuex'
export default {
computed: mapState(['forcedLogin', 'hasLogin', 'userName']),
onLoad() {
if (!this.hasLogin) {
uni.showModal({
title: '未登录',
content: '您未登录,需要登录后才能继续',
/**
* 如果需要强制登录,不显示取消按钮
*/
showCancel: !this.forcedLogin,
success: (res) => {
if (res.confirm) {
/**
* 如果需要强制登录,使用reLaunch方式
*/
if (this.forcedLogin) {
uni.reLaunch({
url: '../login/login'
});
} else {
uni.navigateTo({
url: '../login/login'
});
}
}
}
});
}
}
}
</script>
<style>
.hello {
display: flex;
flex: 1;
flex-direction: column;
}
.title {
color: #8f8f94;
margin-top: 50px;
}
.ul {
font-size: 30px;
color: #8f8f94;
margin-top: 50px;
}
.ul>view {
line-height: 50px;
}
</style>
<template>
<view class="content">
<view class="input-group">
<view class="input-row">
<text class="title">邮箱:</text>
<uni-input type="text" focus clearable v-model="email" placeholder="请输入邮箱"></uni-input>
</view>
</view>
<view class="btn-row">
<button type="primary" class="primary" @tap="findPassword">提交</button>
</view>
</view>
</template>
<script>
import service from '../../service.js';
import uniInput from '../../components/uni-input.vue';
export default {
components: {
uniInput
},
data() {
return {
email: ''
}
},
methods: {
findPassword() {
/**
* 仅做示例
*/
if (this.email.length < 3 || !~this.email.indexOf('@')) {
uni.showToast({
icon: 'none',
title: '邮箱地址不合法',
});
return;
}
uni.showToast({
icon: 'none',
title: '已发送重置邮件至注册邮箱,请注意查收。',
duration: 3000
});
}
}
}
</script>
<style>
</style>
<template>
<view class="content">
<view class="input-group">
<view class="input-row border">
<text class="title">账号:</text>
<uni-input type="text" focus clearable v-model="account" placeholder="请输入账号"></uni-input>
</view>
<view class="input-row border">
<text class="title">密码:</text>
<uni-input type="password" displayable v-model="password" placeholder="请输入密码"></uni-input>
</view>
<view class="input-row">
<text class="title">邮箱:</text>
<uni-input type="text" clearable v-model="email" placeholder="请输入邮箱"></uni-input>
</view>
</view>
<view class="btn-row">
<button type="primary" class="primary" @tap="register">注册</button>
</view>
</view>
</template>
<script>
import service from '../../service.js';
import uniInput from '../../components/uni-input.vue';
export default {
components: {
uniInput
},
data() {
return {
account: '',
password: '',
email: ''
}
},
methods: {
register() {
/**
* 客户端对账号信息进行一些必要的校验。
* 实际开发中,根据业务需要进行处理,这里仅做示例。
*/
if (this.account.length < 5) {
uni.showToast({
icon: 'none',
title: '账号最短为 5 个字符'
});
return;
}
if (this.password.length < 6) {
uni.showToast({
icon: 'none',
title: '密码最短为 6 个字符'
});
return;
}
if (this.email.length < 3 || !~this.email.indexOf('@')) {
uni.showToast({
icon: 'none',
title: '邮箱地址不合法'
});
return;
}
const data = {
account: this.account,
password: this.password,
email: this.email
}
service.addUser(data);
uni.showToast({
title: '注册成功'
});
uni.navigateBack({
delta: 1
});
}
}
}
</script>
<style>
</style>
<template>
<view class="content">
<view class="btn-row">
<button v-if="!hasLogin" type="primary" class="primary" @tap="bindLogin">登录</button>
<button v-if="hasLogin" type="default" @tap="bindLogout">退出登录</button>
</view>
</view>
</template>
<script>
import {
mapState,
mapMutations
} from 'vuex'
export default {
computed: {
...mapState(['hasLogin', 'forcedLogin'])
},
methods: {
...mapMutations(['logout']),
bindLogin() {
uni.navigateTo({
url: '../login/login',
});
},
bindLogout() {
this.logout();
/**
* 如果需要强制登录跳转回登录页面
*/
if (this.forcedLogin) {
uni.reLaunch({
url: '../login/login',
});
}
}
}
}
</script>
<style>
</style>
// 管理账号信息
const USERS_KEY = 'USERS_KEY';
const STATE_KEY = 'STATE_KEY';
const getUsers = function () {
let ret = '';
ret = uni.getStorageSync(USERS_KEY);
if (!ret) {
ret = '[]';
}
return JSON.parse(ret);
}
const addUser = function (userInfo) {
let users = getUsers();
users.push({
account: userInfo.account,
password: userInfo.password
});
uni.setStorageSync(USERS_KEY, JSON.stringify(users));
}
export default {
getUsers,
addUser
}
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
/**
* 是否需要强制登录
*/
forcedLogin: false,
hasLogin: false,
userName: ""
},
mutations: {
login(state, userName) {
state.userName = userName || '新用户';
state.hasLogin = true;
},
logout(state) {
state.userName = "";
state.hasLogin = false;
}
}
})
export default store
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册