微信小程序开发学习(上强度):从0开始写项目

news2025/1/24 14:28:57

前置知识

1、配置插件

微信小程序 基础模板引入sass的两种方法_微信小程序使用sass-CSDN博客

之后在对应页面里新建一个scss文件,写css

2、注册小程序,有个自己的appid,不用测试号了

5.1.注册小程序账号获取appid及个人和企业版差异_哔哩哔哩_bilibili

微信公众平台

3、微信小程序开发学习(基础)-CSDN博客

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 滑块

swiper | 微信开放文档

swiper-item | 微信开放文档

<!-- 写成循环 -->
<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主的成果

8.0.【完结撒花】项目打包上线及课程总结_哔哩哔哩_bilibili

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1329995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud Alibaba(itheima)

SpringCloud Alibaba 第一章 微服务介绍1.1系统架构演变1.1.1单体应用架构1.1.2垂直应用架构1.1.3分布式架构1.1.4 SOA架构1.1.5微服务架构 1.2微服务架构介绍1.2.1微服务架构的常见问题1.2.2微服务架构的常见概念1.2.3微服务架构的常见解决方案 1.3 SpringCloud Alibaba介绍1.…

前端 JS 安全对抗原理与实践

作者&#xff1a;vivo 互联网安全团队- Luo Bingsong 前端代码都是公开的&#xff0c;为了提高代码的破解成本、保证JS代码里的一些重要逻辑不被居心叵测的人利用&#xff0c;需要使用一些加密和混淆的防护手段。 一、概念解析 1.1 什么是接口加密 如今这个时代&#xff0c;…

RabbitMQ入门指南(六):消息转换器及其案例

专栏导航 RabbitMQ入门指南 从零开始了解大数据 目录 专栏导航 前言 一、消息转换器 二、RabbitMQ默认转换器案例&#xff08;省略交换机&#xff09; 三、JSON转换器案例&#xff08;省略交换机&#xff09; 1.配置JSON转换器 2.运行结果 总结 前言 RabbitMQ是一个高…

ruoyi若依前后端分离版部署centos7服务器(全)

目录 VMware虚拟机 centos7 安装环境如下 一、msql 5.7 二、nginx1.23.3 三、java8 四、redis 3.2.1 五、部署若依前端 六、部署若依后端 前言 虚拟机的桥接与nat模式 : 重点 重点&#xff01;&#xff01;&#xff01; 无线不可以用桥接模式 &#xff0c;而你用了nat模式会…

lv12 linux设备树、网卡驱动移植

目录 1 设备树 1.1概念 1.2 设备树文件 1.3 设备树语法 2 Linux内核驱动移植 2.1 步骤 3 实验八网卡驱动移植 3.1 在内核源码的顶层目录下执行如下命令&#xff0c;修改内核配置 3.2 在设备树中添加网卡的硬件信息 3.3 修改时钟相关配置&#xff08;忽略无用的时钟&…

opencv入门到精通——改变颜色空间

目录 目标 改变颜色空间 对象追踪 如何找到要追踪的HSV值&#xff1f; 目标 在本教程中&#xff0c;你将学习如何将图像从一个色彩空间转换到另一个&#xff0c;像BGR↔灰色&#xff0c;BGR↔HSV等 除此之外&#xff0c;我们还将创建一个应用程序&#xff0c;以提取视频中的…

《深入理解计算机系统》学习笔记 - 第七课 - 机器级别的程序三

Lecture 07 Machine Level Programming III Procedures 机器级别的程序三 文章目录 Lecture 07 Machine Level Programming III Procedures 机器级别的程序三概述程序机制 栈结构栈说明栈定义推入数据弹出数据 调用控制代码示例程序控制流程%rip 传递数据ABI 标准示例 管理局部…

YB75XXH系列是采用CMOS工艺制造,低功耗的高压稳压器

YB75xxH 高耐压线性稳压器 ■产品简介&#xff1a; YB75XXH系列是采用CMOS工艺制造&#xff0c;低功耗的高压稳压器&#xff0c;最高输入电压可达25V,输出电压范围为1.5V一12.0V。它具有高精度的输出电压、极低的供电电流、极低的跌落电压等特点。 ■产品特点&#xff1a; …

使用Guava轻松创建和管理不可变集合

第1章&#xff1a;引言 大家好&#xff0c;我是小黑。今天&#xff0c;我们来聊聊一个在Java编程里超有用的话题&#xff1a;使用Guava创建和管理不可变集合。首先&#xff0c;咱们得明白&#xff0c;什么是不可变集合。简单来说&#xff0c;不可变集合就是一旦创建就不能被修…

深入了解 Android 中的应用程序签名

深入了解 Android 中的应用程序签名 一、应用程序签名介绍1.1 应用程序签名1.2 应用程序签名的意义1.3 应用程序签名的流程1.4 应用程序签名的方案1.5 签名的重要性和应用场景 二、AOSP 的应用签名2.1 AOSP的应用签名文件路径2.2 应用程序指定签名文件 三、Android Studio 的应…

【SpringBoot篇】基于Redis实现生成全局唯一ID的方法

文章目录 &#x1f354;生成全局唯一ID&#x1f339;为什么要生成全局唯一id&#x1f33a;生成全局id的方法✨代码实现 &#x1f354;生成全局唯一ID 是一种在分布式系统下用来生成全局唯一id的工具 在项目中生成全局唯一ID有很多好处&#xff0c;其中包括&#xff1a; 数据…

在Next.js和React中搭建Cesium项目

在Next.js和React中搭建Cesium项目&#xff0c;需要确保Cesium能够与服务端渲染(SSR)兼容&#xff0c;因为Next.js默认是SSR的。Cesium是一个基于WebGL的地理信息可视化库&#xff0c;通常用于在网页中展示三维地球或地图。下面是一个基本的步骤&#xff0c;用于在Next.js项目中…

信号与线性系统翻转课堂笔记8——周期信号的频谱

信号与线性系统翻转课堂笔记8——周期性信号的频谱 The Flipped Classroom8 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#xff0c;重点&#…

【github】github设置项目为私有

点击setting change to private 无脑下一步

【Proteus/8086】swjtu西南交大微机与接口技术实验:计时器

实验内容: 计时器基本功能: 1)CPU必须用8086 2)计时器最小计时单位为秒。 3)以00:00格式显示计时,前2位表示分钟,后2位表示秒。 4)计时器是正计时方式 5)有暂停、继续计时功能 6&#xff09;有复位计时功能 7&#xff09;每次按下暂停键&#xff0c;能显示计时间隔时间 参考…

uniapp中使用封装步骤条组件

针对步骤条封装完终于清清楚楚啦 先看效果&#xff1a; 附上代码&#xff1a;使用可直接复用&#xff1a;数据是写在了当前组件中&#xff0c;如有必须&#xff0c;可以使用其中的props传值stepInfos传递相应的数据&#xff0c;根据steps步数就可以控制走到哪一步啦 <temp…

双向数据绑定是什么

一、什么是双向绑定 我们先从单向绑定切入单向绑定非常简单&#xff0c;就是把Model绑定到View&#xff0c;当我们用JavaScript代码更新Model时&#xff0c;View就会自动更新双向绑定就很容易联想到了&#xff0c;在单向绑定的基础上&#xff0c;用户更新了View&#xff0c;Mo…

在 Windows 中关闭指定端口的方法

方法一&#xff1a;使用命令行&#xff08;Command Prompt&#xff09; 查找端口占用情况 打开命令提示符&#xff08;Command Prompt&#xff09;并输入以下命令来查找占用指定端口的进程&#xff1a; netstat -aon|findstr "<port_number>" 这里的 <p…

【笔记】Spring的循环依赖

Spring的循环依赖 ObjectFactory:函数式接口&#xff0c;可以将lambda表达式作为参数放在方法的实参种&#xff0c;在方法执行的时候&#xff0c;并不会实际的调用当前lambda表达式&#xff0c;只有在调用getObject方法的时候才回去调用lambda表达式 为什么spring要用三级缓存…

一周工作问题总结(2023.12.18-2023.12.22)

一周工作问题总结 1. 接口调用频率2. 汉字在数据库中占用字节问题3. Map在循环中修改自己的key与value4. Group BY5.递归同步数据6.代码移动Idea飘红 1. 接口调用频率 供应商给的接口可以每秒调用5-10次&#xff0c;那么我为了保险每秒调用5次&#xff0c;为了防止过度调用接口…