uni-app小程序
uniapp创建
查看本地安装好的vue版本
vue -V
要求不能是5的版本,要4的版本
全局卸载
npm un -g @vue/cli
安装指定版本
npm install -g @vue/cli@4
使用uniapp来创建项目
vue create -p dcloudio/uni-preset-vue hmyg75
填写 appid
在 manifest.json
中填写appid
"mp-weixin": {
/* 微信小程序特有相关 */ "appid": "wxad258ddc70c8662c",
"setting": {
"urlCheck": false
},
"usingComponents": true
},
运行项目
npm run dev:mp-weixin
微信开发者工具导入 编译好的代码
导入这个路径
引入 uview
uview 和 uniapp配套的全端UI框架
使用步骤
-
安装依赖
npm i uview-ui@1.8.4 sass
-
在
main.js
引入以下配置import uView from "uview-ui"; Vue.use(uView);
-
在
uni.scss
引入主题样式文件@import 'uview-ui/theme.scss';
-
引入uView基础样式
App.vue
<style lang="scss"> /* 注意要写在第一行,同时给style标签加入lang="scss"属性 */ @import "uview-ui/index.scss"; </style>
-
修改
pages.json
{ "easycom": { "^u-(.*)": "uview-ui/components/u-$1/u-$1.vue" }, // 此为本身已有的内容 "pages": [ // ...... ] }
-
拷贝了uview的组件代码
<u-button>默认按钮</u-button> <u-button type="primary">主要按钮</u-button> <u-button type="success">成功按钮</u-button> <u-button type="info">信息按钮</u-button> <u-button type="warning">警告按钮</u-button> <u-button type="error">危险按钮</u-button>
-
成功提示
新建4个关键的页面
- 分布建立页面文件
2. 让页面里面有代码
- 在
pages.json
添加了 4个页面记录
- 回到 微信开发者工具中 简单验证了 4个页面创建是成功
引入tabbar
- 拷贝 图标文件到 uniapp项目中
-
找到配置文件
pages.json
设置tabbar 。 拷贝以下代码到一级层级下即可"tabBar": { "color": "#666", "selectedColor": "#eb4450", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/index/index", "iconPath": "static/icons/home.png", "selectedIconPath": "static/icons/home-o.png", "text": "首页" }, { "pagePath": "pages/category/category", "iconPath": "static/icons/category.png", "selectedIconPath": "static/icons/category-o.png", "text": "分类" }, { "pagePath": "pages/cart/cart", "iconPath": "static/icons/cart.png", "selectedIconPath": "static/icons/cart-o.png", "text": "购物车" }, { "pagePath": "pages/my/my", "iconPath": "static/icons/my.png", "selectedIconPath": "static/icons/my-o.png", "text": "我的" } ] }
设置了页面导航栏样式
pages.json
"globalStyle": {
"navigationBarTextStyle": "white",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#eb4450",
"backgroundColor": "#F8F8F8"
},
封装 搜索框组件
借助了uview 搜索框组件 来实现封装
- 使用 easycom 模式来创建组件
-
组件代码
<template> <view class="yg-search"> <u-search placeholder="搜索" shape="square" :show-action="false" input-align="center" bg-color="#fff" ></u-search> </view> </template> <script> export default {}; </script> <style lang="scss"> .yg-search { background-color: #ea4350; padding: 15rpx; } </style>
-
回到首页中 直接使用
<!-- 1 搜索框 --> <YgSearch></YgSearch>
轮播图
-
自己发送请求获取数据
// 获取轮播图 async getSwiperData() { // uni api const [err, data] = await uni.request({ url: "https://api-hmugo-web.itheima.net/api/public/v1/home/swiperdata", }); this.swiperList = data.data.message; },
-
然后将数据结合组件 u-swiper 实现功能
<!-- 2 轮播图 --> <!-- name="image_src" 因为我们 swiperList 是对象数组 存放图片属性名 image_src name属性来指定即可 --> <u-swiper :list="swiperList" name="image_src" height="340" ></u-swiper>
封装网络请求代码
uview 提供 直接使用即可
实现功能
- 后期方便我们统一修改 url
- 自动实现 显示加载中
步骤
-
新建 请求拦截器文件
src\common\http.interceptor.js
const install = (Vue, vm) => { // 此为自定义配置参数,具体参数见上方说明 Vue.prototype.$u.http.setConfig({ // 基地址 baseUrl: 'https://api-hmugo-web.itheima.net/api/public/v1', // 发送请求过程中 提示文字 loadingText: '努力加载中~', // 发送请求的时候 过了800毫秒 才显示加载中 loadingTime: 800, }); }; export default { install, };
-
在
main.js
引入这个文件
const app = new Vue({
...App,
});
// http拦截器,此为需要加入的内容,如果不是写在common目录,请自行修改引入路径
import httpInterceptor from '@/common/http.interceptor.js';
// 这里需要写在最后,是为了等Vue创建对象完成,引入"app"对象(也即页面的"this"实例)
Vue.use(httpInterceptor, app);
app.$mount();
-
在页面中 发送请求的代码 切成 uview的写法
async getSwiperData() { // uni api =>uview 写法 const result = await this.$u.get("/home/swiperdata"); // console.log(result); this.swiperList = result.message; },
商品分类页面布局
<template>
<view>
<!-- 1 搜索框 -->
<YgSearch></YgSearch>
<!-- 2 内容 -->
<view class="main">
<view class="menu"></view>
<view class="content"></view>
</view>
</view>
</template>
<script>
export default {};
</script>
<style lang="scss">
.main {
height: calc(100vh - 94rpx);
display: flex;
.menu {
width: 182rpx;
overflow: auto;
}
.content {
flex: 1;
overflow: auto;
}
}
</style>
小程序的性能优化建议
在uniapp中,如果标签中没有出现的变量,就不要定义的data中,使用的话 一样可以正常 this.abc来使用
小程序页面跳转和传参
使用 navigator 进行跳转和传参
:url="'/pages/goods_list/goods_list?cid='+item2.cat_id"
在新页面中 onLoad 生命周期 接收 数据
onLoad(option) {
// 为了方便调试 cid = 5
const cid = option.cid || 5;
console.log(cid);
},
小程序中滚动条触底事件
onReachBottom(){}
商品列表页面下拉刷新业务
-
pages.json
开启 允许下拉刷新"path": "pages/goods_list/goods_list", "style": { "navigationBarTitleText": "商品列表", "enablePullDownRefresh": true }
-
在页面中 监听 页面下拉刷新事件
onPullDownRefresh(){}
-
执行业务
async onPullDownRefresh() {
this.params.pagenum = 1;
this.goods = [];
await this.getGoods(); // 异步 开始发送请求 获取数据 数据还没有回来
uni.stopPullDownRefresh(); // 关闭下拉刷新
},
商品详情页面业务分析
-
通过接口获取到商品详情数据
-
动态页面渲染
-
轮播图
<u-swiper
:list="goodsDetail.pics"
name="pics_big"
height="497"
img-mode="aspectFit"
bg-color="#fff"
></u-swiper>
-
点击轮播图 放大预览
wx.previewImage
// 点击轮播图 // index 点击 第几张图片 下标 handlePreviewImage(index) { // console.log(index); // console.log(this.goodsDetail.pics); const urls = this.goodsDetail.pics.map((item) => item.pics_big); uni.previewImage({ // 数组构造即可 // 需要轮播图图书数组 urls, // 你要先显示谁 current: urls[index], }); },
-
商品名称价格
6. 图文详情渲染 - 富文本
- 数据 来自于接口文档
-
用什么标签来渲染
-
rich-text
小程序 富文本标签 简单内容 用它<rich-text :nodes="goodsDetail.goods_introduce"></rich-text>
-
v-html
vue中技术<view v-html="goodsDetail.goods_introduce"></view>
-
uview
中Parse
组件 文章内容 图文详情 复杂结构<u-parse :html="goodsDetail.goods_introduce"></u-parse>
-
-
渲染购物车工具栏 - uview 模版
-
注册一个uniapp账号
-
然后打开在 uview 模版中寻找模版
3. 然后打开链接
- 下载使用
-
然后按需拷贝要的代码结构到自己的项目中
在uniapp中引入vuex
看 uniapp中文档来操作
-
购物车数据需要在多个页面中使用 (
商品详情页面
、购物车页面
、支付页面
) -
安装依赖, uniapp 已经提前帮我们安装好
-
新建
src/store/index.js
// 页面路径:store/index.js import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); //vue的插件机制 //Vuex.Store 构造器选项 const store = new Vuex.Store({ state: { //存放状态 username: 'foo', age: 18, }, }); export default store;
-
在
main.js
来全局引入import store from './store'; Vue.prototype.$store = store; const app = new Vue({ store, ...App, });
-
在组件中 通过 计算属性来使用
computed: { username() { return this.$store.state.username; }, },
<view class="buy btn u-line-1">立即购买 {{username}} </view>
-
成功
在vuex中划分购物车模块
-
在
store/modules/cart.js
export default { state: { // 数组 goodsList: [], }, getters: {}, mutations: {}, actions: {}, };
-
在
store/index.js
引入 购物车模块// 引入 购物车模块 import cart from '@/store/modules/cart'; const store = new Vuex.Store({ state: {}, // 子模块 modules: { cart, }, });
-
在组件中使用
this.$store.state.cart.goodsList
添加商品到购物车
-
引入
vuex
辅助函数mapMutations
import { mapMutations } from "vuex";
-
在组件中
methods
使用了辅助函数 快速获取到mutation中的函数
...mapMutations("cart", ["cartAddGoods"]),
-
在组件中 绑定点击事件
<view class="cart btn u-line-1" @click="handleAddCart" >加入购物车</view>
-
事件中开始调用
mutations
// 加入购物车 handleAddCart() { // console.log(this.goodsDetail); // 需要自己添加两个属性 选中状态 和 购买的数量 this.cartAddGoods({ ...this.goodsDetail, checked: true, nums: 1 }); },
-
回到 cart模块 中 mutation 来处理业务
记得添加
namespaced
属性mutations: { // 添加数据到购物车数组 cartAddGoods(state, payload) { // 业务后续修改 state.goodsList.push(payload); console.log(state.goodsList); },
把购物车总数量映射到组件上
-
修改了 mutations中 添加商品到购物车逻辑
const index = state.goodsList.findIndex( (goods) => goods.goods_id === payload.goods_id ); if (index !== -1) { // 已经存在 index state.goodsList[index].nums++; } else { // 不存在 state.goodsList.push(payload); }
-
把购买的商品总的数量 在 vuex 中cart中计算出来
getters
getters: { // 总商品的购买数量 goodsTotalNums(state) { // 数组方法 reduce return state.goodsList.reduce((s, i) => (s += i.nums), 0); }, },
补充数组方法 reduce 叠加器 数量的叠加 字符串叠加
数量叠加
const list = [1, 2, 3, 4, 5]; // const sum = list.reduce(回调函数,初始值); // const sum = list.reduce((总和,当前遍历元素)=>{ // 总和+=当前遍历元素 // 返回 总和 // },0); // const sum = list.reduce((s, i) => { // console.log('总和 s', s, '当前循环项 i', i); // s += i; // return s; // }, 0); const sum = list.reduce((s, i) => (s += i), 0); console.log(sum);
字符串叠加
const list = ['a', 'b', 'c', 'd']; const html = list.reduce((h, i) => (h += `<li>${i}</li>`), ''); console.log(html);
-
在组件中使用了
getters
import { mapMutations, mapGetters } from "vuex"; computed: { ...mapGetters("cart", ["goodsTotalNums"]), }, <view class="item car"> <u-badge :count="goodsTotalNums" ></u-badge>
购物车页面静态结构
<template>
<view class="cart">
<!-- 1 列表 -->
<view class="cart-list">
<view class="cart-item">
<!-- 1 复选框 -->
<view class="goods-chk">
<u-checkbox
value=""
shape="circle"
active-color="red"
></u-checkbox>
</view>
<!-- 2 图片 -->
<view class="goods-img">
<u-image
width="191rpx"
height="191rpx"
></u-image>
</view>
<!-- 3 信息 -->
<view class="goods-info">
<!-- 名称 -->
<view class="goods-name u-line-2"></view>
<!-- 价格和数量 -->
<view class="goods-price-num">
<view class="goods-price">¥xxx</view>
<view class="goods-num-tool">
<view class="num-btn">-</view>
<view class="goods-num">xxx</view>
<view class="num-btn">+</view>
</view>
</view>
</view>
</view>
</view>
<!-- 2 统计 -->
<view class="statistics">
<view class="all-chk">
<u-checkbox
shape="circle"
active-color="red"
>全选</u-checkbox>
</view>
<view class="all-price"> 合计: <text>¥xxx</text> </view>
<view class="all-count">
<u-button
type="error"
shape="circle"
>去结算(xxx)</u-button>
</view>
</view>
</view>
</template>
<script>
export default {};
</script>
<style lang="scss">
.cart {
padding-bottom: 111rpx;
.cart-list {
.cart-item {
display: flex;
padding: 10rpx;
border-bottom: 1rpx solid #ccc;
.goods-chk {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
}
.goods-img {
flex: 2;
display: flex;
align-items: center;
justify-content: center;
}
.goods-info {
color: #666;
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
.goods-name {
}
.goods-price-num {
display: flex;
justify-content: space-between;
.goods-price {
color: #eb4450;
}
.goods-num-tool {
width: 140rpx;
height: 40rpx;
display: flex;
justify-content: space-between;
.num-btn {
border: 1rpx solid #ccc;
border-radius: 50%;
width: 40rpx;
height: 40rpx;
text-align: center;
line-height: 40rpx;
}
}
}
}
}
}
.statistics {
position: fixed;
background-color: #fff;
bottom: 0;
left: 0;
width: 100%;
z-index: 100;
border-top: 1rpx solid #ccc;
display: flex;
align-items: center;
padding: 15rpx;
.all-chk {
}
.all-price {
flex: 1;
color: #666;
text {
}
}
.all-count {
}
}
}
</style>
支付页面静态结构
<template>
<view class="pay">
<!-- 1 收货地址 -->
<view class="address u-p-20">
<view class="address-btn u-flex u-row-center">
<u-button
shape="circle"
type="error"
plain
size="medium"
:custom-style="{ backgroundColor: '#fff!important' }"
>获取收货地址</u-button>
</view>
<view class="address-detail">
<view class="address-detail">xxx</view>
<view class="address-user">xxx</view>
</view>
</view>
<u-line color="#eee"></u-line>
<!-- 2 已选商品 -->
<view class="goods-list u-p-15">
<view class="goods-list-title">已选商品</view>
<view class="goods-list-content">
<view class="cart-item">
<!-- 2 图片 -->
<view class="goods-img">
<u-image
width="191rpx"
height="191rpx"
></u-image>
</view>
<!-- 3 信息 -->
<view class="goods-info">
<!-- 名称 -->
<view class="goods-name u-line-2">xxx</view>
<!-- 价格和数量 -->
<view class="goods-price-num">
<view class="goods-price">¥xxx</view>
<view class="goods-num-tool">
<view class="goods-vnum">Xxxx</view>
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 2 统计 -->
<view class="statistics">
<view class="all-price"> 合计: <text>¥xxx</text> </view>
<view class="all-count">
<u-button
type="error"
shape="circle"
>去支付(xxx)</u-button>
</view>
</view>
</view>
</template>
<script>
export default {};
</script>
<style lang="scss">
.pay {
padding-bottom: 111rpx;
}
.cart-item {
display: flex;
padding: 10rpx;
border-bottom: 1rpx solid #ccc;
.goods-img {
flex: 2;
display: flex;
align-items: center;
justify-content: center;
}
.goods-info {
color: #666;
flex: 3;
display: flex;
flex-direction: column;
justify-content: space-around;
.goods-name {
}
.goods-price-num {
display: flex;
justify-content: space-between;
.goods-price {
color: #eb4450;
}
.goods-num-tool {
width: 140rpx;
height: 40rpx;
display: flex;
justify-content: flex-end;
.goods-vnum {
}
}
}
}
}
.statistics {
position: fixed;
background-color: #fff;
bottom: 0;
left: 0;
width: 100%;
z-index: 100;
border-top: 1rpx solid #ccc;
display: flex;
align-items: center;
padding: 15rpx;
.all-price {
flex: 1;
color: #666;
text {
}
}
.all-count {
}
}
</style>