前置知识
1、配置插件
微信小程序 基础模板引入sass的两种方法_微信小程序使用sass-CSDN博客
之后在对应页面里新建一个scss文件,写css
2、注册小程序,有个自己的appid,不用测试号了
5.1.注册小程序账号获取appid及个人和企业版差异_哔哩哔哩_bilibili
4. Promise用法
异步相关,看完了有点蒙,不看也可以往下进行,但是会不知道原理
ES6 Promise的用法,async/await异步处理同步化 - 哔哩哔哩
5. 图
6. 第三方UI库使用
用的这个:Vant Weapp - 轻量、可靠的小程序 UI 组件库
安装:https://vant-contrib.gitee.io/vant-weapp/#/quickstart
5.9.第三方UI组件库vant weapp和TDesign_哔哩哔哩_bilibili
以icon为例,app.json导入组件,直接用
"usingComponents": {
"van-icon": "@vant/weapp/icon/index"
}
直接用
<van-icon name="contact-o"/>
----- 上手干项目 -----
项目所需材料:https://gitee.com/qingnian8/weixinNative
0. 先写个网络请求接口之后用
建文件 /utils/request.js
第一个网址访问超限换第二个,但是第二个是测试用的脏数据
const baseURL = 'https://tea.qingnian8.com';
// const baseURL = 'https://www.fastmock.site/mock/13998300dc7574018c16109b0ef56a56/xzs';
export function request(params){
let dataObj = params.data || {};
let headerObj = {
"content-type": "application/json"
}
return new Promise((resolve,reject)=>{
wx.request({
url: baseURL + params.url,
method:params.method || "GET",
data:dataObj,
header:headerObj,
success:res=>{
if(res.data.errCode!=0){
reject(res.data);
wx.showToast({
title: res.data.errMsg,
mask:true,
icon:"error"
})
return;
}
resolve(res.data)
},
fail:err=>{
reject(err)
}
})
})
}
1. app.*设置全局
设置全局最常用的view样式,使内填充padding不向外扩充,而是向内扩充,保证全局样式的不变
在app.wxss中设置view样式,之后在哪里用都不会改变了
view,text{
/* 可以使padding往内扩展,使原有定义宽度不变 */
box-sizing: border-box;
}
定义全局配色(其实还不够灵活,有的json文件需要用颜色,无法导入变量)
page{
--themeColor:#bda066;
--globalColor:#1a1b1c;
--focusColor:#4c4d4e;
--descColor:#7e8081;
--greyColor:#8e8e8e;
--subColor:#b1b2b3;
--lightColor:#e4e4e4;
--globalBgColor1:#e3e4e5;
--globalBgColor2:#f6f7f8;
--globalBgColor3:#ffffff;
}
json定义全局上面的栏
"window": {
// 背景色(json不能写注释,小学生都知道)
"navigationBarBackgroundColor": "#333333",
// 文字颜色
"navigationBarTextStyle": "white",
// 默认文本
"navigationBarTitleText": "yuange6666"
},
json中的log页面没有用到,删掉
底部导航栏
app.json
"tabBar": {
// 默认颜色(这里就用不了全局颜色配置了,所以全局配置不是哪里都能用)
"color": "#4c4d4e",
// 选中颜色
"selectedColor": "#bda066",
"list": [
{
"text": "首页",
"pagePath": "pages/one/one",
"iconPath": "static/images/home.png",
"selectedIconPath": "static/images/home-fill.png"
},{
"text": "分类",
"pagePath": "pages/classify/classify",
"iconPath": "/static/images/all.png",
"selectedIconPath": "/static/images/all-fill.png"
},{
"text": "新闻",
"pagePath": "pages/news/news",
"iconPath": "/static/images/news.png",
"selectedIconPath": "/static/images/news-fill.png"
}
]},
2. 顶部全局组件
新建全局部件/components/xzs/xzs.*
在json中引入全局组件,因为是全局,所以到app.json中引入
"usingComponents": {
"xzs":"/components/xzs/xzs-header"
}
wxml
scss
.header {
height: 120rpx;
border: 1px solid var(--themeColor);
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx 0 30rpx;
.logo{
height: 90rpx;
.pic{
height: 100%;
}
}
// 这么直接写一个pic也没有毛病,但是啥叫好的编程习惯啊~
// .pic{
// height: 90rpx;
// }
}
display: flex;是CSS的一个属性,用于将容器设置为弹性盒子(flexbox)布局。这种布局模型非常适合于创建响应式布局和复杂的布局结构。
当一个元素应用了display: flex;属性后:
该元素会变成一个弹性容器(flex container)。
其直接子元素会变成弹性项目(flex items)。
弹性容器有多个属性可以用来调整其子项目如何排列、对齐和分布空间,例如:
flex-direction: 决定子项目的主轴方向。
flex-wrap: 决定子项目是否应该换行。
align-items, align-self: 用于决定子项目在交叉轴上的对齐方式。
justify-content: 用于决定子项目在主轴上的对齐方式。
在别的页面使用时,直接引入
<xzs></xzs>
3. 首页one.*
3.1 滑块
<!-- 写成循环 -->
<view class="banner">
<!-- 显示圆点、自动播放、间隔3000ms、循环、左边缩进 -->
<swiper class="swiper" indicator-dots="true" autoplay="true" interval="3000" circular="true" previous-margin="30rpx">
<!-- 4条数据 -->
<swiper-item class="switem" wx:for="{{4}}">
<image class="pic" src="/static/images/banner{{index}}.jpg" mode="aspectFill" />
</swiper-item>
</swiper>
</view>
3.2 滚动栏
<view class=" scrollNav">
<!-- 横向滑动启动 -->
<scroll-view scroll-x="true">
// 这里的idx参数是用于第6章从首页到分类页跳转用
<navigator class="item" wx:for="{{chaArr}}" wx:key="_id" url="/pages/classify/classify?idx={{index}}" open-type="reLaunch">
<image class="pic" src="{{item.icon}}" mode="" />
<text class="txt">
{{item.classname}}
</text>
</navigator>
</scroll-view>
</view>
.scrollNav{
padding: 30rpx 30rpx 30rpx 30rpx;
}
.scrollNav scroll-view{
/* 父级元素不换行 */
white-space: nowrap;
}
.scrollNav scroll-view .item{
// 转成行级块元素
display: inline-block;
padding: 0 25rpx;
text-align: center;
}
// 第一个和最后一个不要边距
.scrollNav scroll-view .item:first-child{
padding-left: 0;
}
.scrollNav scroll-view .item:last-child{
padding-right: 0;
}
.scrollNav scroll-view .item .pic{
width: 100rpx;
height: 100rpx;
}
.scrollNav scroll-view .item .txt{
font-size: 32rpx;
color: var(--globalColor);
padding-top: 30rpx;
}
js获取导航栏项目,获取的内容item如下
import {formatDate,formatNum} from "../../utils/common.js"
import {listNav,listNews} from "../../api/apis"
data: {
chaArr: [],
newsArr: []
},
onLoad(options) {
this.getNavData()
this.getNewsData()
},
getNavData() {
// 下面封装的就是这个的Promise相关实现,注释部分也能用
// wx.request({
// url: 'https://tea.qingnian8.com/nav/get',
// method:"POST",
// header:{"Content-Type":"application/json"},
// success:res=>{
// console.log(res);
// this.setData({
// chaArr:res.data.data
// })
// }
// })
listNav().then(res => {
// console.log(res)
this.setData({
chaArr: res.data
})
})
},
其中listNav() 函数在/api/apis.js中写一个
import {
request
} from "../utils/request"
export function listNav() {
return request({
url: "/nav/get",
method: "POST"
})
}
3.3 简介栏
<view class="about">
<view class="pubTitle">
<view class="en">introduce</view>
<view class="zh">茶美文化简介</view>
<!-- /* 这个线实际是一个view长方形 */ -->
<view class="line"></view>
</view>
<view class="content">
<view class="row">白茶,素为茶中珍品,历史悠久,属中国六大茶类之一,具有极高的收藏价值。巷子深茶美文化馆,位于泉城济南,是一家致力于弘扬茶美文化,集白茶销售、品牌、体验、品鉴于一体的综合性企业。</view>
<view class="row">巷子深茶美文化馆,传承卓越,与美共勉,以中式传统风格为基础,结合现代时尚格调,将观赏性与实用性、商务与休闲、体验与收藏高度融合,为顾客提供全新的体验式服务。茶舍环境优雅,可以茶会友、修身养性、品鉴收藏,感受白茶独特的文化魅力。</view>
<view class="row">从白茶的栽培管理到茶窖存储,每一款产品都诠释着我们追求完美的品质之心,我们拥有最佳的仓储环境,全系列白茶产品,优质的客户服务,致力于打造创新发展、诚信经营的新标杆。</view>
</view>
</view>
就是一个大背景灰色,英文、中文、横线,内容,标题后面会复用,所以把css写在了全局app.wxss中
.pubTitle{
text-align: center;
}
当您在一个元素上设置 text-align: center; 时,该元素中的所有文本内容(包括子元素)都会被居中对齐。
这意味着,即使您没有明确指定 .line 的位置,它也会被居中对齐,因为它是一个文本内容的一部分。
.pubTitle .en{
font-size: 86rpx;
font-weight: 900;
/* 在这里转大写,妙啊 */
text-transform: uppercase;
color:var(--globalColor);
opacity: 0.1;
}
.pubTitle .zh{
font-size: 56rpx;
font-weight: 900;
/* Y轴方向上向上回退,堆叠英文 */
transform: translateY(-60rpx);
color: var(--globalColor);
}
/* 这个线实际是一个view长方形 */
.pubTitle .line{
width: 100rpx;
height: 5rpx;
background-color: var(--globalColor);
opacity: 0.8;
display: inline-block;
transform: translateY(-40rpx);
}
3.4 资讯栏
大标题可以CV之前的,每个条目需要写个公共组件
3.4.1 新闻条目公共组件
<!-- 整个条目都是一个导航,这个id是传递具体信息,在5章中讲 -->
<navigator url="/pages/new2/new2?id={{item._id}}" class="news">
<!-- 左边的图片 -->
<view class="pic">
<image class="img" src="{{item.picurl}}" mode="aspectFill" />
</view>
<!-- 右边的文字块 -->
<view class="txt">
<!-- 上面的标题 -->
<view class="up">{{item.title}}</view>
<!-- 下面的三个小项 -->
<view class="down">
<!-- 1日期 -->
<view class="block">
<van-icon name="calendar-o" />
<text>{{item.publish_date}}</text>
</view>
<!-- 2浏览量 -->
<view class="block">
<van-icon name="eye-o" />
<text>{{item.view_count}}</text>
</view>
<!-- 3作者 -->
<view class="block">
<van-icon name="contact-o"/>
<text>{{item.author}}</text>
</view>
</view>
</view>
</navigator>
.news{
/* 弹性盒模型左右布局,当您将一个元素的 display 属性设置为 flex 时,该元素会变成一个弹性容器,其子元素会变成弹性项目。
这允许您使用各种 Flexbox 属性来控制这些项目在容器中的布局和对齐。
justify-content: space-between; 是这些属性之一。它决定了弹性项目在主轴(默认为水平方向)上的对齐方式。
space-between 值意味着项目会均匀地分布在容器中,第一个项目位于容器的起点,最后一个项目位于容器的终点,而其他项目则位于起点和终点之间的位置。 */
display: flex;
justify-content: space-between;
padding-bottom: 30rpx;
}
.news .pic{
width: 220rpx;
height: 150rpx;
}
.news .pic .img{
width: 100%;
height: 100%;
}
.news .txt{
width: 440rpx;
height: 150rpx;
/* 两端对齐,justify 值会使文本两端对齐,使得左右两边的空白间距相等。 */
text-align: justify;
display: flex;
flex-direction: column;
// 上下两端均匀分布
justify-content: space-between;
}
.news .txt .up{
line-height: 1.5em;
color: var(--globalColor);
font-size: 32rpx;
// 结尾超出用省略号,网上现用现CV
text-overflow: -o-ellipsis-lastline;
overflow: hidden; /*溢出内容隐藏*/
text-overflow: ellipsis;/*省略号表示*/
display: -webkit-box;/*特别显示模式*/
-webkit-line-clamp: 2;/*行数*/
line-clamp: 2;
-webkit-box-orient: vertical;
}
.news .txt .down{
display: flex;
justify-content: space-between;
color: var(--descColor);
}
传参
/**
* 组件的属性列表
*/
properties: {
item:{
type:Object,
value:{
title:"默认标题",
author:"yuan"
}
}
},
把公共组件引入全局app.json就能用了
"usingComponents": {
"xzs-news":"/components/xzs-news/xzs-news"
}
3.4.2 正页内容
这里传个item循环项就可以了,内容都在公共组件内写好,就是不好维护,万一接口变量都变了
<view class="news">
<view class="pubTitle">
<view class="en">news</view>
<view class="zh">资讯</view>
<view class="line"></view>
</view>
<view class="content">
<view class="row" wx:for="{{newsArr}}">
<xzs-news item="{{item}}"></xzs-news>
</view>
</view>
</view>
获取循环列表,在js内写函数
getNewsData() {
listNews({
"limit": 3,
"size":0
// "hot": true
}).then(res => {
// console.log(res);
// 在函数中拿到数据直接格式化掉再传给前端
res.data.forEach(item => {
item.view_count = formatNum(item.view_count)
})
res.data.forEach(item => {
item.publish_date = formatDate(item.publish_date)
})
this.setData({
newsArr: res.data
})
})
// wx.request({
// url: 'https://tea.qingnian8.com/news/get',
// method: "POST",
// header: {
// "Content-Type": "application/json"
// },
// data: {
// "limit": 3,
// "size": 0
// // "hot":true
// },
// success: res => {
// console.log(res);
// res.data.data.forEach(item => {
// item.view_count = formatNum(item.view_count)
// })
// res.data.data.forEach(item => {
// item.publish_date = formatDate(item.publish_date)
// })
// this.setData({
// newsArr: res.data.data
// })
// }
// })
},
listNews()写在apis.js中,需要传递参数形参data
import {
request
} from "../utils/request"
export function listNews(data) {
return request({
url: "/news/get",
method: "POST",
data
})
}
3.5 页面尾版权信息、客服标志
每个页面都要用,写个公共组件
3.5.1 版权
这个简单,就是三行居中的字,小学生都会
<view class="footer">
<view class="row">解释权归远哥无限公司所有</view>
<view class="row">Copyright © {{year}} 版权所有</view>
<view class="row">上海市宝山区上大路99号上海大学</view>
</view>
.footer{
padding: 50rpx 0rpx;
text-align: center;
background: var(--globalBgColor2);
border-top: 1px solid var(--themeColor);
color: var(--focusColor);
font-size: 30rpx;
line-height: 1.5em;
}
3.5.2 客服标志
结构:最上面一个按钮,透明的->下面一个客服图片->一个圆圈线做动画
<view class="kefu">
<button class="btn" open-type="contact">btn</button>
<image src="/static/images/kefu.png" mode="aspectFill" class="pic"/>
<view class="line"></view>
</view>
.kefu{
width: 100rpx;
height: 100rpx;
background: var(--themeColor);
// 卡位
position: fixed;
bottom: 100rpx;
right: 60rpx;
// 圆的
border-radius: 50%;
box-shadow: 0 0 20rpx rgba(189,160,102,0.8);
z-index: 0;
.btn{
// position: relative;
z-index: 2;
opacity: 0.5; // 把这里改成按钮0透明
border-radius: 10%; // 改完透明边框也就没用了
border: 1px solid black;
width: 100%;
height: 100%;
}
.pic{
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
z-index: 1;
width: 90%;
height: 90%;
margin: 5%;
}
// 用于动画的线
.line{
width: 100%;
height: 100%;
border: 3px solid var(--themeColor);
position: absolute;
top: 0;
left: 0;
border-radius: 50%;
// 动画name 类型 时间 循环
animation: emit111 1.5s infinite;
}
}
// 动画定义,
@keyframes emit111{
0%{}
100%{
border-width: 0px;
opacity: 0;
transform: scale(1.8);
}
}
把公共组件引入全局app.json就能用了
"usingComponents": {
"xzs-footer":"/components/xzs-footer/xzs-footer"
}
4. 新闻列表页news.*
/**
* 页面的初始数据
*/
data: {
newsArr: [],
loading: true
},
<view class="news">
<!-- 大标题 -->
<view class="pubTitle">
</view>
<!-- 内容列表 -->
<view class="content">
</view>
<!-- 最后的显示 -->
<view class="loadOut">
</view>
</view>
.news{
padding: 30rpx 30rpx;
.loadOut{
text-align: center;
padding: 30rpx 0;
.nodata{
font-size: 30rpx;
color: var(--descColor);
}
}
}
4.1 大标题
抄着3.3、3.4干什么,愣啊
<!-- 大标题 -->
<view class="pubTitle">
<view class="en">news</view>
<view class="zh">资讯</view>
<view class="line"></view>
</view>
4.2 内容列表
<!-- 内容列表 -->
<view class="content">
<view class="row" wx:for="{{newsArr}}">
<xzs-news item="{{item}}"></xzs-news>
</view>
</view>
4.2.1 获取列表逻辑
加载的时候要获取一次
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
this.getNewsData();
},
下拉触底要获取一次,并且要显示加载中
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
// 要是判断不需要加载了,就别再执行函数了,退出吧
if(this.data.loading==false) return;
// 模拟一下0.5s加载,不然太快了
setTimeout(() => {
let arr = this.data.newsArr
this.getNewsData()
}, 500);
},
下拉刷新整个页面
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
this.setData({
// 要把新闻列表清空
newsArr:[]
})
this.getNewsData()
},
所以获取函数这么写,其中的格式化函数写在api中导入就行了,时间戳格式化,数字处理,有手就能写
getNewsData() {
// 先有loading后有天!
this.setData({
loading: true
})
// 获取列表
listNews({
"limit": 5,
// 这个参数是隔断几个之后开始取,数组列表已经有的就隔断,往后继续取
"size": this.data.newsArr.length
}).then(res => {
// 阻止那个下拉刷新的函数
wx.stopPullDownRefresh()
// 得到数据直接格式化掉,再传给前端
res.data.forEach(item => {
item.view_count = formatNum(item.view_count)
})
res.data.forEach(item => {
item.publish_date = formatDate(item.publish_date)
})
// 页面显示的事整个数组,所以从空数组开始不断追加就行了
this.setData({
newsArr: this.data.newsArr.concat(res.data),
})
// console.log(res);
// console.log(this.data.newsArr.length);
// 如果数组长度==后端返回的总数计数,那就可以不用加载了
if (this.data.newsArr.length == res.total) {
// console.log("no more");
this.setData({
loading: false
})
}
})
},
// 在/api/apis.js中
export function listNews(data) {
return request({
url: "/news/get",
method: "POST",
data
})
}
4.3 最后的显示
<!-- 最后的显示 -->
<view class="loadOut">
<!-- 加个判断 如果是loading为true显示加载的三方图标 -->
<van-loading size="24px" color="#3badff" wx:if="{{loading}}">加载中...</van-loading>
<!-- 否则就显示没有更多 -->
<view class="nodata" wx:if="{{!loading}}">No more...</view>
</view>
5. 新闻详情页new2.*
结构:
<view class="detail" wx:else="">
// 标题
<view class="title">
</view>
// 文章信息
<view class="info">
// 左边日期作者阅读量
<view class="left">
</view>
// 右边分享图标
<view class="right">
</view>
</view>
// 内容
<view class="content">
</view>
// 底部版权
<view class="copyright">
</view>
</view>
.detail{
padding:30rpx;
.title{
font-size: 50rpx;
line-height: 1.5em;
}
.info{
font-size: 28rpx;
color:#999;
display: flex;
justify-content: space-between;
padding:30rpx 0 50rpx;
.left{
text{
padding-right: 15rpx;
}
}
.right{
display: flex;
align-items: center;
color:var(--themeColor);
position: relative;
.share{
position: absolute;
top:0;
left:0;
opacity: 0;
}
text{
padding-left:5rpx;
}
}
}
.content{
.pstyle{
padding:10rpx 0;
line-height: 1.6em;
text-indent: 2em;
font-size: 36rpx;
}
.pstyle .imgstyle{
margin-left: -2em;
}
.imgstyle{
border-radius: 15rpx;
}
}
.copyright{
margin-top:30rpx;
background:var(--globalBgColor2);
padding:30rpx;
font-size: 26rpx;
color:#888;
.top{
font-size: 30rpx;
padding-bottom:15rpx;
}
}
}
5.1 怎么得到不同页面信息
在点击新闻项时,每个组件本身都是一个导航框,这个id就用于传递信息
<navigator url="/pages/new2/new2?id={{item._id}}" class="news">
在新闻详情页加载的时候,有一个参数options是携带传入来的信息的
onLoad: function (options) {
console.log(options);
id = options.id
this.getDetail()
},
所以就可以得到具体的id,写获取详情函数
5.2 标题、信息
<view class="title">
{{detail.title}}
</view>
<view class="info">
<view class="left">
<text>{{detail.publish_date}}</text>
<text>{{detail.author}}</text>
<text>{{detail.view_count}}阅读</text>
</view>
<view class="right">
<van-icon name="share-o" size="20" />
<text>分享</text>
<button open-type="share" class="share" size="mini">
享
</button>
</view>
</view>
getDetail() {
newsDetail({
"id": id
}).then(res => {
console.log(res);
// 以下是正则处理页面标签,用来做css
res.data.publish_date = formatTime(res.data.publish_date, 1)
res.data.view_count = formatNum(res.data.view_count)
res.data.content = res.data.content.replace(/<p/gi, "<p class='pstyle'")
res.data.content = res.data.content.replace(/<img/gi, "<img class='imgstyle'")
res.data.content = res.data.content.replace(/<br\/>/gi, "")
this.setData({
detail:res.data
})
})
},
res长这样
5.3 富文本内容、尾部
页面详情信息都有了,写就行了
<view class="content">
<rich-text nodes="{{detail.content}}"></rich-text>
</view>
<view class="copyright">
<view class="top">免责声明</view>
<view>本文来自网络新闻创作者,不代表巷子深小程序端的观点和立场,如有侵权请联系客服进行删除。</view>
</view>
6. 商品分类页classify.*
6.1 顶图
没写成循环
<view class="banner">
<image class="pic" src="/static/images/teaBanner.jpg" mode="aspectFill" />
</view>
6.2 三方导航条
<view class="nav">
<!-- active打开第几个页面、点击事件、流畅动画、手势滑动、标签主题颜色、外边框、选中颜色 -->
<van-tabs active="{{navActive}}" bind:click="onClick" animated swipeable color="#bda066" border title-active-color="#bda066">
<van-tab title="{{item.classname}}" wx:for="{{navArr}}" wx:key="_id"></van-tab>
</van-tabs>
</view>
async getNavList() {
await listNav().then(res => {
this.setData({
navArr: res.data
})
})
},
--- apis.js中
export function listNav() {
return request({
url: "/nav/get",
method: "POST"
})
}
6.3 获取产品项
/**
* 页面的初始数据
*/
data: {
navActive: 4,
navArr: [],
proArr: [],
loading: true
},
6.3.1 产品项公用组件
// 这里埋点点击事件,第七章用
<view class="product" bind:tap="clickProduct" data-id="{{info._id}}">
<!-- 图 -->
<view class="pic">
<image class="image" mode="widthFix" src="{{info.picpath}}"></image>
</view>
<!-- 文字 -->
<view class="text">
<!-- 标题 -->
<view class="title">{{info.title}}</view>
<!-- 详细信息 -->
<view class="info">
<!-- 1 -->
<view class="row">
<view class="left"><text space="emsp">货 号:</text></view>
<view class="right">{{info.pronum}}</view>
</view>
<!-- 2 -->
<view class="row">
<view class="left"><text space="emsp">等 级:</text></view>
<view class="right">{{info.grade}}</view>
</view>
<!-- 3 -->
<view class="row">
<view class="left"><text space="emsp">年 份:</text></view>
<view class="right">{{info.year}}</view>
</view>
<!-- 4 -->
<view class="row">
<view class="left">净含量:</view>
<view class="right">{{info.weight}}</view>
</view>
<!-- 5 -->
<view class="row">
<view class="left">零售价:</view>
<view class="right">{{info.price}}</view>
</view>
</view>
</view>
</view>
.product .pic .image {
width: 100%;
}
.product .text {
padding: 15rpx 20rpx;
}
.product .title {
font-size: 36rpx;
color: #333;
border-bottom: 1rpx solid #efefef;
padding-bottom: 20rpx;
margin-bottom: 10rpx;
white-space: nowrap;
text-overflow: ellipsis;
width: 100%;
overflow: hidden;
}
.product .row {
font-size: 28rpx;
color: #aaa;
display: flex;
line-height: 2em;
}
.product .row .left {
font-size: 26rpx;
white-space: nowrap;
}
.product .row .right {
color: #666;
white-space: nowrap;
}
6.3.2 页面
<view class="content">
<!-- 产品块 -->
<view class="body">
<view class="box" wx:for="{{proArr}}">
<xzs-product info="{{item}}"></xzs-product>
</view>
</view>
<!-- 结尾加载 -->
<view class="loadOut">
<van-loading size="24px" color="#3badff" wx:if="{{loading}}">加载中...</van-loading>
<view class="nodata" wx:if="{{!loading}}">No more...</view>
</view>
</view>
<xzs-footer></xzs-footer>
/**
* 生命周期函数--监听页面加载
*/
async onLoad(options) {
let {idx} = options;
console.log(options, idx);
// 加载完导航条再说别的
await this.getNavList();
// 如果是从首页来的,要直接定位到指定导航点
if (idx) {
this.onClick(idx)
} else {
// 如果是当前页面乱点,直接访问定位
navid = this.data.navArr[this.data.navActive]._id
this.getProductList()
}
},
async getNavList() {
await listNav().then(res => {
console.log("导航");
console.log(res);
this.setData({
navArr: res.data
})
})
},
// 如果是从首页来的,要直接定位到指定导航点
onClick(e) {
console.log(e);
let index = e?.detail?.index ?? e;
console.log("index",index);
this.setData({
proArr: [],
navActive: Number(index)
})
navid = this.data.navArr[index]._id,
this.getProductList()
},
getProductList() {
listProducts({
"navid": navid, // 获取产品种类的id参数
limit: 3,
size: this.data.proArr.length
}).then(res => {
this.setData({
proArr: this.data.proArr.concat(res.data)
})
// 够了就别再加载了
if (this.data.proArr.length >= res.total) {
this.setData({
loading: false
})
}
})
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
if (this.data.loading == false) return;
setTimeout(() => {
this.getProductList()
}, 300)
},
7. 商品详情
7.1 在商品项上埋点
<view class="product" bind:tap="clickProduct" data-id="{{info._id}}">
然后在产品公共组件上js写
/**
* 组件的方法列表
*/
methods: {
clickProduct(e){
let id = e.currentTarget.dataset.id
console.log(e);
wx.navigateTo({
// 到详情页时会携带一个参数
url: '/pages/productShow/productShow?id='+id,
})
}
}
7.2 详情页
<xzs></xzs>
<!-- 骨架屏 -->
<view style="padding:50rpx 30rpx; min-height: 50vh;" wx:if="{{!detail}}">
<van-skeleton title row="20" />
</view>
<view class="detail" wx:else>
<view class="banner">
<image src="{{detail.picpath}}"></image>
</view>
<view class="textMain">
<view class="title">
{{detail.title}}
</view>
<view class="text">
<view class="row">
<view class="left"><text space="emsp">货 号:</text></view>
<view class="right">{{detail.pronum}}</view>
</view>
<view class="row">
<view class="left"><text space="emsp">等 级:</text></view>
<view class="right">{{detail.grade}}</view>
</view>
<view class="row">
<view class="left"><text space="emsp">年 份:</text></view>
<view class="right">{{detail.year}}</view>
</view>
<view class="row">
<view class="left"><text space="emsp">净含量:</text></view>
<view class="right">{{detail.weight}}</view>
</view>
<view class="row">
<view class="left"><text space="emsp">零售价:</text></view>
<view class="right">{{detail.price}}</view>
</view>
</view>
</view>
</view>
<xzs-footer></xzs-footer>
.banner {
width: 750rpx;
height: 750rpx;
}
.banner image {
width: 100%;
height: 100%;
}
.textMain {
padding: 80rpx 30rpx;
}
.textMain .title {
border-bottom: 1px solid #dedede;
padding-bottom: 50rpx;
font-size: 50rpx;
color: #333;
}
.textMain .text {
border-top: 1px solid #dedede;
margin-top: 50rpx;
padding-top: 60rpx;
}
.textMain .row {
display: flex;
padding-bottom: 30rpx;
}
.textMain .row .left {
font-size: 34rpx;
color: #888
}
.textMain .row .right {
font-size: 38rpx;
color: #666;
padding-left: 30rpx;
}
/**
* 页面的初始数据
*/
data: {
detail:null
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
console.log(options);
// 传过来的参数
let id = options.id;
this.getDetail();
},
getDetail(){
queryProductDetail({id}).then(res=>{
console.log(res);
this.setData({
detail:res.data
})
wx.setNavigationBarTitle({
title: this.data.detail.title,
})
})
},
打包上线要钱¥30,我不上!看看up主的成果