小程序知识点总结

页面

首页

分类

购物车

我的

搜索

商品列表

商品详情

微信支付

使用组件

tabBar

本程序中用到了首页、分类、购物车、我的

轮播图

<!-- 轮播图区域 -->
    <swiper :indicator-dots="true" :autoplay="true" :interval="3000" :duration="1000" :circular="true">
      <!-- 循环渲染轮播图的 item 项 -->
      <swiper-item v-for="(item, i) in swiperList" :key="i">
        <view class="swiper-item">
          <!-- 动态绑定图片的 src 属性 -->
          <image :src="item.image_src"></image>
        </view>
      </swiper-item>
    </swiper>

页面跳转

<swiper-item v-for="(item, i) in swiperList" :key="i">
    <navigator class="swiper-item" :url="'/subpkg/goods_detail/goods_detail?goods_id=' + item.goods_id">
      <!-- 动态绑定图片的 src 属性 -->
      <image :src="item.image_src"></image>
    </navigator>
</swiper-item>

图片展示

<view class="left-img-box">
    <image :src="item.product_list[0].image_src" :style="{width: item.product_list[0].image_width + 'rpx'}" mode="widthFix">            </image>
</view>

滚动视图

<!-- 左侧的滚动视图区域 -->
      <scroll-view class="left-scroll-view" scroll-y :style="{height: wh + 'px'}">
        <view class="left-scroll-view-item active">xxx</view>
        <view class="left-scroll-view-item">xxx</view>
        <view class="left-scroll-view-item">xxx</view>
        <view class="left-scroll-view-item">xxx</view>
        <view class="left-scroll-view-item">xxx</view>
        <view class="left-scroll-view-item">多复制一些节点,演示纵向滚动效果...</view>
      </scroll-view>

uni-icons

<!-- 使用 view 组件模拟 input 输入框的样式 -->
    <view class="my-search-box">
      <uni-icons type="search" size="17"></uni-icons>
      <text class="placeholder">搜索</text>
    </view>

uni-search-bar

<view class="search-box">
  <!-- 使用 uni-ui 提供的搜索组件 -->
  <uni-search-bar @input="input" :radius="100" cancelButton="none"></uni-search-bar>
</view>

uni-tag

<!-- 标题区域 -->
  <view class="history-title">
    <text>搜索历史</text>
    <uni-icons type="trash" size="17"></uni-icons>
  </view>

block 使用

<view>
    <view class="goods-list">
      <block v-for="(goods, i) in goodsList" :key="i">
        <view class="goods-item">
          <!-- 商品左侧图片区域 -->
          <view class="goods-item-left">
            <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
          </view>
          <!-- 商品右侧信息区域 -->
          <view class="goods-item-right">
            <!-- 商品标题 -->
            <view class="goods-name">{{goods.goods_name}}</view>
            <view class="goods-info-box">
              <!-- 商品价格 -->
              <view class="goods-price">¥{{goods.goods_price}}</view>
            </view>
          </view>
        </view>
      </block>
    </view>
  </view>

uni-goods-nav

<!-- 商品导航组件 -->
<view class="goods_nav">
  <!-- fill 控制右侧按钮的样式 -->
  <!-- options 左侧按钮的配置项 -->
  <!-- buttonGroup 右侧按钮的配置项 -->
  <!-- click 左侧按钮的点击事件处理函数 -->
  <!-- buttonClick 右侧按钮的点击事件处理函数 -->
  <uni-goods-nav :fill="true" :options="options" :buttonGroup="buttonGroup" @click="onClick" @buttonClick="buttonClick" />
</view>

radio

<!-- 商品左侧图片区域 -->
<view class="goods-item-left">
  <!-- 存储在购物车中的商品,包含 goods_state 属性,表示商品的勾选状态 -->
  <radio :checked="goods.goods_state" color="#C00000" v-if="showRadio"></radio>
  <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
</view>

uni-number-box

<view class="goods-info-box">
  <!-- 商品价格 -->
  <view class="goods-price">¥{{goods.goods_price | tofixed}}</view>
  <!-- 商品数量 -->
  <uni-number-box :min="1"></uni-number-box>
</view>

uni-swipe-action 和 uni-swipe-action-item

<!-- 商品列表区域 -->
<!-- uni-swipe-action 是最外层包裹性质的容器 -->
<uni-swipe-action>
  <block v-for="(goods, i) in cart" :key="i">
    <!-- uni-swipe-action-item 可以为其子节点提供滑动操作的效果。需要通过 options 属性来指定操作按钮的配置信息 -->
    <uni-swipe-action-item :options="options" @click="swipeActionClickHandler(goods)">
      <my-goods :goods="goods" :show-radio="true" :show-num="true" @radio-change="radioChangeHandler" @num-change="numberChangeHandler"></my-goods>
    </uni-swipe-action-item>
  </block>
</uni-swipe-action>

button

<!-- 选择收货地址的盒子 -->
<view class="address-choose-box" v-if="JSON.stringify(address) === '{}'">
  <button type="primary" size="mini" class="btnChooseAddress" @click="chooseAddress">请选择收货地址+</button>
</view>

样式美化

常用样式

display

justify-content

flex-direction

align-items

display

flex-wrap

top

z-index

text-align

line-height

position

transform

text-overflow

overflow

white-space

box-sizing

flex

&::

border-radius

box-shadow

使用颜色

技术点

下拉刷新

pages.json 中添加如下

{
      "path" : "pages/cate/cate",
      "style" :{
          // "navigationBarTitleText": "",
          "enablePullDownRefresh": false
      }
    },

页面中 methods 方法增加

    onPullDownRefresh() {
      this.queryObj.pagenum = 1
      this.total = 0
      this.isloading = false
      this.goodsList = []
      this.getGoodsList(()=> uni.stopPullDownRefresh())
    }

上拉加载

page.json 中添加如下

{
        "path" : "goods_list/goods_list",
        "style" :                                                                                    
    {
        // "navigationBarTitleText": "",
        "enablePullDownRefresh": true,
        "onReachBottomDistance": 150,
        "backgroundColor": "#f8f8f8"
    }

}

页面方法中增加

    onReachBottom() {
      if (this.queryObj.pagenum * this.queryObj.pagesize >= this.total) return uni.$showMsg('数据加载完毕!')
      if(this.isloading) return
      this.queryObj.pagenum += 1
      // console.log(this.queryObj.pagenum)
      this.getGoodsList()
    },

左移删除

使用组件 uni-swipe-action

<!-- 商品列表区域 -->
<!-- uni-swipe-action 是最外层包裹性质的容器 -->
<uni-swipe-action>
  <block v-for="(goods, i) in cart" :key="i">
    <!-- uni-swipe-action-item 可以为其子节点提供滑动操作的效果。需要通过 options 属性来指定操作按钮的配置信息 -->
    <uni-swipe-action-item :options="options" @click="swipeActionClickHandler(goods)">
      <my-goods :goods="goods" :show-radio="true" :show-num="true" @radio-change="radioChangeHandler" @num-change="numberChangeHandler"></my-goods>
    </uni-swipe-action-item>
  </block>
</uni-swipe-action>

methods 中实现删除功能

// 点击了滑动操作按钮
swipeActionClickHandler(goods) {
  console.log(goods)
}

吸顶效果

封装组件

组件的构成:页面布局;

父页面如下:

<my-goods :goods="goods" :show-radio="true" @radio-change="radioChangeHandler" :showNum="true" @num-change="numberChangeHandler"></my-goods>
      //商品的勾选状态发生了变化 
      radioChangeHandler(e){
        this.updateGoodsState(e)
        console.log("-------")
        // console.log(e) 
      },
      
      // 商品的数量发生了变化 
      numberChangeHandler(e){
        this.updateGoodsCount(e)
        console.log(e)
      },

子页面如下:

<template>
  <view class="goods-item">
    <view class="goods-item-left">
      <radio :checked="goods.goods_state" color="#c00" v-if="showRadio" @click="radioClickHandler"></radio>
      <!-- <text>{{goods.goods_small_logo}}</text> -->
      <image :src="goods.goods_small_logo || defaultPic" class="goods-pic"></image>
    </view>
    <view class="goods-item-right">
      <view class="goods-name">{{goods.goods_name}}</view>
      <view class="goods-info-box">
        <view class="goods-price">${{goods.goods_price | tofixed}}</view>
        <uni-number-box :min="1" :value="goods.goods_count" v-if="showNum" @change="numChangeHandler"></uni-number-box>
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    name:"my-goods", 
    props: {
      goods: {
        type: Object,
        default: {},
      },
      // 是否展示图片左侧的 radio
      showRadio: {
        type: Boolean,
        // 如果外界没有指定 show-radio 属性的值,则默认不展示 radio 组件
        default: false
      },
      // 是否显示价格右侧的 NumberBox 组件
      showNum:{
        type: Boolean,
        default: false,
      },
      
    },
    data() {
      return {
        defaultPic: 'https://img3.doubanio.com/f/movie/8dd0c794499fe925ae2ae89ee30cd225750457b4/pics/movie/celebrity-default-medium.png',
        
      };
    },
    filters: {
      tofixed(num){
         return Number(num).toFixed(2)
      }
    },
    methods:{
      //radio 组件 的点击事件处理函数
      radioClickHandler(){
         // 通过 this.$emit() 触发外界通过@绑定的 radio-change 事件,
         //同时把商品的 id 和勾选状态作为参数传递给 radio-change 事件处理函数
         this.$emit('radio-change',{
           //商品 id
           goods_id: this.goods.goods_id,
           //商品最新的勾选状态
           goods_state: !this.goods.goods_state
         })
      },
      
      //NumberBox 组件的 change 事件处理函数 
      numChangeHandler(val){
        console.log(val)
        //通过 this.$emit()触发外界通过@ 绑定 num-change 事件
        this.$emit('num-change',{
          goods_id : this.goods.goods_id,
          goods_count: +val 
        })
      }
    }
  }
</script>

<style lang="scss">
  
</style>

其中:props中定义在子页面中使用的数据,方法使用 this.$emit 进行向父窗口传值。

分包

分包的目的:为了小程序首次加载时速度变快

pages.json 中增加

"subPackages": [
    {
      "root": "subpkg",
      "pages": [],
    }
  ]

在根目录下增加 subpkg 文件夹,增加新的页面

mixins

抽离出一个公共的 js 文件,方法进行徽标的设置

在根目录下新建一个 mixins 文件夹,新建一个 tabbar-badge.js 文件

import {mapGetters} from 'vuex'

export default{
  
  computed: {
    //  将 m_cart 模块中的 total 映射为当前页面的计算属性
    ...mapGetters('m_cart',['total'])
  },
  watch:{
    total() {
      this.setBadge()
    }
  },
  onShow() {
    //在页面展示的时候,设置数字徽标
    this.setBadge()
  },
  methods: {
    setBadge(){
      //调用 uni.setTabBarBadger()方法,为购物车设置右上角的徽标
      uni.setTabBarBadge({
        index: 2,   //索引
        text: this.total + ''   // 注意,text 的值必须是字符串,不能是数字 
      })
    }
  },
  
}

home.vue 页面进入导入

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

持久化

持久化数据都放在 store.js 中

import Vue from 'vue'
import Vuex from 'vuex'
import moduleCart from '@/store/cart.js'
import moduleUser from '@/store/user.js'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules:{
    'm_cart': moduleCart,
    'm_user': moduleUser
  }
})

export default store

然后在每个 js 中进行各自类型的持久化,文件的结构如下。其中包括 state,mutation 和 getters

export default {
  
  namespaced: true,
  
  state: () => ({
    cart: JSON.parse(uni.getStorageSync('cart') || '[]'),
  }),
  
  mutations: {
    // 增加商品到购物车
    addToCart(state,goods){
      const findResult = state.cart.find(x => x.goods_id === goods.goods_id)
      // console.log(findResult)
      if(!findResult){
        state.cart.push(goods)
      }else{
        findResult.goods_count++
      }
      
      // 通过 commit 方法,调用 m_cart 命名空间下 saveToStorage方法
      this.commit('m_cart/saveToStorage')
    },
    
    // 将购物车的数据持久化存储到本地
    saveToStorage(state){
      // console.log(state.cart)
      uni.setStorageSync('cart',JSON.stringify(state.cart))
    },
  },
  
  getters: {
    //  勾选的商品的总数量
    checkedCount(state){
      let checkedCount = state.cart.filter(x => x.goods_state).reduce((total,item) => total += item.goods_count,0)
      return checkedCount
    },
  }
   
}

调用如下:

import {mapState,mapMutations}  from 'vuex'
  export default {
    mixins: [badgeMix],
    computed: {
      ...mapState('m_cart',['cart'])
    },
    data() {
      return {
      }
    },
    methods:{
      ...mapMutations('m_cart',['updateGoodsState','updateGoodsCount','removeGoodsById']),
      //商品的勾选状态发生了变化 
      radioChangeHandler(e){
        this.updateGoodsState(e)
        console.log("-------")
        // console.log(e) 
      },
    }
  }

后端方法

优化点

注意事项

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358

推荐阅读更多精彩内容

  • 当我们在不同的电脑上开发时,想要开发工具的配置是一样的(字体,字号,主题等等),可以把 project.confi...
    在路上919阅读 950评论 0 0
  • 1、简单描述下微信小程序的相关文件类型?答:微信小程序项目结构主要有四个文件类型,如下1、WXML (WeiXin...
    AKyS佐毅阅读 21,279评论 1 23
  • 一.小程序特点 小程序依赖微信 1.快,因为免去下载和安装 2.小,一个包不能超过2M 3.强,微信有什么能力它也...
    朱朱是个小太阳阅读 203评论 0 0
  • 1. 什么是小程序? 小程序是一种"不需要下载安装"即可使用的应用,它实现了"触手可及"的梦想。使用起来方便快捷、...
    蓝海00阅读 388评论 0 1
  • Uniapp是什么,它的优势和特点Uniapp是一种跨平台开发框架,可以同时开发出iOS、Android、H5等多...
    木火应阅读 1,509评论 0 0