uni-app项目分析:
背景:最近接手一个前同事留下的半拉子项目,出拿过来觉得很简单;当我看到app.vue的时候很确定是vue项目,心里不怎么慌,果断安装node.js,然后就去npm ;安装VS code,事实并不是我期盼的那样,或者说根本就不能运行。
报错:应用vs code打开文件,输入命令npm run dev,项目根本就没有运行,一直显示缺少一个package.json文件。
最后由于进度问题,只能去找前同事,听他说前端这几年变化挺大,项目可能适用的是其他编译器,再三辗转确定是HBuilder X。
一番操作之后,我下载了HBuilder X之后,运行项目其实也不是很顺利,因为这个编译器虽然是免安装的,但是运行之后就会提示缺少运行的插件,还好都是无脑安装。
项目运行后才发向,项目根本没有后台服务,当时心中有一万只羊驼一闪而过;这样的项目怎么还说是成功运行的?不管三七二十一,我先利用HBuilderX的内置管理器进行运行,登录的界面如下:
为了进一步弄清uni.app开发程序的架构,首先打开APP.vue希望从这里查到一点蛛丝马迹,如下图所示:
上图可以看到这个文件只有style样式和默认的Script方法;于是乎我只能从pages.json
这里的json文件都是一些路径组合,从 注解中了解到uni.app开发vue程序的启动格式:
//pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
之后点击完对应的参考了解到:
pages.json 页面路由
pages.json
文件用来对 uni-app 进行全局配置,决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。
它类似微信小程序中app.json
的页面管理部分。注意定位权限申请等原属于app.json
的内容,在uni-app中是在manifest中配置。
以下是一个包含了所有配置选项的 pages.json
:
{
"pages": [{
"path": "pages/component/index",
"style": {
"navigationBarTitleText": "组件"
}
}, {
"path": "pages/API/index",
"style": {
"navigationBarTitleText": "接口"
}
}, {
"path": "pages/component/view/index",
"style": {
"navigationBarTitleText": "view"
}
}],
"condition": { //模式配置,仅开发期间生效
"current": 0, //当前激活的模式(list 的索引项)
"list": [{
"name": "test", //模式名称
"path": "pages/component/view/index" //启动页面,必选
}]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "演示",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8",
"usingComponents":{
"collapse-tree-item":"/components/collapse-tree-item"
},
"renderingMode": "seperated", // 仅微信小程序,webrtc 无法正常时尝试强制关闭同层渲染
"pageOrientation": "portrait", //横屏配置,全局屏幕旋转设置(仅 APP/微信/QQ小程序),支持 auto / portrait / landscape
"rpxCalcMaxDeviceWidth": 960,
"rpxCalcBaseDeviceWidth": 375,
"rpxCalcIncludeWidth": 750
},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"height": "50px",
"fontSize": "10px",
"iconWidth": "24px",
"spacing": "3px",
"iconfontSrc":"static/iconfont.ttf", // app tabbar 字体.ttf文件路径 app 3.4.4+
"list": [{
"pagePath": "pages/component/index",
"iconPath": "static/image/icon_component.png",
"selectedIconPath": "static/image/icon_component_HL.png",
"text": "组件",
"iconfont": { // 优先级高于 iconPath,该属性依赖 tabbar 根节点的 iconfontSrc
"text": "\ue102",
"selectedText": "\ue103",
"fontSize": "17px",
"color": "#000000",
"selectedColor": "#0000ff"
}
}, {
"pagePath": "pages/API/index",
"iconPath": "static/image/icon_API.png",
"selectedIconPath": "static/image/icon_API_HL.png",
"text": "接口"
}],
"midButton": {
"width": "80px",
"height": "50px",
"text": "文字",
"iconPath": "static/image/midButton_iconPath.png",
"iconWidth": "24px",
"backgroundImage": "static/image/midButton_backgroundImage.png"
}
},
"easycom": {
"autoscan": true, //是否自动扫描组件
"custom": {//自定义扫描规则
"^uni-(.*)": "@/components/uni-$1.vue"
}
},
"topWindow": {
"path": "responsive/top-window.vue",
"style": {
"height": "44px"
}
},
"leftWindow": {
"path": "responsive/left-window.vue",
"style": {
"width": "300px"
}
},
"rightWindow": {
"path": "responsive/right-window.vue",
"style": {
"width": "300px"
},
"matchMedia": {
"minWidth": 768
}
}
}
接下来首先打开登录页面pages/index/index.vue页面,我们近一步分析:首先看一下Template代码:
<template>
<view class="main">
<!-- 登录框 -->
<view class="loginBox">
<view class="vv"></view>
<view class="logoImgBox">
<image :src="loginImage" mode=""></image>
</view>
<view class="loginInptu">
<input type="text" class="username" value="" placeholder="请输入用户名" maxlength="11" @input="phoneInput"/>
</view>
<view class="loginInptu" >
<input type="password" class="password" value="" placeholder="请输入密码" maxlength="16" @input="passwordInpur"/>
</view>
<view class="loginUp" @click="login">
<image src="../../static/denglu.png" mode=""></image>
</view>
</view>
</view>
</template>
由上可以看到Template中可以看到:
有两个输入框input,利用不同的class设置是文本输入框还是密码输入框,并且定义了默认的placeholder提示信息,以及对应的数据长度maxlength;
一个图标形式的登录按钮,对应一个@Click的"login"事件。
从上有的template中我们还可以看到一个现场就是template中的所有的视图元素都是包裹在<view></View>标签中,这应该时uni.app的一种书写格式。
最近开了uni-app的官方文档了解到<view></View>相当于html中的<div></div>,意思应该同<div>
元素 (或 HTML 文档分区元素) 是一个通用型的流内容容器,在不使用CSS的情况下,其对内容或布局没有任何影响。此部分内容更新于2024-04-05.
接着我们对login函数进行分析:
<script>
export default {
data() {
return {
loginMode: 1,
usernameType:"text",
codeBut:"获取验证码",
loginImage:"../../static/logo.png",
codeClick:true,
phone:"",
password:"",
code:"",
username:"",
loginres:0,
}
},
onLoad() {
},
methods: {
gotoMenu(){
uni.navigateTo({
url:"/pages/menu/menu/menu"
})
},
login()
{
uni.request({
url: 'http://127.0.0.1:5034/Login/Login2',
method: 'GET',
data: { g_UserID: this.username, g_Password: this.password},
success: (res) => {
console.log('数据:'+this.username+this.password);
//console.log(res.data);
var loginres = res.data.loginres;
console.log('loginres:'+loginres);
//var _that = this
if(loginres == 1){
//console.log(res.data)
uni.showToast({
title: '登录成功',
icon: 'none',
duration:2000,
});
this.$globals.us = this.username;
uni.navigateTo({
url:"/pages/menu/menu/menu"
});
this.loginres = 0;
}
else if(loginres != 1){
uni.showToast({
title: '登录失败',
icon: 'none',
duration:2000
});
this.loginres = 0;
};
},
fail: () => {console.log('登录失败'+this.username+this.password);},
complete: () => {console.log('完成');}
});
},
}
}
</script>
在分析login方法时我们首先需要看一下Script怎么定义的数据:
export default {
data() {
return {
loginMode: 1,
usernameType:"text",
codeBut:"获取验证码",
loginImage:"../../static/logo.png",
codeClick:true,
phone:"",
password:"",
code:"",
username:"",
loginres:0,
}
}
这个方法中我们可以看到所有在界面中会适用的参数及类型。
在来看一下method:{}中的方法:
methods: {
gotoMenu(){
uni.navigateTo({
url:"/pages/menu/menu/menu"
})
},
login()
{
uni.request({
url: 'http://127.0.0.1:5034/Login/Login2',
method: 'GET',
data: { g_UserID: this.username, g_Password: this.password},
success: (res) => {
console.log('数据:'+this.username+this.password);
//console.log(res.data);
var loginres = res.data.loginres;
console.log('loginres:'+loginres);
//var _that = this
if(loginres == 1){
//console.log(res.data)
uni.showToast({
title: '登录成功',
icon: 'none',
duration:2000,
});
this.$globals.us = this.username;
uni.navigateTo({
url:"/pages/menu/menu/menu"
});
this.loginres = 0;
}
else if(loginres != 1){
uni.showToast({
title: '登录失败',
icon: 'none',
duration:2000
});
this.loginres = 0;
};
},
fail: () => {console.log('登录失败'+this.username+this.password);},
complete: () => {console.log('完成');}
});
},
}
method的中有两个方法:
gotoMenu(){
uni.navigateTo({
url:"/pages/menu/menu/menu"
})
},
这个方法从名称中可以看到是一个跳转功能,跳转的页面是项目下/pages/menu/menu/menu页面:
uni.request({
url: 'http://127.0.0.1:5034/Login/Login2',
method: 'GET',
data: { g_UserID: this.username, g_Password: this.password},
success: (res) => {
console.log('数据:'+this.username+this.password);
//console.log(res.data);
var loginres = res.data.loginres;
console.log('loginres:'+loginres);
//var _that = this
if(loginres == 1){
//console.log(res.data)
uni.showToast({
title: '登录成功',
icon: 'none',
duration:2000,
});
this.$globals.us = this.username;
uni.navigateTo({
url:"/pages/menu/menu/menu"
});
this.loginres = 0;
}
else if(loginres != 1){
uni.showToast({
title: '登录失败',
icon: 'none',
duration:2000
});
this.loginres = 0;
};
},
fail: () => {console.log('登录失败'+this.username+this.password);},
complete: () => {console.log('完成');}
});
},
另一个方法是request一个路径,data: { g_UserID: this.username, g_Password: this.password}是传入的对应参数,可以看到:
success: (res) => {
console.log('数据:'+this.username+this.password);
//console.log(res.data);
var loginres = res.data.loginres;
console.log('loginres:'+loginres);
//var _that = this
if(loginres == 1){
//console.log(res.data)
uni.showToast({
title: '登录成功',
icon: 'none',
duration:2000,
});
this.$globals.us = this.username;
uni.navigateTo({
url:"/pages/menu/menu/menu"
});
this.loginres = 0;
}
else if(loginres != 1){
uni.showToast({
title: '登录失败',
icon: 'none',
duration:2000
});
this.loginres = 0;
};
},
这段逻辑意思是登录成功后,首先在控制台打印调用接口时的参数,在根据 res.data.loginres的值判断进行弹窗显示,弹窗部分的代码:
uni.showToast({
title: '登录成功',
icon: 'none',
duration:2000,
});
接着是this.$globals.us = this.username;别看只有一句代码,这句的意思是将用户名放入到global中,这个后期可做全局对象处理页面之间的权限验证等功能,按住alt+鼠标左键可以看到,对应的文件config.js
接着是登录成功后跳转对应的menu菜单页面:
uni.navigateTo({
url:"/pages/menu/menu/menu"
});
因此我按照前台数据类型,写了一个登录成功的方法,先看看菜单栏的功能,后台代码如下:
成功跳转后的功能如图:
码字不易,如果您觉的我的文章对您有帮助的话,建议您在经济能力之内慷慨打赏一元给我买瓶水, 这将是我下一步继续书写本题目的动力;如果您囊肿羞涩也没有关系,希望您点个关注,写点评论;您的支持将是我创作之路上的无线动力;青山依旧绿水长流,希望我们下期来能再见。