首页 >> 大全

uniapp黑马项目总结

2023-11-15 大全 33 作者:考证青年

在做完了两个vue项目之后,我开始了小程序的学习,由于开学等因素影响进度一直都是断断续续的。最终在开学一周多的时间结束了项目的练习。于是我选择了黑马商场做为微信小程序的练手。

是一个基于vue.js开发的一个前端框架,可以发布各个平台,本项目是开发一个微信小程序,使用中的内置的uni.ui模块。使用了sass,练习了对微信小程序开发的一套相对完整的流程,还有用git提交代码到gitee。

小程序中一个不同于网页的地址在于栏,微信小程序中,栏可以通过配置生成,也方便管理。只要在根目录中的pages.json配置文件,新增的配置节点即可

{"tabBar": {"selectedColor": "#C00000","list": [{"pagePath": "pages/home/home","text": "首页","iconPath": "static/tab_icons/home.png","selectedIconPath": "static/tab_icons/home-active.png"},{"pagePath": "pages/cate/cate","text": "分类","iconPath": "static/tab_icons/cate.png","selectedIconPath": "static/tab_icons/cate-active.png"},{"pagePath": "pages/cart/cart","text": "购物车","iconPath": "static/tab_icons/cart.png","selectedIconPath": "static/tab_icons/cart-active.png"},{"pagePath": "pages/my/my","text": "我的","iconPath": "static/tab_icons/my.png","selectedIconPath": "static/tab_icons/my-active.png"}]}
}

之后再修改一个导航条的模式效果,也是在pages.json中,修改节点

{"globalStyle": {"navigationBarTextStyle": "white","navigationBarTitleText": "黑马优购","navigationBarBackgroundColor": "#C00000","backgroundColor": "#FFFFFF"}
}

然后就是配置网络请求了,因为小程序中是不支持axios的,wx.()又功能简单,不能支持拦截器等,所以这个项目老师用了一个自己写的第三方包来发起网络请求的,官方文档如下:

@/- - npm

再main.js入口文件中配置,引入再绑定到uni顶级对象上,再加个请求和响应拦截器

import { $http } from '@escook/request-miniprogram'uni.$http = $http
// 配置请求根路径
$http.baseUrl = 'https://www.uinav.com'// 请求开始之前做一些事情
$http.beforeRequest = function (options) {uni.showLoading({title: '数据加载中...',})
}// 请求完成之后做一些事情
$http.afterRequest = function () {uni.hideLoading()
}

轮播图

发起请求,再动态把图片的src等属性渲染到页面上,用小程序自带的标签。

小程序分包

考虑到首次启动的加载时间,可以采用分包,而且微信小程序也对分包的大小有检测,所以我们是把相关的页面(home,cate,cart,my)放在主包,再把其它页面放在分包里(,,)。配置分包如下:

1、先在根目录中,创建分包的根目录,命名

2、再在pages.json中,与pages平级配置节点

{"pages": [{"path": "pages/home/home","style": {}},{"path": "pages/cate/cate","style": {}},{"path": "pages/cart/cart","style": {}},{"path": "pages/my/my","style": {}}],"subPackages": [{"root": "subpkg","pages": []}]
}

3、之后可在分包目录下,新建页面,并选择小程序分包,即可自动配置

封闭uni.$()方法

使用原生uni.({})来提示用户,要配置配置对象,所以封闭全局方法来简化之后的使用

// 封装的展示消息提示的方法
uni.$showMsg = function (title = '数据加载失败!', duration = 1500) {uni.showToast({title,duration,icon: 'none',})
}

分类导航区域

渲染然后再使用uni.()跳转页面



// nav-item 项被点击时候的事件处理函数
navClickHandler(item) {// 判断点击的是哪个 navif (item.name === '分类') {uni.switchTab({url: '/pages/cate/cate'})}
}

三级分类,左右侧滚动

这里有一个bug,就是每点一次左边的一级分类,再滚动右侧的二三级分类,再点一点一级分类,会发现右边的滚动条并不是在顶部,所以要动态绑定一个-y属性,然后每一次点击了一级分类,重置为0

data() {return {// 滚动条距离顶部的距离scrollTop: 0}
}


// 选中项改变的事件处理函数
activeChanged(i) {this.active = ithis.cateLevel2 = this.cateList[i].children// 让 scrollTop 的值在 0 与 1 之间切换this.scrollTop = this.scrollTop === 0 ? 1 : 0// 可以简化为如下的代码:// this.scrollTop = this.scrollTop ? 0 : 1
}

封闭my-组件

由于搜索组件要在很多页面都要进行重用,所以这里可以封闭为一个组件

1、在根目录下新建一个,再新建组件

2、直接在结构中以标签的方式直接使用自定义组件

在分类页面中,加上了自定义搜索组件后,右侧分类下面会不能滑动到底部,因为样式的原因,所以还需要在挂载的时候就要减去搜索组件的大小

onLoad() {const sysInfo = uni.getSystemInfoSync()// 可用高度 = 屏幕高度 - navigationBar高度 - tabBar高度 - 自定义的search组件高度this.wh = sysInfo.windowHeight - 50
}

为了增加组件的通用性,我们可以通过props来定义属性,以方便以后使用的时候可以通过传入参数,让组件更个性化

1、通过props来定义两个变量

props: {// 背景颜色bgcolor: {type: String,default: '#C00000'},// 圆角尺寸radius: {type: Number,// 单位是 pxdefault: 18}
}

2、再动态的绑定stype属性

搜索

搜索框自动获取焦点

这个项目的搜索框的实现是先用一个view然后再点击跳转到搜索页面实现的,所以跳转后自动获取焦点,以增强用户体验

在中的uni--bar中uni--bar.vue中,data中的show与的值改为true即可,但是这里直接改源码不好

搜索框的防抖

经典防抖,每次输入后,500毫秒内要是有新的输入事件,再不断重启延时器

input(e) {// 清除 timer 对应的延时器clearTimeout(this.timer)// 重新启动一个延时器,并把 timerId 赋值给 this.timerthis.timer = setTimeout(() => {// 如果 500 毫秒内,没有触发新的输入事件,则为搜索关键词赋值this.kw = e.valueconsole.log(this.kw)}, 500)
}

关键字数组的顺序

最近搜索的应该放在前面,可以用计算属性,再把这个数组复制一下再反转

computed: {historys() {// 注意:由于数组是引用类型,所以不要直接基于原数组调用 reverse 方法,以免修改原数组中元素的顺序// 而是应该新建一个内存无关的数组,再进行 reverse 反转return [...this.historyList].reverse()}
}

解决关键词重复问题

在保存关键词为历史记录的方法中,把这个数组转为set对象,因为set对象没有重复的元素

再移除对应元素,再添加元素,再转为数组即可

// 保存搜索关键词为历史记录
saveSearchHistory() {// this.historyList.push(this.kw)// 1. 将 Array 数组转化为 Set 对象const set = new Set(this.historyList)// 2. 调用 Set 对象的 delete 方法,移除对应的元素set.delete(this.kw)// 3. 调用 Set 对象的 add 方法,向 Set 中添加元素set.add(this.kw)// 4. 将 Set 对象转化为 Array 数组this.historyList = Array.from(set)
}

数据的持久化存储

把对象用JSON.转为json,存在本地

 uni.setStorageSync('kw', JSON.stringify(this.historyList))

把json用JSON.parse转为对象,拿到数据

onLoad() {this.historyList = JSON.parse(uni.getStorageSync('kw') || '[]')
}

再练习vuex

在根目录下store中store.js

导入vue与vuex,再安装为vue插件,创建store实例对象,向外暴露store对象,也可以使用别的模块中的数据

// 1. 导入 Vue 和 Vuex
import Vue from 'vue'
import Vuex from 'vuex'// 2. 将 Vuex 安装为 Vue 的插件
Vue.use(Vuex)// 3. 创建 Store 的实例对象
const store = new Vuex.Store({// TODO:挂载 store 模块modules: {m_cart: moduleCart,},
})// 4. 向外共享 Store 的实例对象
export default store

最后再从入口文件中把store挂载到vue实例上

// 1. 导入 store 的实例对象
import store from './store/store.js'const app = new Vue({...App,// 2. 将 store 挂载到 Vue 实例上store,
})
app.$mount()

为了模块化,我们可以再建cart.js,为了语义化,可以开启命名空间

export default {// 为当前模块开启命名空间namespaced: true,// 模块的 state 数据state: () => ({// 购物车的数组,用来存储购物车中每个商品的信息对象// 每个商品的信息对象,都包含如下 6 个属性:// { goods_id, goods_name, goods_price, goods_count, goods_small_logo, goods_state }cart: [],}),// 模块的 mutations 方法mutations: {},// 模块的 getters 属性getters: {},
}

在页面中把store映射到当前页面

// 按需导入 mapMutations 这个辅助方法
import { mapMutations } from 'vuex'export default {methods: {// 把 m_cart 模块中的 addToCart 方法映射到当前页面使用...mapMutations('m_cart', ['addToCart']),},
}

在store中使用调用中的方法

 // 通过 commit 方法,调用 m_cart 命名空间下的 saveToStorage 方法this.commit('m_cart/saveToStorage')

为设置数字徽标

先把映射一下

再把使用方法更新下标为2,即第3个的上徽标

// 按需导入 mapGetters 这个辅助方法
import { mapGetters } from 'vuex'export default {data() {return {}},computed: {// 将 m_cart 模块中的 total 映射为当前页面的计算属性...mapGetters('m_cart', ['total']),},
}

methods: {setBadge() {// 调用 uni.setTabBarBadge() 方法,为购物车设置右上角的徽标uni.setTabBarBadge({index: 2, // 索引text: this.total + '' // 注意:text 的值必须是字符串,不能是数字})}
}

然后在挂载的时候和更新数量的时候用一下就行

因为很多页面都要用,所以这里可以使用混入,在根目标下新建一个文件夹,然后把代码封装到一个单独的js文件,在四个页面中导入即可

也可再加一个监听属性,可以全局改变的值

  watch: {// 监听 total 值的变化total() {// 调用 methods 中的 setBadge 方法,重新为 tabBar 的数字徽章赋值this.setBadge()},},

// 导入自己封装的 mixin 模块
import badgeMix from '@/mixins/tabbar-badge.js'export default {// 将 badgeMix 混入到当前的页面中进行使用mixins: [badgeMix],// 省略其它代码...
}

动态更新勾选的商品数量

商品数量 = 每一项已勾选的商品所选数量相加

这里使用了方法

// 勾选的商品的总数量
checkedCount(state) {// 先使用 filter 方法,从购物车中过滤器已勾选的商品// 再使用 reduce 方法,将已勾选的商品总数量进行累加// reduce() 的返回值就是已勾选的商品的总数量return state.cart.filter(x => x.goods_state).reduce((total, item) => total += item.goods_count, 0)
}

购物车项左滑删除UI效果

      

用ui-swipe-组件,这里的item项,用:right-来设置,之前是属性

 options: [{text: '删除', // 显示的文本内容style: {backgroundColor: '#C00000' // 按钮的背景颜色}}]

实现选择收货地址



// 选择收货地址async chooseAddress() {// 1. 调用小程序提供的 chooseAddress() 方法,即可使用选择收货地址的功能//    返回值是一个数组:第 1 项为错误对象;第 2 项为成功之后的收货地址对象const [err, succ] = await uni.chooseAddress().catch(err => err)// 2. 用户成功的选择了收货地址if (err === null && succ.errMsg === 'chooseAddress:ok') {// 为 data 里面的收货地址对象赋值this.address = succ}}

之前的API点击取消后,再次点选择地址不会再弹出是否确认授权,但是现在本来也就没有弹出框了,所以就没有了这个问题

三秒自动跳转到登录页面

若在没有登录情况下结算,会提示先登录,并会自动3秒后跳转到登录页面

1、展示倒计时的信息

// 展示倒计时的提示消息
showTips(n) {// 调用 uni.showToast() 方法,展示提示消息uni.showToast({// 不展示任何图标icon: 'none',// 提示的消息title: '请登录后再结算!' + n + ' 秒后自动跳转到登录页',// 为页面添加透明遮罩,防止点击穿透mask: true,// 1.5 秒后自动消失duration: 1500})
}

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了