小程序学习笔记(不断更新)

目录

 项目结构

 app.json文件

​编辑

project.config.json文件

 sitemap.json文件

新建页面

wxml模板

 wxss样式

 app.js文件

宿主环境

通信主体

通信模型

 运行机制

组件 

数据绑定

事件绑定

条件渲染

wxss模板样式

全局样式

局部样式

 全局配置

页面配置

 网络请求

页面导航

 导航到tabBar页面

 导航到非tabBar页面

 后退导航

编程式导航

导航到tabBar页面

 导航到非tabBar页面

 后退导航

导航传参

声明式导航传参

 编程式导航传参

 在onLoad中接收参数

页面事件

下拉刷新

监听页面下拉刷新事件

停止下拉刷新

上拉触底

配置上拉触底距离 

随机颜色

渲染UI美化

加载层loading

节流处理

生命周期

应用生命周期函数 

 页面生命周期函数

 添加编译模式方便开发

wxs脚本

wxs和javaScript的关系

 内嵌在wxml文件里的wxs脚本

​编辑

 自定义wxs脚本文件

 特点

修改跳转页面的title

js字符串转数字

js回调函数参数

项目商铺列表页

自定义组件

创建与局部引入组件

全局引入组件

组件和页面区别

组件样式 

组件样式隔离

 注意点!!

 修改组件隔离选项

data数据

 methods方法

properties属性

 data和properties区别​编辑

数据监听器

纯数据字段

组件生命周期

 组件所在页面的生命周期

插槽

父子组件之间通信

behaviors 组件中共享的东西

使用npm包

Vant Weapp 

使用Vant组件

定制全局主题样式

API Promise化

创建Promise化

实现Promise化

全局数据共享 

 安装MobX

将Store中的成员绑定到页面中

使用Store中的成员

将Store中的成员绑定到组件中

 在组件中使用

分包

 分包加载规则

 限制

 配置方法

打包规则

 引用规则

 独立分包

 应该场景 

独立分包配置

引用独立分包规则

 配置分包预下载

 预下载规则

 自定义tabBar

使用Vant的tabBar

uni-app项目

每做一个模块都新建一个分支

导航栏不显示title

把分支推送到仓库

合并分支全并分支删除分支

下载第三方包前先初始化项目结构

安装第三方网络请求包

main.js添加请求的根路径

对promise网络请求应该用await修饰,方法用async修饰

配置小程序分包

改造swiper-item  url指向分包路径和带上商品ID参数

提示信息组件封装

如果链接要跳转tabbar页面只能用uni.switchTab()

动态绑定样式

遇到接口返回的路径和分包的路径不同可以修改后挂载给数据集合

如果大小是固定那就不需要用rpx,直接使用px

获取屏幕可高度

根据条件动态修改样式

解决滚动条不会自动回到顶部BUG

组件要提供可灵活修改的属性

使用组件的自定义事件

组件吸顶效果

如果真机的跳转焦点效果没出来可以去修改源代码

修改第三方组件样式

防抖处理输入框每次键盘输入都进行查询

 对于数组修改应该新建一个数组,不要修改原数组的顺序,它是个引用对象

增加数组的内容时去重

善用计算属性computed

添加缓存和加载页面时取缓存

添加默认图片属性,当商品没有图片时默认显示

商品列表里的每一项商品可以做成组件

善用过滤器

上拉刷新下一页判断条件

下拉刷新

轮播图放大展示

展示富文本内容

正则替换富文本内容,把图片底下的空白区去掉

解决页面加载瞬间文字闪烁undefind

组件名:uni-goods-nav

使用VUEX全局共享实现购物车功

判断对象obj是否为undefind

调用store里的方法

补充getters

调用getters

因为监听器watch不会在页面加载的时候第一时间执行,所以不会加载购物车的数量

跳转购物车页面添加tab徽标

抽离成mixins供每个tabbar页面使用,因为每个tabbar页面都需要加载购物车数量

修改商品列表组件

获取微信地址需要在manifest.json添加权限

 结构赋值

收货地址数据要放到store里

 让用户重新授权

 苹果手机无法重新授权解决

 利用reduce计算勾选商品的总数 

当购物车商品数量发生改变,mixins数据没有更新的解决办法

购物车结算事件

微信登陆接口

发布


 项目结构

 

 app.json文件

  •  页面样式会覆盖全局样式 

project.config.json文件

  • setting里添加"checkSiteMap": false; 不会提示警告

 sitemap.json文件

  •  默认可以被微信索引所有页面allow
  • 修改成disallow不被索引

新建页面

  • app.json添加配置,会自动创建页面

  •  修改首页

        修改pages里的顺序就可以了,第一位是首页

wxml模板

  • 可以理解成html,但有区别

       

 wxss样式

  • 可以理解成css,但有区别

 app.js文件

宿主环境

        微信就是小程序的宿主环境

通信主体

通信模型

  • 都是由微信客户端来接收请求和响应的

 运行机制

  • 启动过程

  •  渲染过程

组件 

  •  常用视图窗口类组件

  •  使用html的语法
    <rich-text nodes="<h1 style='color:red;'>标题</h1>"></rich-text>
  • 其它常用组件

数据绑定

  • 页面的js文件
  data: {
    msg:'你好'
  },
  •  页面wxml文件
<view>{{msg}}</view>
  • 三元运算

         跟java一样   type == 1 ? '男' : '女'

事件绑定

  • 渲染层触发事件通过微信客户端交给js逻辑层处理

  •  常用事件

  •  事件回调收到event对象,它的属性有

  •  target和currentTarget区别,用得最多是target

 

  •  数据赋值

  •  事件传参数

  •  事件接收参数

  •  input事件

条件渲染

  • wx:if

  • <block>使用wx:if

  •  hidden

  •  wx:if与hidden

  •  wx:for

 不推荐自定义名字,太麻烦

  •  wx:key 没有ID可以用索引

wxss模板样式

  • rpx尺寸单位

        把屏幕分成750份,可以自动适合屏幕大小,和html的vw vh单位一样

        用iphone6作为视觉标准

  • @import样式导入

 

全局样式

  • app.wxss文件里面的都属于全忆样式

局部样式

  • 页面的wxss文件里面的都属于局部样式
  • 当和全局样式冲突,局部会覆盖全局样式

 全局配置

  •  window

         常用配置属性

        enablePullDownRefresh一般不会在全局设置,只会在需要的页面上配置即可

        onReachBottomDistance没有特别需求保持默认值即可

  • tabBar

  tabBar节点配置

list属性

页面配置

  • 如果和全局配置冲突,会覆盖全局配置

常用配置荐

 网络请求

  •  wx.request

 

  • 小程序不存在跨域问题
  • 小程序没有Ajax,Ajax是依赖浏览器XMLHttpRequest对象的

页面导航

 导航到tabBar页面

 导航到非tabBar页面

 后退导航

编程式导航

导航到tabBar页面

 

 导航到非tabBar页面

 

 后退导航

 

导航传参

声明式导航传参

 编程式导航传参

 在onLoad中接收参数

 可以在data里定义一个属性接收options供页面使用

页面事件

下拉刷新

下拉刷新窗口样式

监听页面下拉刷新事件

 

停止下拉刷新

 

上拉触底

一般是用来处理数据列表分页

 注意:要做节流处理,当前上拉触底请求没处理完不能再重复处理

配置上拉触底距离 

随机颜色

  •  js解构
----------------------------------------
const User = {
  name: '搞前端的半夏',
  age: 18
}

const { name, age } = User;

------------------------------------------

const User = {
  name: '搞前端的半夏',
  age: '18',
  contact:{
    phone:'110',
  }
}

const phone = User.contact.phone; //需要通过两层获取.

const  {contact:{phone}}=User
consosle.log(phone)  // 输出10.

----------------------------------------------

const { name, age=18 } = employee;  //可以添加属性,也可以为属性赋默认值

-----------------------------------------------------------------------

const { age: userAge } = User;//为属性定义别名
console.log(userAge); 
  •  js 三个点扩展运算符
// 数组
var number = [1,2,3,4,5,6]
console.log(...number) //1 2 3 4 5 6
//对象
var man = {name:'蔡',height:180}
console.log({...man}) / {name:'蔡',height:180}

---------------------------------------------------
//数组的复制
var arr1 = ['hello']
var arr2 =[...arr1]
arr2 // ['hello']
//对象的复制
var obj1 = {name:'Steven'}
var obj2 ={...obj2}
obj2 //  {name:'Steven'}

---------------------------------------------
//数组的合并
var arr1 = ['hello']
var arr2 =['world']
var mergeArr = [...arr1,...arr2]
mergeArr  // ['hello','world']
// 对象分合并
var obj1 = {name:'Steven'}
var obj2 = {height:181}
var mergeObj = {...obj1,...obj2}
mergeObj // {name: "Steven", height: 181}

渲染UI美化

加载层loading

wx.showLoading(Object object)

title属性必填

网络请求完成回调complete方法需要调用wx.hideLoading

节流处理

生命周期

应用生命周期函数 

 页面生命周期函数

 添加编译模式方便开发

wxs脚本

        wxml文件中不能调用页面.js文件中的函数,但是可以调用wxs定义的函数

        典型应该就是“过滤器”

wxs和javaScript的关系

 内嵌在wxml文件里的wxs脚本

 自定义wxs脚本文件

 特点

  • 不能作为组件事件回调
  • wxs和js代码是隔离的,互相不能调用
  • 在ios设备上wxs比js快2~20倍,安卓设备上没有差异

修改跳转页面的title

  data: {
    //先定义一个接收跳转参数的变量
    query:{}
  },

  onLoad(options) {
    //页面加载时把参数赋值给query变量
    this.setData({
      query: options
    })
  },

  onReady() {
    //页面渲染完成后修改title
    wx.setNavigationBarTitle({
      title: this.data.query.name,
    })
  },

js字符串转数字

  • "80" - 0

js回调函数参数

    this.getShopList(() =>{
      wx.stopPullDownRefresh()
    })

    getShopList(cb) {
        ...;
        cb && cb();
      }
    })
  },

项目商铺列表页

// pages/shopList/shopList.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    hideBottom: true,
    isLoading: false,
    query: {},
    shopList: [],
    page: 1,
    pageSize: 10,
    total: 0
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {

    this.setData({
      query: options
    })
    this.getShopList();
  },
  // cb是回调方法
  getShopList(cb) {
    wx.showLoading({
      title: '加载数据...',
    })
    this.setData({
      isLoading: true
    })
    wx.request({
      url: `https://www.escook.cn/categories/${this.data.query.id}/shops`,
      method: 'GET',
      data: {
        _page: this.data.page,
        _limit: this.data.pageSize
      },
      success: (res) => {
        console.log(res.data)
        this.setData({
          shopList: [...this.data.shopList, ...res.data],
          total: res.header['X-Total-Count'] - 0
        })
      },
      complete: () => {
        wx.hideLoading({
          success: (res) => {

          },
        })
        this.setData({
          isLoading: false
        })
        cb && cb();
      }
    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {
    wx.setNavigationBarTitle({
      title: this.data.query.title,
    })
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {
    this.setData({
      shopList:[],
      page:1,
      total:0,
      hideBottom:true
    })
    // 只有下拉事件的时候才会传关闭下拉更新的回调函数
    this.getShopList(() =>{
      wx.stopPullDownRefresh()
    })
    
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {
    if ((this.data.page * this.data.pageSize) >= this.data.total) {
      this.setData({
        hideBottom: false
      })
      return;
    }
    if (this.data.isLoading) {
      return;
    }
    this.setData({
      page: this.data.page + 1
    })
    this.getShopList();
  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage() {

  }
})
<view class="shop-item" wx:for="{{shopList}}" wx:key="id">
  <image src="{{item.images[0]}}" ></image>
  <view class="shop-info">
    <view>{{item.name}}</view>
    <view>{{item.phone}}</view>
    <view>{{item.address}}</view>
    <view>{{item.businessHours}}</view>
  </view>
</view>
<view class="bottom" hidden="{{hideBottom}}">----------------  我是有底线的  -------------------</view>

自定义组件

创建与局部引入组件

  • 项目结构新建如下目录

  • 在需要引入组件的页面.json里引入

  •  页面wxml文件
<my-test></my-test>

全局引入组件

只要在app.json里引入组件,全部页面就可以使用

/*app.json文件*/
"usingComponents": {
    "my-test":"/components/test/test"
}

组件和页面区别

组件样式 

组件样式隔离

 注意点!!

 修改组件隔离选项

data数据

 methods方法

properties属性

 data和properties区别

 两个都指向同一个地方,里面的数据是共享的,也可以用setData修改properties的数据

数据监听器

 

 rgb:{r:0,g:0,b:0}

 fullColor:"0,0,0"

 简化

纯数据字段

即纯用于业务逻辑处理,不用于页面渲染

 使用规则

组件生命周期

  • lifetimes节点

 组件所在页面的生命周期

  •  pageLifetimes节点

插槽

  • 默认单插槽

  •  启用多插槽

父子组件之间通信

  •  属性绑定,父组件传值给子组件

  •  事件绑定,子组件传值给父组件

 

  • 获取组件实例,访问子组件数据和方法

behaviors 组件中共享的东西

 然后这个组件就可以使用behavior里面的所有东西了

  • behavior可用节点

  • 同名处理

使用npm包

Vant Weapp 

  • 先在项目根目录初始化  命令:npm init -y
  • 安装步骤

Vant Weapp - 轻量、可靠的小程序 UI 组件库

使用Vant组件

定制全局主题样式

  • 以--开头为变量名
  • 以下是在html范围内有效,你也可以自定义在其它范围(类名)里生效,作用范围也会改变

  • 在小程序里可以这样用 

 

记得最好是定义在page范围里,这样页面所有组件都生效

根据你想改变样式的组件类型,找到样式,把变量名改成--开头,加上你要的样式

https://github.com/vant-ui/vant-weapp/blob/dev/packages/common/style/var.less

API Promise化

创建Promise化

  • 第一步

  • 第二步

        为了不出错,先删除项目根目录的miniprogram_npm文件夹 (开发者工具新版本好像不需要删除了)

  • 第三步

        工具---构建npm,成功后重启开发者工具

实现Promise化

wxp和wx.p都是指向同一个内存地址

promisifyAll(wx,wxp)的意思是把微信小程序的wx定级对象进行了promise化,然后赋给wxp

因为wxp和wx.p都是指向同一个内存地址,所以今后可以使用wx.p就是promise化的api

  • 使用

 因为wx.p已经promise化,它调用的api是没有回调函数的,最张会得到promise对象。

所以方法需要加 async修饰,api调用前加await修饰

全局数据共享 

跟vue里的vuex一样

 安装MobX

  • 项目根目录创建store/store.js

 

 get代表是计算属性,是只读的

action函数是修改数据值的

将Store中的成员绑定到页面中

store是数据源、fields是字段(属性)、actions是方法。

storeBindings是得到的对象,前面加this是挂载到当前页面上作为自定义属性来用,可以用来清理绑定的东西

使用Store中的成员

将Store中的成员绑定到组件中

 在组件中使用

分包

  • 主包的公共资源可以被其它分包访问,但是分包里的私有资源不能给其它分包以及主包访问

 分包加载规则

 限制

 配置方法

保存后项目自动生成目录结构 

为每个分包添加别名属性"name": "p1"

开发者工具的基本信息可以查看项目代码体积大小

打包规则

 引用规则

 独立分包

  • 不用下载主包就能打开小程序 

 应该场景 

独立分包配置

在普通分包里加上"independent": true

引用独立分包规则

 

 配置分包预下载

 预下载规则

 自定义tabBar

 自定义 tabBar | 微信开放文档

记住原来的list不能删除,给低版本的兼容用

 

 

使用Vant的tabBar

 

把原来app.json里的tabBar里的list整个复制到custom-tab-bar的.js文件的data里,然后循环item项

  <van-tabbar-item wx:for="{{list}}" wx:key="index" info="{{item.info ? item.info : ''}}">
    <image
      slot="icon"
      src="{{item.iconPath}}"
      mode="aspectFit"
      style="width: 30px; height: 30px;"
    />
    <image
      slot="icon-active"
      src="{{item.selectedIconPath}}"
      mode="aspectFit"
      style="width: 30px; height: 30px;"
    />
    {{item.text}}
  </van-tabbar-item>

在自定义组件里要覆盖Vant的默认样式需开启styleIsolation: 'shared'

数字徽标可以在list里其中一个tab里添加info:this.data.info,页面循环用三元运算判断

组件引入store后需要用监听里面的数据值,如果发生改变就对List里的info赋值,简单

跳转就用wx.switchTab()方法,记得把pagePath要路径前加上/

 解决选中项索引问题,把active抽离到store里,监测到改变tab时修改store里的active

更改选中tab的文本颜色:直接在van-tabbar标签上加上active-color="#123123"写死就好

uni-app项目

每做一个模块都新建一个分支

比如正在做tabbar页面:git checkout -b tabbar

导航栏不显示title

导航栏的navigationBarTitleText会被页面的navigationBarTitleText覆盖

把分支推送到仓库

git push -u origin tabbar

合并分支全并分支删除分支

先切换到主分支才可以合并 git checkout master

然后合并 git merge tabbar

最后把最新的master分支推送到仓库 git push 

因为仓库已经有tabbar分支,所以最后删除本地的tabbar分支 git branch -d tabbar

下载第三方包前先初始化项目结构

npm init -y

安装第三方网络请求包

npm install @escook/request-miniprogram

 如果出现错误 npm ERR! code ECONNREFUSED 解决方法是

npm config set proxy null 
npm config set https-proxy null 
npm config set registry http://registry.npmjs.org/ 

安装成功后导入,在main.js里

// 按需导入 $http 对象
import { $http } from '@escook/request-miniprogram'

// 在 uni-app 项目中,可以把 $http 挂载到 uni 顶级对象之上,方便全局调用
uni.$http = $http

// 请求拦截器
$http.beforeRequest = function(option){
	uni.showLoading({
		title:'加载中...'
	})
}

// 响应拦截器
$http.afterRequest = function(option){
	uni.hideLoading()
}

main.js添加请求的根路径

$http.baseUrl = 'https://www.uinav.com'

对promise网络请求应该用await修饰,方法用async修饰

            async getSwiperList() {
				const {data:res} = await uni.$http.get('/api/public/v1/home/swiperdata')
				if(res.meta.status != 200){
					return uni.showToast({
						title:'请求失败!',
						icon:"none",
						duration:1500
					})
				}
				this.swiperList = res.message
			}

配置小程序分包

  • 第一步:在项目根目录建subpkg文件夹

  •  第二步:在pages.json文件添加配置后保存,注意一定要先保存,不然后面新建子包页面有问题
    "subPackages": [
		{
			"root": "subpkg",
			"pages": []
		}
	],
  • 第三步:在subpkg文件夹添加页面文件

 同时页面配置会记录到pages.json的subPackages里面

改造swiper-item  url指向分包路径和带上商品ID参数

                <navigator class="swiper-item" :url="'/subpkg/goods_detail/goods_detail?goods_id='+ item.goods_id">
					<image :src="item.image_src" ></image>
				</navigator>

这样点轮播图就会跳转到指定的分包页面

提示信息组件封装

参数可以有默认值

// 封装提示信息组件
uni.$showMsg = function(title = '数据请求失败!',duration = 1500){
	uni.showToast({
		title,
		duration,
		icon:'none'
	})
}

如果链接要跳转tabbar页面只能用uni.switchTab()

uni.switchTab({
    url:'/pages/cate/cate',
})

动态绑定样式

:style="{width: item.product_list[0].image_width + 'rpx'}"

遇到接口返回的路径和分包的路径不同可以修改后挂载给数据集合

            async getFloorList() {
				const {
					data: res
				} = await uni.$http.get('/api/public/v1/home/floordata')
				
				res.message.forEach(floor =>{
					floor.product_list.forEach(product =>{
						product.url = '/subpkg/goods_list/goods_list?' +             product.navigator_url.split('?')[1]
					})
				})
				this.floorList = res.message
			}

 再把view改成navigator url跳转

如果大小是固定那就不需要用rpx,直接使用px

获取屏幕可高度

可用高度windowHeight = 屏幕高度 - 导航条高度 - tabbar高度

uni.getSystemInfoSync() - windowHeight

还有顶部如果有搜索的记得减去搜索栏的高度

根据条件动态修改样式

data里放一个被激活的属性active:0,因为默认第一个选中

:class="['left-item', i === active ? 'active':'']"   根据循环索引i的值决定是否有active样式

@click="activeChanged(i)" 添加点击事件,动态修改active为当前索引值

解决滚动条不会自动回到顶部BUG

为scroll-view添加 :scroll-top="scrollTop"属性,scrollTop在data设置为0,激活后赋值Math.random(),或者赋值不为0的数字,这个数字是滚动条么顶部的距离

组件要提供可灵活修改的属性

 

使用组件时如果是字符串类型记得用单引号包起来<my-search :bgcolor="'#000'" :radius="50"></my-search>

使用组件的自定义事件

<my-search @myclick="search"></my-search>因为自定义组件没有myclick事件

所以要在组件的view标签添加@click事件再通过this.$emit('myclick')来调用父页面的myclick事件

组件吸顶效果

    .search-box {
		position: sticky;
		top: 0;
		z-index: 999;
	}	

如果真机的跳转焦点效果没出来可以去修改源代码

修改第三方组件样式

进入uni_modules里面找到需要修改样式的组件

比如:uni-search-bar,找到vue文件,查看组件其中的类名

在引用组件的页面使用相同类名样式覆盖原组件样式

防抖处理输入框每次键盘输入都进行查询

			input(e) {
				//500毫秒内再次输入会清除延时器
				clearTimeout(this.timer)
				//500毫秒延时器
				this.timer = setTimeout(() =>{
					console.log(e)
				},500)
			}

 对于数组修改应该新建一个数组,不要修改原数组的顺序,它是个引用对象

错误:this.histroyList.reverse()

正确:[...this.histroyList].reverse()

增加数组的内容时去重

//把原数组转成set数组
let list = new Set(this.historyList)
//添加元素时先删除数组里相同的元素
list.delete(e)
//添加元素
list.add(e)
//把set数组转变成数组
this.historyList = Array.from(list)

善用计算属性computed

如果使用 methods 执行函数,vue 每次都要重新执行一次函数,不管message 的值是否有变化;

如果使用computed 执行函数,只有当message 这个最初的数据发生变化时,函数才会被执行。(依赖-监测数据变化)

调用:{{history}}

historyList如果没有发生变化,走的缓存,只有它发生变化才执行该方法重新计算。

添加缓存和加载页面时取缓存

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

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

添加默认图片属性,当商品没有图片时默认显示

defaultPic:''

<image :src="goods.goods_small_logo || defaultPic"></image>

商品列表里的每一项商品可以做成组件

        props: {
			goods: {
				type: Object,
				default: {}
			},
		}

调用:<my-goods :goods="goods"></my-goods>

如果没有显示清一下缓存刷新

善用过滤器

        filters: {
			toFixed(num) {
				return Number(num).toFixed(2)
			}
		}

调用:{{goods.goods_price | toFixed}}  这是过滤器的使用方式

上拉刷新下一页判断条件

pagenum * pagesize >= total

下拉刷新

重点是把关闭下拉刷新的方法传给getGoodsList方法和执行

            async getGoodsList(cb) {
				this.isLoading = true
				const {
					data: res
				} = await uni.$http.get('/api/public/v1/goods/search', this.queryObj)
				this.goodsList = [...this.goodsList, ...res.message.goods]
				this.total = res.message.total
				this.queryObj.pagenum = res.message.pagenum
				this.isLoading = false
				cb && cb()
			}

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

轮播图放大展示

<image class="item-pic" :src="pic.pics_big" @click="preview(i)"></image>

            preview(i) {
				uni.previewImage({
					urls: this.goodsInfo.pics.map(x => x.pics_big),
					current: i
				})
			}

展示富文本内容

<rich-text :nodes="goodsInfo.goods_introduce"></rich-text>

正则替换富文本内容,把图片底下的空白区去掉

res.message.goods_introduce.replace(/<img /g,'style:"display:block;"')

/<img 开头   /g 全局

webp图片格式对IOS系统不兼容,同样正则替换

解决页面加载瞬间文字闪烁undefind

v-if="goodsInfo.goods_name"  在标签上加判断

组件名:uni-goods-nav

uni-app官网

 注意不要遮挡最下面的介绍图

使用VUEX全局共享实现购物车功

挂载 VUEX

//  store/store.js

import Vue from "vue"
import Vuex from "vuex"
import moduleCart from "@/store/cart.js"

Vue.use(Vuex)

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

export default store


// main.js
import store from "@/store/store.js"
const app = new Vue({
	...App,
	store
})

store目录里创建cart.js文件作为购物车vuex模块

 store/store.js挂载cart.js

调用 

 

 

补充mutitions

判断对象obj是否为undefind

if(obj)

调用store里的方法

注意mapMutations只能放在methods里使用

import {  mapState, mapMutations  } from "vuex"

methods: {
    ...mapMutations('m_cart', ['addToCart']),
}

buttonClick(e) {
    if (e.content.text === '加入购物车') {
        const goods = {
            goods_id: this.goodsInfo.goods_id,
            goods_name: this.goodsInfo.goods_name,
            goods_price: this.goodsInfo.goods_price,
            goods_count: 1,
            goods_small_logo: this.goodsInfo.goods_small_logo,
            goods_state: true
         }
         this.addToCart(goods)
     }
     this.options[1].info++            
}

补充getters

    getter: {
		total(state) {
			let c = 0
			state.cart.forEeach(x => c += x.goods_count)
			return c
		}
	}

调用getters

    //引入mapGetters
    import {
		mapState,
		mapMutations,
		mapGetters
	} from "vuex"

       //计算属性引入store里的total
		computed: {
			...mapState('m_cart', ['cart']),
			...mapGetters('m_cart', ['total'])
		},
        //监听total变动
		watch: {
			total(newValue) {
				const findResult = this.options.find(x => x.text === '购物车')
				if (findResult) {
					findResult.info = newValue
				}
			}
		},

因为监听器watch不会在页面加载的时候第一时间执行,所以不会加载购物车的数量

解决:

跳转购物车页面添加tab徽标

    //购物车页面
    import {
		mapGetters
	} from "vuex"
	export default {
		computed: {
			...mapGetters('m_cart', ['total'])
		},
		data() {
			return {

			};
		},
		onShow() {
			this.setBage()
		},
		methods: {
			setBage() {
				uni.setTabBarBadge({
					index: 2,
					text: this.total + ''
				})
			}
		},
	}

抽离成mixins供每个tabbar页面使用,因为每个tabbar页面都需要加载购物车数量

把上面的代码放到/mixins/tabbar-badge.js里,然后在每个tabbar页面引用

    import badgeMixin from "@/mixins/tabbar-badge.js"
	export default {
		mixins: [badgeMixin],
		data() {
			return {

			};
		}
	}

修改商品列表组件

showRaido属性是供外面定义的,默认关闭不显示radio

            <label class="radio" v-if="showRadio">
				<radio checked="true" color="#C00000" /><text></text>
			</label>
        props: {
			showRadio: {
				type: Boolean,
				default: false
			},
			goods: {
				type: Object,
				default: {}
			},
		},

获取微信地址需要在manifest.json添加权限

 结构赋值

const [err, succ] = await uni.chooseAddress().catch(err => err)

收货地址数据要放到store里

store/user.js

 让用户重新授权

 苹果手机无法重新授权解决

 利用reduce计算勾选商品的总数 

当购物车商品数量发生改变,mixins数据没有更新的解决办法

购物车结算事件

            settleHandler() {
				if (!this.checkCount) {
					return uni.showToast({
						icon: "none",
						title: '请选择要结算的商品'
					})
				}
				console.log(this.checkCount)
				if (!this.addstr) {
					return uni.showToast({
						icon: "none",
						title: '请填写收货地址'
					})
				}
				if (!this.token) {
					return uni.showToast({
						icon: "none",
						title: '请先登陆'
					})
				}
			}

微信登陆接口

<button type="primary" class="btn-login" open-type="getUserInfo" @click="getUserInfo">
    一键登录
</button>
            async getUserInfo(e) {
				const [err, succ] = await uni.getUserProfile({
					desc: '用于登陆小程序'
				})
				if (err && err.errMsg === 'getUserProfile:fail auth deny') {
					uni.showToast({
						title: '你取消了登陆授权',
						icon: "none"
					})
					return
				}
				if (succ.errMsg === 'getUserProfile:ok') {
					uni.showToast({
						title: succ.userInfo.nickName + '登陆成功',
						icon: "none"
					})

					console.log(succ)
				}
			}

发布

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值