之前没有完整的写过H5端的项目,最近写了一个点餐商家版的项目,来复盘一下,我之前没有遇到过的知识盲区吧!
首先第一点,我这个项目是基于uni-app框架写的,创建时直接用的模板。本着之前用uni-app框架写过一个电商小程序的经验来说,我这次也用着这个电商的请求数据方式(即没有封装request.js),那么我们是怎么实现的呢?我们来回忆一下!
// #ifndef VUE3
import Vue from 'vue'
import App from './App'
// import * as config from './config/config.js'
// 引入全局uView
import uView from '@/uni_modules/uview-ui'
// 按需导入$http对象
import {
$http
} from "@escook/request-miniprogram"
// 将$http挂载到uni顶级对象之上,方便全局使用
uni.$http = $http
//配置baseUrl
$http.baseUrl = process.env.VUE_APP_TITLE == '生产环境' ? process.env.VUE_APP_BASE_API : '/api'
// 请求拦截器
$http.beforeRequest = function(options) {
const token = uni.getStorageSync('token')
const pages = getCurrentPages()
const currentPage = pages[pages.length-1]
const currentRoute = currentPage.route
// 如果当前页面为登录页面,则不显示loading
if(currentRoute === 'pages/login/login'){
wx.hideLoading()
}else{
wx.showLoading({
title: '数据加载中...',
})
}
options.header = {
token: token,
}
}
// 响应拦截器
$http.afterRequest = function(resp) {
if(resp.message == 'token不存在' || resp.data.message == 'token不存在'){
uni.showToast({
title:'请先登录!',
duration:1000,
icon:'error'
})
setTimeout(()=>{
uni.reLaunch({
url:'/pages/login/login'
})
},2000)
}
wx.hideLoading()
}
Vue.use(uView)
Vue.config.productionTip = false
App.mpType = 'app'
const app = new Vue({
...App
})
app.$mount()
// #endif
// #ifdef VUE3
import {
createSSRApp
} from 'vue'
import App from './App.vue'
export function createApp() {
const app = createSSRApp(App)
return {
app
}
}
// #endif
可以看到,主要分为以下几步:
按需导入$http对象
import { $http } from "@escook/request-miniprogram"
将$http挂载到uni顶级对象之上,方便全局使用
uni.$http = $http
配置baseUrl(因为我们配置了代理,在生产环境是不支持代理的,所以我们在这是需要进行判断的)
$http.baseUrl = process.env.VUE_APP_TITLE == '生产环境' ? process.env.VUE_APP_BASE_API : '/api'
请求拦截器
我们在这个请求拦截器里,添加了【 wx.showLoading({ title: '数据加载中...' })】,在响应拦截器里添加了【wx.hideLoading()】,是为了在我们进行数据请求的时候,用户有更好的使用体验,知道自己请求了,但是因为网络的原因,会有个等待的过程。
但是我们在登录的时候,也属于一个请求。可能用户名或者密码输入错了,有个错误提示,但是同时也有这个【数据加载中……】的提示,这样用户体验可能就不太好,所以我使用了下面的方法,把login页面的请求排除在外了。
const pages = getCurrentPages()
const currentPage = pages[pages.length-1]
const currentRoute = currentPage.route
// 如果当前页面为登录页面,则不显示loading
if(currentRoute === 'pages/login/login'){
wx.hideLoading()
}else{
wx.showLoading({
title: '数据加载中...',
})
}
响应拦截器
我们刚刚说到了配置代理,那么怎么配置代理呢?
有两种方式:
修改manifest.json文件(找到mainfest.json => 源码视图,添加H5配置项)
"h5" : {
"devServer" : {
"disableHostCheck" : true,
"proxy" : {
"/api" : {
"target" : "http://www.dzm.com",
"changeOrigin" : true,
"secure" : false,
"ws": false,
"pathRewrite" : {
"^/api" : ""
}
}
}
}
}
添加vue.config.js文件
uni-app会识别vue.config.js文件,但是mainfest.json的优先级要高于vue.config.js文件,所以看需求选择一个配置即可。
像vue开发一样,手动创建一个vue.config.js文件,然后添加上代理,vue.config.js只能创建在项目的根目录,不然会无法识别到。
module.exports = {
devServer: {
disableHostCheck: true,
proxy: {
'/api': {
target: 'http://www.dzm.com',
changeOrigin: true,
secure: false,
ws: false,
pathRewrite: {
'^/api': ''
}
}
}
}
}
今天遇到一个问题,我觉得挺神奇的,不是有多难,而是我没有写过,作此笔记,方便自己查看!
在 iOS 和安卓系统上,TabBar 的高度是不同的,并且不同的设备上也可能不同。为了实现 TabBar 的自适应高度,可以使用以下代码:
.tab-bar {
height: calc(env(safe-area-inset-bottom) + 50px);
}
在上述代码中,我们使用了 calc() 函数和 env() 函数来计算 TabBar 的高度。env() 函数用于获取当前设备的安全区域大小,safe-area-inset-bottom 表示底部的安全区域大小,而 50px 则表示 TabBar 的默认高度。通过这样的计算,可以实现 TabBar 的自适应高度。
在实际开发中,你还可以使用 JavaScript 来动态计算 TabBar 的高度,例如:
在上述代码中,我们使用了一个 container 容器元素,其中包括了一个 main-content 元素用于显示页面主要内容,以及一个自适应高度的 tab-bar 元素用于显示 TabBar。
在 CSS 样式中,我们使用了 flex 布局来实现 TabBar 的布局,使用了 calc() 函数和 env() 函数来计算 TabBar 的高度。
在 JavaScript 中,我们在页面加载完成后获取当前设备的底部安全区域大小,并计算出 TabBar 的高度,最后将计算得到的高度应用到 tab-bar 元素上。
需要注意的是,在实际开发中,如果你在多个页面中都需要使用自适应高度的 TabBar,你可以将计算高度的 JavaScript 代码抽取出来,放到一个单独的公共模块中,然后在各个页面中引用。这样可以避免代码重复,并提高代码的可维护性。
使用ECharts在Uni-App中创建图表的基本步骤:
安装ECharts插件,可使用插件市场中的插件或者运行命令npm install echarts --save进行安装。
在需要使用图表的页面中导入ECharts插件:
import * as echarts from 'echarts';
创建一个空的canvas元素,用于渲染图表:
在页面的onReady生命周期中初始化图表:
import * as echarts from 'echarts';
export default {
onReady() {
this.initChart();
},
methods: {
initChart() {
let chart = null;
this.$nextTick(() => {
chart = echarts.init(this.$refs.ecChart, null, {
width: uni.upx2px(750),
height: uni.upx2px(400)
});
//构建图表的配置项,例如:
const option = {
title: {
text: 'ECharts Demo'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
chart.setOption(option);
this.chart = chart;
});
}
}
}
在图表的其他方法中,例如onLoad、onUnload等方法中,对图表进行操作:
onUnload() {
// 销毁图表实例
if (this.chart) {
this.chart.dispose();
}
}
对于checkBox复选框,我在uniapp中可能是我不太熟悉吧,我踩了很多坑,我来总结一下我在uniapp框架的用法和uview的用法:
先看结构:
//每一个商品前的单选框
//全选按钮
全选
JS:
// 单个商品的选择
checkClick(item) {
item.checked = !item.checked
if (!item.checked) {
this.allChecked = false
} else {
// 判断每一个商品是否是被选择的状态
const goods = this.list.every(item => {
return item.checked === true
})
if (goods) {
this.allChecked = true
} else {
this.allChecked = false
}
}
},
//全选、全不选
checkAll() {
this.allChecked = !this.allChecked
if (this.allChecked) {
this.list.map(item => {item.checked = true})
} else {
this.list.map(item => {item.checked = false})
}
}
营业时间段设置
是否全天:
时间段一:
{{titleTime}}
~
{{titleTime2}}
时间段二:
{{titleTime3}}
~
{{titleTime4}}
时间段三:
{{titleTime5}}
~
{{titleTime6}}
保存
取消
对于后端返回的html结构渲染以及样式修改:
当前日期:{{datetime}}