写一个uniapp的登录注册页面

目录

一、效果图

二、代码

1、登录

(1)页面布局代码

(2)逻辑实现代码

(3)css样式

2、注册

(1)页面布局代码

(2)逻辑实现代码

(3)css样式

3、接口(所有用到的js)

(1)login.js

(2)request.js

(3)auth.js

(4)common.js

(5)crpto.js

(6)jsencrypt.js

(7)errorCode.js

(8)config.js


一、效果图

二、代码

1、登录
(1)页面布局代码
<template><view class="normal-login-container"><view class="logo-content align-center justify-center flex"><image class="img-a" src="/static/images/b-1.png"></image><image class="img-b" src="/static/images/b-2.png"></image><!-- 标题 --><view class="text"><view class="t-b">{{ title }}</view><view class="t-b2">{{ subTitle }}</view></view></view><view class="login-form-content"><view class="input-item flex align-center"><view class="iconfont icon-user icon"></view><input v-model="loginForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" /></view><view class="input-item flex align-center"><view class="iconfont icon-password icon"></view><input v-model="loginForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" /></view><view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"><view class="iconfont icon-code icon"></view><input v-model="loginForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" /><view class="login-code"> <image :src="codeUrl" @click="getCode" class="login-code-img"></image></view></view><view class="action-btn"><button @click="handleLogin" class="login-btn cu-btn block bg-blue lg round">登录</button></view><view class="reg text-center" v-if="register"><text class="text-grey1">没有账号?</text><text @click="handleUserRegister" class="text-blue">立即注册</text></view><view class="xieyi text-center"><!-- <text class="text-grey1">登录即代表同意</text><text @click="handleUserAgrement" class="text-blue">《用户协议》</text><text @click="handlePrivacy" class="text-blue">《隐私协议》</text> --></view></view></view>
</template>
(2)逻辑实现代码
<script>import { getCodeImg } from '@/api/login'export default {data() {return {title: '管理平台',subTitle: '欢迎回来,开始工作吧!',codeUrl: "",captchaEnabled: true,// 用户注册开关register: true,globalConfig: getApp().globalData.config,loginForm: {username: "admin",password: "admin123",code: "",uuid: ''}}},created() {this.getCode()},methods: {// 用户注册handleUserRegister() {this.$tab.redirectTo(`/pages/register`)},// 隐私协议// handlePrivacy() {//   let site = this.globalConfig.appInfo.agreements[0]//   this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)// },// // 用户协议// handleUserAgrement() {//   let site = this.globalConfig.appInfo.agreements[1]//   this.$tab.navigateTo(`/pages/common/webview/index?title=${site.title}&url=${site.url}`)// },// 获取图形验证码getCode() {getCodeImg().then(res => {res=res.datathis.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabledif (this.captchaEnabled) {this.codeUrl = 'data:image/gif;base64,' + res.imgthis.loginForm.uuid = res.uuid}})},// 登录方法async handleLogin() {if (this.loginForm.username === "") {this.$modal.msgError("请输入您的账号")} else if (this.loginForm.password === "") {this.$modal.msgError("请输入您的密码")} else if (this.loginForm.code === "" && this.captchaEnabled) {this.$modal.msgError("请输入验证码")} else {this.$modal.loading("登录中,请耐心等待...")this.pwdLogin()}},// 密码登录async pwdLogin() {this.$store.dispatch('Login', this.loginForm).then(() => {// console.log(document.response);this.$modal.closeLoading()this.loginSuccess()}).catch(() => {if (this.captchaEnabled) {this.getCode()}})},// 登录成功后,处理函数loginSuccess(result) {// 设置用户信息this.$store.dispatch('GetInfo').then(res => {this.$tab.reLaunch('/pages/index')})}}}
</script>

(3)css样式
<style lang="scss">page {background-color: #ffffff;}.normal-login-container {width: 100%;.logo-content {width: 100%;font-size: 21px;text-align: center;padding-top: 15%;image {border-radius: 4px;}.title {margin-left: 10px;}}.login-form-content {text-align: center;margin: 20px auto;// margin-top: 3%;width: 80%;.input-item {margin: 20px auto;background-color: #f5f6f7;height: 45px;border-radius: 20px;.icon {font-size: 38rpx;margin-left: 10px;color: #999;}.input {width: 100%;font-size: 14px;line-height: 20px;text-align: left;padding-left: 15px;}}.login-btn {margin-top: 40px;height: 45px;}.reg {margin-top: 15px;}.xieyi {color: #333;margin-top: 20px;}.login-code {height: 38px;float: right;.login-code-img {height: 38px;position: absolute;margin-left: 10px;width: 200rpx;}}}}
.img-a {position: absolute;width: 100%;top: -74px;right: 0;z-index: 100;
}
.img-b {position: absolute;width: 50%;bottom: 0;left: -50rpx;z-index: 100;
}
.text{margin-left: -111px;margin-top: 28px;
}
.t-b {text-align: left;font-size: 29px;color: #000;padding: 60px 0 10px 0;font-weight: bold;
}
.t-b2 {text-align: left;font-size: 32rpx;color: #aaaaaa;padding: 0rpx 0 60rpx 0;
}</style>
2、注册
(1)页面布局代码
<template><view class="normal-login-container"><view class="logo-content align-center justify-center flex"><!-- <image style="width: 100rpx;height: 100rpx;" :src="globalConfig.appInfo.logo" mode="widthFix"></image> --><image class="img-a" src="/static/images/b-1.png"></image><image class="img-b" src="/static/images/b-2.png"></image><text class="title">绣创科技移动端注册</text></view><view class="login-form-content"><view class="input-item flex align-center"><view class="iconfont icon-user icon"></view><input v-model="registerForm.username" class="input" type="text" placeholder="请输入账号" maxlength="30" /></view><view class="input-item flex align-center"><view class="iconfont icon-password icon"></view><input v-model="registerForm.password" type="password" class="input" placeholder="请输入密码" maxlength="20" /></view><view class="input-item flex align-center"><view class="iconfont icon-password icon"></view><input v-model="registerForm.confirmPassword" type="password" class="input" placeholder="请输入重复密码" maxlength="20" /></view><view class="input-item flex align-center" style="width: 60%;margin: 0px;" v-if="captchaEnabled"><view class="iconfont icon-code icon"></view><input v-model="registerForm.code" type="number" class="input" placeholder="请输入验证码" maxlength="4" /><view class="login-code"> <image :src="codeUrl" @click="getCode" class="login-code-img"></image></view></view><view class="action-btn"><button @click="handleRegister()" class="register-btn cu-btn block bg-blue lg round">注册</button></view></view><view class="xieyi text-center"><text @click="handleUserLogin" class="text-blue">使用已有账号登录</text></view></view>
</template>
(2)逻辑实现代码
<script>import { getCodeImg, register } from '@/api/login'export default {data() {return {codeUrl: "",captchaEnabled: true,globalConfig: getApp().globalData.config,registerForm: {username: "",password: "",confirmPassword: "",code: "",uuid: '',userType:"app_user"}}},created() {this.getCode()},methods: {// 用户登录handleUserLogin() {this.$tab.navigateTo(`/pages/login`)},// 获取图形验证码getCode() {getCodeImg().then(res => {this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabledif (this.captchaEnabled) {this.codeUrl = 'data:image/gif;base64,' + res.data.imgthis.registerForm.uuid = res.data.uuid}})},// 注册方法async handleRegister() {if (this.registerForm.username === "") {this.$modal.msgError("请输入您的账号")} else if (this.registerForm.password === "") {this.$modal.msgError("请输入您的密码")} else if (this.registerForm.confirmPassword === "") {this.$modal.msgError("请再次输入您的密码")} else if (this.registerForm.password !== this.registerForm.confirmPassword) {this.$modal.msgError("两次输入的密码不一致")} else if (this.registerForm.code === "" && this.captchaEnabled) {this.$modal.msgError("请输入验证码")} else {this.$modal.loading("注册中,请耐心等待...")this.register()}},// 用户注册async register() {register(this.registerForm).then(res => {this.$modal.closeLoading()uni.showModal({title: "系统提示",content: "恭喜你,您的账号 " + this.registerForm.username + " 注册成功!",success: function (res) {if (res.confirm) {uni.redirectTo({ url: `/pages/login` });}}})}).catch(() => {if (this.captchaEnabled) {this.getCode()}})},// 注册成功后,处理函数registerSuccess(result) {// 设置用户信息this.$store.dispatch('GetInfo').then(res => {this.$tab.reLaunch('/pages/index')})}}}
</script>
(3)css样式
<style lang="scss">page {background-color: #ffffff;}.normal-login-container {width: 100%;.logo-content {width: 100%;font-size: 21px;text-align: center;padding-top: 15%;image {border-radius: 4px;}.title {margin-left: 10px;position: absolute;z-index: 100;}}.login-form-content {text-align: center;margin: 20px auto;margin-top: 30%;width: 80%;.input-item {margin: 20px auto;background-color: #f5f6f7;height: 45px;border-radius: 20px;.icon {font-size: 38rpx;margin-left: 10px;color: #999;}.input {width: 100%;font-size: 14px;line-height: 20px;text-align: left;padding-left: 15px;}}.register-btn {margin-top: 40px;height: 45px;}.xieyi {color: #333;margin-top: 20px;}.login-code {height: 38px;float: right;.login-code-img {height: 38px;position: absolute;margin-left: 10px;width: 200rpx;}}}}
.img-a {position: absolute;width: 100%;top: -74px;right: 0;z-index: 100;
}
.img-b {position: absolute;width: 50%;bottom: 0;left: -50rpx;z-index: 100;
}
</style>
3、接口(所有用到的js)
(1)login.js
import request from '@/utils/request'// 登录方法
export function login(username, password, code, uuid) {const data = {username,password,code,uuid}return request({'url': '/login',headers: {isToken: false},'method': 'post','data': data})
}// 注册方法
export function register(data) {return request({url: '/register',headers: {isToken: false},method: 'post',data: data})
}// 获取用户详细信息
export function getInfo() {return request({'url': '/getInfo','method': 'get'})
}// 退出方法
export function logout() {return request({'url': '/logout','method': 'post'})
}// 获取验证码
export function getCodeImg() {return request({'url': '/captchaImage',headers: {isToken: false},method: 'get',timeout: 20000})
}
(2)request.js
import store from '@/store'
import config from '@/config'
import { getToken } from '@/utils/auth'
import errorCode from '@/utils/errorCode'
import { toast, showConfirm, tansParams } from '@/utils/common'
import { encryptBase64, encryptWithAes, generateAesKey } from '@/utils/crypto';
import { encrypt } from '@/utils/jsencrypt';let timeout = 10000
const baseUrl = config.baseUrl
const clientId = config.clientIdconst request = config => {// 是否需要设置 tokenconst isToken = (config.headers || {}).isToken === falseconfig.header = config.header || {}if (getToken() && !isToken) {config.header['Authorization'] = 'Bearer ' + getToken()}config.header['clientid']=clientId// get请求映射params参数if (config.params) {let url = config.url + '?' + tansParams(config.params)url = url.slice(0, -1)config.url = url}// 是否需要加密const isEncrypt = (config.headers || {}).isEncrypt === true;// 当开启参数加密if (isEncrypt && (config.method === 'post' || config.method === 'put')) {// 生成一个 AES 密钥const aesKey = generateAesKey();config.header['encrypt-key'] = encrypt(encryptBase64(aesKey));config.data = typeof config.params === 'object' ? encryptWithAes(JSON.stringify(config.params), aesKey) : encryptWithAes(config.params, aesKey);}return new Promise((resolve, reject) => {uni.request({method: config.method || 'get',timeout: config.timeout ||  timeout,url: config.baseUrl || baseUrl + config.url,data: config.data,header: config.header,dataType: 'json'}).then(response => {let [error, res] = responseif (error) {toast('后端接口连接异常')reject('后端接口连接异常')return}const code = res.data.code || 200const msg = errorCode[code] || res.data.msg || errorCode['default']if (code === 401) {showConfirm('登录状态已过期,您可以继续留在该页面,或者重新登录?').then(res => {if (res.confirm) {store.dispatch('LogOut').then(res => {uni.reLaunch({ url: '/pages/login' })})}})reject('无效的会话,或者会话已过期,请重新登录。')} else if (code === 500) {toast(msg)reject('500')} else if (code !== 200) {toast(msg)reject(code)}resolve(res.data)}).catch(error => {let { message } = errorif (message === 'Network Error') {message = '后端接口连接异常'} else if (message.includes('timeout')) {message = '系统接口请求超时'} else if (message.includes('Request failed with status code')) {message = '系统接口' + message.substr(message.length - 3) + '异常'}toast(message)reject(error)})})
}export default request
(3)auth.js
const TokenKey = 'App-Token'export function getToken() {return uni.getStorageSync(TokenKey)
}export function setToken(token) {return uni.setStorageSync(TokenKey, token)
}export function removeToken() {return uni.removeStorageSync(TokenKey)
}
(4)common.js
/**
* 显示消息提示框
* @param content 提示的标题
*/
export function toast(content) {uni.showToast({icon: 'none',title: content})
}/**
* 显示模态弹窗
* @param content 提示的标题
*/
export function showConfirm(content) {return new Promise((resolve, reject) => {uni.showModal({title: '提示',content: content,cancelText: '取消',confirmText: '确定',success: function(res) {resolve(res)}})})
}/**
* 参数处理
* @param params 参数
*/
export function tansParams(params) {let result = ''for (const propName of Object.keys(params)) {const value = params[propName]var part = encodeURIComponent(propName) + "="if (value !== null && value !== "" && typeof (value) !== "undefined") {if (typeof value === 'object') {for (const key of Object.keys(value)) {if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {let params = propName + '[' + key + ']'var subPart = encodeURIComponent(params) + "="result += subPart + encodeURIComponent(value[key]) + "&"}}} else {result += part + encodeURIComponent(value) + "&"}}}return result
}
(5)crpto.js
import CryptoJS from 'crypto-js';/*** 随机生成32位的字符串* @returns {string}*/
export function generateRandomString(){const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';let result = '';const charactersLength = characters.lengthfor (let i = 0; i < 32; i++) {result += characters.charAt(Math.floor(Math.random() * charactersLength));}return result
}/*** 随机生成aes 密钥* @returns {string}*/
export function generateAesKey(){return CryptoJS.enc.Utf8.parse(generateRandomString());
}/*** 加密base64* @returns {string}*/
export function encryptBase64(str){return CryptoJS.enc.Base64.stringify(str);
}/*** 使用密钥对数据进行加密* @param message* @param aesKey* @returns {string}*/
export function encryptWithAes(message, aesKey){const encrypted = CryptoJS.AES.encrypt(message, aesKey, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7});return encrypted.toString();
}
(6)jsencrypt.js
import JSEncrypt from 'jsencrypt';
// 密钥对生成 http://web.chacuo.net/netrsakeypairconst publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==';// 前端不建议存放私钥 不建议解密数据 因为都是透明的意义不大
const privateKey = '**********';// 加密
export function encrypt(txt){const encryptor = new JSEncrypt();encryptor.setPublicKey(publicKey); // 设置公钥return encryptor.encrypt(txt); // 对数据进行加密
};// 解密
export function decrypt(txt){const encryptor = new JSEncrypt();encryptor.setPrivateKey(privateKey); // 设置私钥return encryptor.decrypt(txt); // 对数据进行解密
};
(7)errorCode.js
export default {'401': '认证失败,无法访问系统资源','403': '当前操作没有权限','404': '访问资源不存在','default': '系统未知错误,请反馈给管理员'
}
(8)config.js
// 应用全局配置
module.exports = {baseUrl: 'http://localhost:8080',//根据实际更换//客户端idclientId:'...............',//授权模式grantType:'password',//租户idtenantId: '000000',//记住我模式rememberMe: false,// 应用信息appInfo: {// 应用名称name: "...",// 应用版本version: "1.1.0",// 应用logologo: "/static/logo.png",// 官方网站site_url: "...",// 政策协议agreements: [{title: "隐私政策",url: "..."},{title: "用户服务协议",url: "..."}]}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/855.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一个完全用rust写的开源操作系统-Starry

1. Starry Starry是2023年全国大学生计算机系统能力大赛操作系统设计赛-内核实现赛的二等奖作品。Starry是在组件化OS的arceos的基础上&#xff0c;进行二次开发的操作系统内核&#xff0c;使用宏内核架构&#xff0c;能够运行Linux应用的内核。 原始的操作系统大赛的仓库为 …

51-42 NÜWA:女娲,统一的多模态预训练模型

21年11月&#xff0c;微软、北大联合发布了NUWA模型&#xff0c;一个统一的多模态预训练模型&#xff0c;在 8 个下游任务上效果惊艳。目前该项目已经发展成为一系列工作&#xff0c;而且都公开了源代码。 Abstract 本文提出了一种统一的多模态预训练模型N̈UWA&#xff0c;该…

【精简改造版】大型多人在线游戏BrowserQuest服务器Golang框架解析(1)——功能清单

1.匿名登录 2.服务连接 3.新手引导 4.随机出生点 5.界面布局 6.玩法帮助 7.NPC会话 8.成就系统 9.成就达成 10.用户聊天 11.战斗&信息展示 12.药水使用 13.副本传送 14.玩家死亡 15.超时断开

实验:使用FTP+yum实现自制yum仓库

实验准备 FTP服务器端&#xff1a;centos-1&#xff08;IP:10.9.25.33&#xff09; 客户端&#xff1a;centos-2 两台机器保证网络畅通&#xff0c;原yum仓库可用&#xff0c;已关闭防火墙和selinux FTP服务器端 ①安装vsftpd并运行&#xff0c;设定开机自启动 安装vsftpd…

金融数字化能力成熟度指引

1 范围 本文件提出了金融数字化能力成熟度模型、成熟度计算方法&#xff0c;明确了不同维度金融数字化转型能力 相应的分档要求。 本文件适用于金融机构衡量金融科技应用和数字化转型发展水平&#xff0c;检视自身数字化发展优势与短板&#xff0c; 加快数字化转型&#xff0c…

金蝶云星空和金蝶云星空单据接口对接

金蝶云星空和金蝶云星空单据接口对接 来源系统:金蝶云星空 金蝶K/3Cloud结合当今先进管理理论和数十万家国内客户最佳应用实践&#xff0c;面向事业部制、多地点、多工厂等运营协同与管控型企业及集团公司&#xff0c;提供一个通用的ERP服务平台。K/3Cloud支持的协同应用包括但…

Linux Makefile

1.开发背景 linux 下编译程序需要用到对应的 Makefile&#xff0c;用于编译应用程序。 2.开发需求 编写 Makefile 编译应用程序 1&#xff09;支持多个源文件 2&#xff09;支持多个头文件 3&#xff09;支持只编译修改的文件&#xff0c;包括源文件和头文件 4&#xff09;支持…

Web程序设计-实验03 JavaScript语言基础

题目 【实验主题】 素数问题求解。计算&#xff08;判断&#xff09; 1~100中哪些是素数、哪些是合数。 素数也称为质数&#xff0c;是只能被1及其自身整除的自然数。与素数相对应的是合数&#xff0c;合数可以被分解为若干个素数的乘积&#xff0c;这些素数称为这个合数的质…

数据结构从入门到实战——顺序表的应用

目录 一、基于动态顺序表实现通讯录 二、代码实现 2.1 通讯录的初始化 2.2 通讯录的销毁 2.3 通讯录的展示 2.4 通讯录添加联系人信息 2.5 通讯录删除联系人信息 2.6 通讯录修改联系人信息 2.7 通讯录的查找联系人信息 2.8 将通讯录中联系人信息保存到文件中 2.9…

【Windows10】Anaconda3安装+pytorch+tensorflow+pycharm

文章目录 一、下载anaconda0.双击下载的文件1. 选择All users2. 安装路径3. 勾选环境变量和安装python4.安装完成5.添加环境变量6.测试是否安装成功 二、安装pytorch&#xff08;先看四&#xff01;先检查一下自己电脑是不是只能安装GPU版的1.查看conda图形化界面2.在安装pytor…

【图解计算机网络】网络协议分层解析

网络协议分层解析 网络协议分层应用层传输层网络层数据链路层 TCP/IP分层模型通讯示例 网络协议分层 网络协议分层一共有OSI七层网络协议&#xff0c;TCP/IP四层网络网络协议&#xff0c;还有五层网络协议。 七层由于分层太多过于复杂&#xff0c;实际应用中并没有使用&#x…

代码编辑工具PilotEditPro18.4版本在Windows系统的下载与安装配置

目录 前言一、PilotEdit Pro安装二、使用配置总结 前言 “ PilotEdit Pro是一个功能强大且功能丰富的文本和代码编辑器&#xff0c;可满足程序员、开发人员和IT专业人员的不同需求。定位为一个多功能的编辑解决方案&#xff0c;PilotEdit Pro以其对广泛的文本和代码文件格式的…

Nginx莫名奇妙返回了404

描述 nginx作为反向代理&#xff0c;代理python的服务&#xff0c;但是通过代理访问服务的时候&#xff0c;报了404的错误。 难受的是客户现场没有查看日志的权限&#xff0c;只有查看配置文件的权限&#xff0c;我们检测了几遍配置文件也没有找到问题&#xff0c;哎~ 问题引…

相机摄影入门技巧,数码摄影技巧大全

一、资料前言 本套数码相机摄影资料&#xff0c;大小1.08G&#xff0c;共有42个文件。 二、资料目录 《aking人像摄影技巧分享》.pdf 《Nikon.D90数码单反摄影技巧大全》FUN视觉.全彩版.pdf 《不可不学的摄影技巧》.pdf 《常用场景摄影》.pdf 《单反数码摄影专家技法》.…

【Web】AFCTF 2021 题解(部分)

目录 BABY_CSP search secret google authenticator 随便做做&#xff0c;环境是NSS上的 BABY_CSP CSP绕过_script-src self-CSDN博客 CSP指令值 *&#xff1a; 星号表示允许任何URL资源&#xff0c;没有限制&#xff1b; self&#xff1a; 表示仅允许来自同源&#xff…

盲人购物指南:智能化辅助引领超市购物新体验

作为一名资深记者&#xff0c;我有幸见证了一位盲人朋友借助一款名为蝙蝠避障的高科技辅助应用&#xff0c;独立完成超市购物之旅&#xff0c;这一过程充分展示了盲人购物指南新时代的到来。 在前往超市的路上&#xff0c;这款应用犹如一位贴心的“电子向导”&#xff0c;实时为…

Android Room 记录一个Update语句不生效的问题解决记录

代码展示 1.数据实体类 Entity public class User {PrimaryKey(autoGenerate true)private long id;private String name;private String age;private String sex;public User(String name, String age, String sex) {this.name name;this.age age;this.sex sex;}public …

【剪映专业版】14为视频添加炫酷特效

视频课程&#xff1a;B站有知公开课【剪映电脑版教程】 1.特效 画面特效&#xff1a;用于整个画面 人物特效&#xff1a;仅用于画面中的人物&#xff0c;如画面中无人&#xff0c;则不起作用 2.添加特效 按号添加 可通过鼠标推动实现特效时间调节 可叠加使用特效 3.特效修…

危险场景智能运维巡检系统

在石油、天然气、煤炭和化工等行业&#xff0c;特别是在I/IIC级防爆区场景中&#xff0c;存在着诸如易燃、易爆、高温、有毒有害以及粉尘等危险因素。例如&#xff0c;油气转运站、催化裂化装置、煤化工甲醇车间以及制氢站等地点&#xff0c;都面临着这些潜在的危险。传统的人工…

34. 【Android教程】菜单:Menu

作为 Android 用户&#xff0c;你一定见过类似这样的页面&#xff1a; 它就是我们今天的主角——菜单&#xff0c;它的使用场景和作用不用多说&#xff0c;几乎每个 App 都会用到它&#xff0c;今天我们就一起来看看 Android 提供的几种菜单类型及用法。 1. 菜单的几种类型 根…