小程序学习笔记

文件和目录结构介绍

页面文件

配置文件介绍

全局配置-window 配置

全局配置-pages 配置

全局配置-tabbar 配置

页面配置

项目配置文件和配置sass

sitemap.json 文件

只有index页面能被索引到,sitemap.json当中的配置

小程序的样式和组件介绍

样式-尺寸单位 rpx

样式-全局样式和局部样式

组件-组件案例演示

view 小程序提供的容器组件,可以直接当成 div 使用即可

小程序当中一些标签的作用及其属性含义

<!-- src:图片的资源地址 -->
<!-- mode:图片的裁剪和缩放模式 -->
<!-- show-menu-by-longpress:长按展示菜单,菜单中有转发给好友、收藏、保存等功能 -->
<!-- lazy-load:图片懒加载功能,在滑动到一定的距离(上下三屏)以后展示图片 -->
<!-- <image src="../../assets/floor/1.png" mode="aspectFit" show-menu-by-longpress lazy-load /> -->

<!-- user-select:长按以后选中文本 -->
<!-- space:显示连续空格 -->
<!-- ensp(全部展示),emsp(空格更大了),nbsp(以字符大小进行展示)空格 -->
<!-- text里面不能写其他标签,否则不会展示 -->
<!-- <text user-select space="nbsp"><view user-select>尚硅谷</view>尚     硅谷</text> -->

<!-- 在进行 页面跳转时,需要再路径的前面添加 / 斜线,否则跳转不成功 -->
<!-- <navigator url="/pages/list/list?id=10&num=hua">到商品列表页面</navigator>
<navigator url="/pages/cate/cate?id=10&num=hua" open-type="switchTab">到商品分类页面</navigator> -->

<!-- navigate:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,保留上一级页面  -->
<!-- <navigator url="/pages/list/list" open-type="navigate">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="navigate">到商品分类页面</navigator> -->

<!-- redirect:只能跳转到非 TabBar 页面,不能跳转到 TabBar 页面,关闭上一级页面,也就不能通过箭头来返回了 -->
<!-- <navigator url="/pages/list/list" open-type="redirect">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="redirect">到商品分类页面</navigator> -->

<!-- switchTab:只能跳转到 TabBar 页面,不能跳转到非 TabBar 页面,关闭其他所有的非 TabBar 页面 -->
<!-- <navigator url="/pages/list/list" open-type="switchTab">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="switchTab">到商品分类页面</navigator> -->

<!-- reLaunch:关闭所有页面,然后打开小程序中某一个页面  -->
<!-- <navigator url="/pages/list/list" open-type="reLaunch">到商品列表页面</navigator>
<navigator url="/pages/cate/cate" open-type="reLaunch">到商品分类页面</navigator> -->

组件案例-轮播图区域绘制

组件案例-轮播图图片添加

组件案例-绘制公司信息区域

组件案例-跳转到商品列表

组件案例-推荐商品区域

组件案例-字体图标的使用

背景图的使用

事件绑定和事件对象

事件分类以及阻止事件冒泡

事件传参-data-*自定义数据

事件传参-mark 自定义数据

<!-- view 小程序提供的容器组件,可以直接当成 div 使用即可 -->
<!-- 第一种绑定事件的方式: bind:事件名 -->
<button type="primary" bind:tap="handler">绑定事件</button>
<!-- 第一种绑定事件的方式: bind事件名 -->
<button type="primary" bindtap="handler">绑定事件</button>
<!--在小程序中,input输入框默认没有边框,需要自己添加样式 -->
<input type="text" bindinput="getinputvalue" />


<view class="line"></view>

<view class="catch" bind:tap="parentHandler">
  <button bind:tap="btnHandler">按钮</button>
  <!-- 
    子组件事件被触发了
    父组件事件被触发了
  -->
</view>
<view class="catch" bind:tap="parentHandler">
  <button catch:tap="btnHandler">按钮</button>
  <!-- 
    子组件事件被触发了
  -->
</view>
<!-- 如果需要展示数据,在 wxml 中需要使用双大括号写法将变量进行包裹 -->
<view>{{school}}</view>
<view>{{obj.name}}</view>
<!-- 绑定属性值,如果需要动态绑定一个变量,属性值也需要使用双大括号进行包裹 -->
<view id="{{id}}">绑定属性值</view>
<!-- 不加上双大括号的话,将不会生效 -->
<!--如果属性值是布尔值,也需要使用双大括号进行包裹 -->
<checkbox checked="{{isChecked}}" />

<!-- 算数运算 -->
<view>{{id + 1}}</view>
<view>{{id - 1}}</view>

<!-- 三元运算 -->
<view>{{id === 1 ? '等于' : '不等于'}}</view>

<!-- 逻辑判断 -->
<view>{{id === 1}}</view>

<!-- 在双括号写法内部,只能写表达式,不能写语句,也不能调用 js 的方法 -->
<!-- <view>{{if(id===1) {}}}</view> -->
<!-- <view>{{ for(const i=0; i<= 10;i++) {}}}</view> -->
<!-- <view>{{obj.name.toUpperCase}}</view>  页面中不会显示 -->
// pages/cate/cate.js
Page({
  btnHandler(event) {
    // currentTartget 事件绑定者,也就是指:哪个组件绑定了当前事件处理函数
    // target 事件触发者,也就是指:哪个组件触发了当前事件处理函数
    // currentTartget 和 target 都是指按钮,因为是按钮绑定的事件处理函数,同时点击按钮触发事件处理函数
    // 这时候通过谁来获取数据都可以
    console.log(event.currentTartget.dataset.id, '555')
    console.log(event.target.dataset.name, '555')
  },
  // view 绑定的事件处理函数
  parentHandler(event){
    // 点击蓝色区域(不点击按钮)
    // currentTartget 事件绑定者:view
    // target 事件触发者:view
    // currentTartget 和 target 都是指 view,如果想要获取 view 身上的数据,使用谁都可以

    // 点击按钮(不点击蓝色区域)
    // currentTartget 事件绑定者:view
    // target 事件触发者:按钮
    // 如果想要获取 view 身上的数据,必须使用currentTartget身上的才可以
    // 如果相获取的是事件触发者,就需要使用target
    console.log(event)

    // 在传递参数的时候,如果自定义属性是多个单词,单词与单词之间使用中划线 - 进行连接
    // 在事件对象中会被转换为小驼峰写法
    console.log(event.currentTarget.dataset.parentId)

    // 在传递参数的时候,如果自定义属性是多个单词,单词如果使用的小驼峰写法
    // 在事件对象中会被转为全部小写的 
    console.log(event.currentTarget.dataset.parentname)
  },
  // 按钮绑定的事件处理
  btnHandlerMark(event) {
    console.log(event.mark.id)
    console.log(event.mark.name)
  },
  parentHandlerMark(event) {
    // 先点击蓝色区域(不点击按钮)
    // 通过事件对象获取的是 view 身上绑定的函数

    // 先点击按钮(不点击蓝色区域)
    // 通过事件对象获取到的是 触发事件的节点 以及 父节点身上所有的 mark 数据
    console.log(event)
  },
  /**
   * 页面的初始数据
   */
  data: {

  },

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

  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady() {

  },

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

  },

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

  },

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

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom() {

  },

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

  }
})

WXML 语法

声明和绑定数据

setData() 修改数据

setData() – 修改对象类型数据

setData() – 修改数组类型数据

/**
   * 页面的初始数据
   */
  data: {
    num: 1,
    userInfo:{
      name: 'tom',
      age: 10,
      test: 111
    },
    list: [1,2,3]
    // list: [{id: 1, name: 'tom'}]
  },
  updateNum() {
    // 获取数据(要修改数据需要先获取到数据)
    // 通过赋值的方式直接修改数据
    // 能够修改数据,但是不能改变页面上的数据
    // this.data.num += 1
    // console.log(this.data.num)
    // 这个方法接收一个对象作为参数
    // this.setData() 两个作用 
    // 1.更新数据
    // 2.驱动数据(页面)更新
    this.setData({
      // key: 是需要更新的数据
      // value: 是最新的值
      num: this.data.num + 1
    })
  },
  updateUserInfo() {
    // 新增单个 / 多个属性
    // this.setData({
    //   // 如果是给对象新增属性,可以将key写给数据路径的方式 a.b.c
    //   'userInfo.name': 'tom',
    //   'userInfo.age': 10,
    // })

    // 修改单个和多个属性
    // this.setData({
    //   // 如果需要修改对象属性,也可以将 key 写成数据路径的方式 a.b.c
    //   'userInfo.name': 'jerry',
    //   'userInfo.age': 18
    // })

    // 目前进行新增和修改都是使用数据路径,如果新增和修改的数据量比较小,还可以
    // 如果修改的数据很多,每次都写数据路径就太麻烦了
    // 可以使用 es6 提供的展开运算符和Object.assign()

    // es6 提供的展开运算符
    // 通过展开运算符,能够将对象中的属性赋值给另一个对象
    // 后面的属性会覆盖前面的属性
    //  const userInfo = {
    //    ...this.data.userInfo,
    //    name: 'jerry',
    //    age: 18
    //  }
    // this.setData({
    //   userInfo
    // })

    // Object.assign() 将多个对象合并为一个对象
    // const userInfo = Object.assign(this.data.userInfo, {name: 'jerry'}, {age: 18})
    // this.setData({
    //   userInfo
    // })

    // 删除单个属性
    // delete this.data.userInfo.age
    // console.log(this.data.userInfo)
    // this.setData({
    //   userInfo: this.data.userInfo
    // })
    // 删除多个属性 rest 剩余参数
    // const {age,test,...rest} = this.data.usserInfo
    // this.setData({
    //   userInfo: rest
    // })
  },
  // 更新list
  updateList() {
    // 新增数组元素
    // 如果直接使用push方法,可以直接更新 data,但是不能更新 页面中的数据
    // this.data.list.push(4)
    // this.setData({
    //   list: this.data.list
    // })

    // const newList = this.data.list.concat(4)
    // this.setData({
    //   list: newList
    // })

    // const newList = [...this.data.list, 4]
    // this.setData({
    //   list: newList
    // })
    // 修改数组元素
    // this.setData({
    //   'list[1]': 6
    //   // 'list[0].name': 'jerry'
    // })
    // 删除数组元素
    // this.data.list.splice(1, 1)
    // this.setData({
    //   list: this.data.list
    // })
    const newList = this.data.list.filter(item=>item !== 2)
    this.setData({
      list: newList
    })
  },

简易双向数据绑定

<!-- 单向绑定,数据能够影响页面,但是页面更新不会影响到数据 -->
<!-- <input type="text" value="{{value}}" /> -->

<!-- 双向绑定:数据能够影响页面,页面更新也能够影响数据 model:  -->
<!-- 如果想实现简易双向绑定,需要在对应的属性之间添加 model: -->
<input type="text" model:value="{{value}}" />

<!-- 如果需要获取复选框的选中效果,需要给 checked 添加 model: -->
<checkbox model:checked="{{isChecked}}"/>是否同意该协议

<!-- 注意事项1: 属性值只能是一个单一事项的绑定 -->
<!-- AppData数据改变之后,视图能够改变,但是视图改变之后,数据不能改变 -->
<input type="text" model:value="值为 {{value}}"/>

<!-- 注意事项2: 属性值不能写数据路径,也就是不支持对象和数组 -->
<!-- AppData数据改变之后,视图能够改变,但是视图改变之后,数据不能改变 -->
<input type="text" model:value="{{obj.value}}"/>

列表渲染-基本使用

<!-- 如果需要进行列表渲染,需要使用wx:for属性 -->
<!-- 属性值需要使用双大括号进行包裹 -->
<!-- 每一项变量名默认是item -->
<!-- 每一项下标(索引) 的变量名默认是 index -->

<!-- 如果渲染的是数组, item:数组的每一项,index: 下标 -->
<!-- <view wx:for="{{numList}}">{{item}}-{{index}}</view> -->

<!-- 如果渲染的是对象,item:对象属性的值,index:对象属性 -->
<!-- <view wx:for="{{obj}}">{{item}}-{{index}}</view> -->

<!-- wx:key 提升性能 -->
<!-- wx:key 属性值有两种添加形式 -->
<!-- 1.字符串,需要是遍历数组中 item 的某个属性,要求该属性是列表中唯一的字串或者数字,不能进行动态改变 -->
<!-- 保留关键字 *this, *this 代表的是item 本身,item本身是唯一的字符串或者数字" -->
<!-- wx:key 的属性值不需要使用双大括号进行包裹,直接写遍历的数组中 item 的某个属性 -->
<!-- wx:key如果不加上的话,控制台会报错 -->
<view wx:for="{{fruitList}}" wx:key="id">{{item.name}}</view>

<view wx:for="{{numList}}" wx:key="*this">{{item}}</view>

列表渲染-进阶用法

<!-- 如果需要修改默认的变量名,需要使用 wx:for-item 属性 -->
<!-- 如果需要修改默认的下标变量名,需要使用 wx:for-index 属性 -->
<!-- 两个属性需要和 wx:for 写到同一个组件上 -->
<!-- 再重命名,修改以后,需要使用最新的变量名才可以 -->
<!-- 数组 -->
<view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">{{fruitItem.name}}</view>
<!-- 对象 -->
<view wx:for="{{obj}}" wx:key="index" wx:for-item="value" wx:for-index="key">{{value}}-{{key}}</view>

<!-- <view wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
  <view>名字: {{fruitItem.name}}</view>
  <view>价格: {{fruitItem.price}}</view>
</view> -->

<!-- block 不是一个组件,只是渲染元素 -->
<!-- 也就是只是包装元素,可以组织代码结构,支持列表渲染 -->
<!-- block不会在页面中做任何渲染,只接受控制属性 -->
<block wx:for="{{fruitList}}" wx:key="id" wx:for-item="fruitItem" wx:for-index="i">
  <view>名字: {{fruitItem.name}}</view>
  <view>价格: {{fruitItem.price}}</view>
</block>

条件渲染

<!-- wx:if 属性组 -->
<!-- wx:if wx:elif wx:else -->
<!-- 只有对应的条件成立,属性所在的组件才会进行展示 -->
<!-- <view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view> -->

<!-- wx:elif wx:else 不能单独使用,在使用的时候,必须结合 wx:if 来使用 -->
<view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view>

<!-- 使用了 wx:if 属性组的组件不能被打断,组件必须连贯才可以 -->
<view wx:if="{{num === 1}}">num 等于 {{num}}</view>
<!-- <view></view> -->
<view wx:elif="{{num === 2}}">num 22等于 {{num}}</view>
<view wx:else>num 大于 2,目前 num 等于 {{num}}</view>

<!-- hidden 属性 -->
<!-- hidden 属性  属性值 如果是 true,就会隐藏结构,如果是 false,才会展示结构 -->
<view hidden="{{ !isFlag }}">如果isFlag 是true,展示结构,否则隐藏结构</view>

<!-- wx:if 控制结构的展示与隐藏,通过新增与移除结构来实现的 -->
<!-- hidden 属性控制结构的显示与隐藏,是通过 css 的 display 属性来实现 -->

小程序运行机制

小程序更新机制

  // onLaunch 是小程序的钩子函数,这个钩子函数在冷启动时肯定会执行到
  // 当小程序冷启动时,会自动微信后台请求新版本的信息,如果有新版本,会立即进行下载
  onLaunch() {
    // 使用wx.getUpdateManager() 方法监听下载的状态
    const UpdateManager = wx.getUpdateManager()
    // 当下载完成新版本之后,会触发 onUpdateReady 回调函数
    UpdateManager.onUpdateReady(function() {
      // 在回调函数中给用户提示
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备完成,是否重新启动应用?',
        success(res){
          if(res.confirm){
            // 强制当前小程序使用新版本并且会重启当前小程序
            updateManager.applyUpdate()
          }
        },
        complete: (res) => {
          if (res.cancel) {
            
          }
          if (res.confirm) {
            
          }
        }
      })
    })
  }

小程序生命周期介绍

应用生命周期

当进行冷启动时,才会触发 onLaunch 钩子函数
如果是热启动,不会触发 onLaunch 钩子函数,会触发 onShow 钩子函数
因此 onLaunch(全只会触发一次)

页面生命周期

onLoad:一个页面只会调用一次

onReady:一个页面只会调用一次

onHide:在当前小程序进入后台时,也会触发执行

onShow:如果从后台进入前台,也会触发

小程序 API 介绍

网络请求

界面交互-loading 提示框

// 获取数据
  getData() {
    wx.showLoading({
      // 用来显示提示的内容
      // 提示的内容不会自动换行,如果提示的内容比较多,因为在同一行展示
      // 多出来的内容会被隐藏
      title: '数据加载中...',
      // 是否显示透明层,防止触摸穿透
      mask: true
    })
    // 如果需要发起网络请求,需要使用 wx.request API
    wx.request({
      // 接口地址
      url: 'https://gmall-prod.atguigu.cn/mall-api/index/findBanner',
      // 请求方式
      method: 'GET',
      // 请求参数
      data:{},
      // 请求头
      header: {},
      // API 调用成功之后 执行的回调
      success: (res) => {
        if(res.data.code === 200) {
          this.setData({
            list: res.data.data
          })
        }
        console.log(res)
      },
      // API 调用失败之后,执行的回调
      fail: (err) => {
        console.log(err)
      },
      // API 不管调用成功还是失败以后,执行的回调
      complete: (res) => {
        console.log(res)
        // 关闭掉loading提示框
        // hideLoading 和 showLoading 必须结合,配对使用才可以
        wx.hideLoading()
      }
    })
  }, 

界面交互-模态对话框-消息提示框

  // 删除商品
  async delHandler() {
    // showModal 显示模态对话框
    const {confirm} = await wx.showModal({
      title: '提示',
      content: '是否删除该商品?'
    })
    if(confirm) {
      // showToast 消息提示框
      wx.showToast({
        title: '删除成功',
        icon: 'none',
        duration: 2000
      })
    }else {
      wx.showToast({
        title: '取消删除',
        icon: 'none',
        duration: 2000
      })
    }
    console.log(res)
  },

本地存储

 // 将数据存储到本地
  setStorage() {
    // 第一个参数:本地存储中指定的 key
    // 第二个参数: 需要存储的数据
    // wx.setStorageSync('num', 1)

    // 在小程序中
    // 如果存储的是对象类型数据,不需要使用 JSON.stringify 和 JSON.parse 进行转换
    // wx.setStorageSync('obj', {name: 'tom',age: 18})

    // --------------- 异步API --------------------
    wx.setStorage({
      key: 'num',
      data: 1
    })
    wx.setStorage({
      key: 'obj',
      data: {name:'jerry', age:18}
    })
  },
  // 获取本地存储的数据
  async getStorage() {
    // 从本地存储的数据中获取指定key的数据,内容
    const num = wx.getStorageSync('num')
    const obj = wx.getStorageSync('obj')
    console.log(num,obj)

    // --------------- 异步API --------------------
    const {data} = await wx.getStorage({
      key:'obj',
    })
    console.log(data)
  },
  // 删除本地存储的数据
  removeStorage() {
    // 从本地移除指定 key 的数据,内容
    wx.removeStorageSync('num')

    // --------------- 异步API --------------------
    wx.removeStorage({
      key: 'num',
    })
  },
  // 清空本地存储的全部数据
  clearStorage() {
    wx.clearStorageSync()
    // --------------- 异步API --------------------
    wx.clearStorage()
  },

路由与通信

页面处理函数-上拉加载

页面处理函数-下拉刷新

  // 监听用户上拉加载
  onReachBottom() {
    console.log('监听用户上拉加载')
    // 产品需求:
    // 当用户上拉,需要数字进行累加

    // 当用户上拉加载时,需要对数据进行累加,每次加载 3 个数字
    // 目前是 [1,2,3],[1,2,3,4,5,6]
    // 怎么进行追加?
    // 获取目前数组中最后一项 n,n+1, n+2, n+3
    wx.showLoading({
      title: '数据加载中...',
    })
    setTimeout(()=>{
      // 获取数组的最后一项
      const lastNum = this.data.numList[this.data.numList.length -1]
      // 定义需要追加的元素
      const newArr = [lastNum+1,lastNum+2,lastNum+3]
      this.setData({
        numList: [...this.data.numList, ...newArr]
      })
      wx.hideLoading()
    },1500)
  },
  // 监听用户下拉刷新
  onPullDownRefresh() {
    console.log('监听用户下拉刷新')
    // 产品需求:
    // 当用户上拉加载更多以后,如果用户进行了下拉刷新
    // 需要将数据进行重置
    this.setData({
      numList: [1,2,3]
    })
    // 在下拉刷新之后,loading效果有可能不会回弹回去
    if(this.data.numList.length === 3) {
      wx.stopPullDownRefresh()
    }
  },

增强 scroll-view

profile.wxml

<scroll-view 
    scroll-y
    class="scroll-y"

    lower-threshold="100"
    bindscrolltolower="getMore"
    enable-back-to-top

    refresher-enabled
    refresher-default-style="white"
    refresher-background="#f7f7f7"
    bindrefresherabort="refreshHandler"
    refresher-triggered="{{isTriggered}}"
>
  <view wx:for="{{numList}}" wx:key="*this">{{item}}</view>  
</scroll-view>
profile.js
  // scroll-view 上拉加载更多事件的事件处理函数
  getMore() {
    wx.showLoading({
      title: '数据加载中...',
    })
    setTimeout(()=>{
      // 获取数组的最后一项
      const lastNum = this.data.numList[this.data.numList.length -1]
      // 定义需要追加的元素
      const newArr = [lastNum+1,lastNum+2,lastNum+3]
      this.setData({
        numList: [...this.data.numList, ...newArr]
      })
      wx.hideLoading()
    },1500)
  },
  refreshHandler() {
    wx.showToast({
      title: '下拉刷新...',
    })
    this.setData({
      numList: [1,2,3],
      isTriggered: false // 允许弹回去
    })
  },


创建和注册组件

组件的数据以及方法

Component({

  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据,用来定义当前租价所需要使用的数据
   */
  data: {
    isChecked: false
  },

  /**
   * 组件的方法列表:在组件中,所有的事件处理函数都需要写在methods方法中
   */
  methods: {
    // 更新复选框的状态
    updateChecked() {
      this.setData({
        isChecked: !this.data.isChecked
      })
    }
  }
})

组件的属性

组件 wxml slot - 插槽

<!-- <text>我是自定义组件</text> -->
<view class="custom-checkbox-container">
  <view class="custom-checkbox-box {{ position === 'right' ? 'right' : 'left'}}">
    <checkbox value="{{isChecked}}" bindtap="updateChecked" />
    <view>
      <!-- label 和 子节点内容都进行了展示 -->
      <!-- 要么展示 label 要么展示 子节点内容 -->
      <!-- 如果用户传递了label属性,就展示label -->
      <!-- 如果用户没有传递 label 属性,就展示 子节点内容 -->
      <text wx:if="{{label !== ''}}">{{label}}</text>
      <slot wx:else></slot>
    </view>
  </view>
</view>


<!-- label 文本显示内容 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
<view class="line"></view>
<custom-checkbox label="匿名提交" position="left">
  匿名提交 - 111
</custom-checkbox>

组件样式以及注意事项

如果是在全局样式文件中设置样式,会影响项目中全部的相同组件
如果是在页面样式文件中设置样式,会影响当前页面所有的相同组件

组件样式隔离

数据监听器

  // 用来监听数据以及属性是否发生了改变
  observers: {
    // key:需要监听的数据
    // value: 就是一个回调函数,形参:最新的数据
     num: function(newNum) {
      //  对 data 中的数据进行监听,如果数据没有发生改变,监听器不会执行
       console.log(newNum)
     },
     count: function(newCount) {
      //  对 data 中的数据进行监听,如果数据没有发生改变,监听器不会执行
       console.log(newCount)
     },
    //  同时监听多个数据
    'num,count': function(newNum,newCount) {
      console.log(newNum,newCount)
    },
    // 支持监听属性以及内部属性的变化
    'obj.name': function(newName) {
      console.log(newName)
    },
    'arr[1]': function(newItem) {
      console.log(newItem)
    },
    // 使用通配符
    'obj.**': function(newObj) {
      console.log(newObj)
    },
    'label': function(newlabel) {
      // 只要使用者传递了数据,这时候在监听器中就能获取传递的数据
      // 也就是说,监听器立即就执行了
      console.log(newlabel)
    }
  },
  /**
   * 组件的方法列表
   */
  methods: {
    // 更新数据
    updateData() {
      this.setData({
        // num: this.data.num +1,
        // count: this.data.count - 1
        // 'obj.name': 'jerry',
        // 'arr[1]': 666
        label: '最新的标题'
      })
    }
  }

组件通信-父往子传值

  observers: {
    // 如果需要将 properties 中的数据赋值给 data
    // 可以使用 observers 进行处理
    checked: function(newChecked) {
      console.log(newChecked)
      this.setData({
        isChecked: newChecked
      })
    }
  },



<!-- 组件传值 index.wxml -->
<!-- label 文本显示内容 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>
<view class="line"></view>
<view class="custom">
  <custom-checkbox label="匿名提交" position="left">
  匿名提交 - 111
  </custom-checkbox>
</view>

组件通信-子往父传值

   // 更新复选框的状态
    updateChecked() {
      this.setData({
        // isChecked: !this.data.isChecked,
        checked: !this.properties.checked
        // label: '在组件内部也可以修改 properties 中的数据'
      })
      console.log(this.properties.checked)
      // 在js中可以访问和获取 properties 中的数据
      // 但是一般情况下,不建议修改,因为会造成数据流的混乱

      // 目前复选框组件的 状态是存储在复选框组件内部的,存储在自定义父组件内部的
      // 但是,在以后实际开发中,组件使用者,父组件有时候也需要获取到复选框内部的状态
      // 怎么办?
      // 这时候,自定义组件内部就需要发射一个自定义事件
      // 如果组件使用者,父组件需要使用数据,绑定自定义事件进行获取即可
      this.triggerEvent('changechecked', this.data.isChecked)
    }



<-- 组件使用者及其逻辑 -->
<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}" bind:changechecked="getData">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>



  getData(event) {
    console.log(event.detail)
    if(event.detail) {
      console.log('提交')
    } else {
      console.log('请同意协议! ')
    }
  }

组件通信-获取组件实例

<custom-checkbox label="我已阅读并同意 用户协议 和 隐私协议" position="right" checked="{{isChecked}}" class="child" id="child" bind:changechecked="getData">
  我已阅读并同意 用户协议 和 隐私协议 - 111
</custom-checkbox>


// 获取子组件实例对象
  getChild() {
    // this.selectComponent 方法获取子组件实例对象
    // 获取到实例对象之后,就能获取子组件所有的数据,也能调用子组件的方法
    const res = this.selectComponent('#child')
    console.log(res.data.isChecked)
  }

组件生命周期

// components/custom06/custom06.js
Component({

  /**
   * 组件的属性列表
   */
  properties: {

  },

  /**
   * 组件的初始数据
   */
  data: {
    name: 'tom'
  },

  /**
   * 组件的方法列表
   */
  methods: {

  },

  // 组件生命周期声明对象
  lifetimes: {
    // created: 组件实例被创建好以后执行
    created() {
      console.log('组件 created')

      // 在组件实例刚刚被创建时执行,注意此时不能调用 setData
      // 可以去给组件添加一些自定义的属性,可以通过this的方式进行添加
      this.test = '测试'
      this.setData({
        name: 'jerry'
      })
    },
    // 组件被初始化完毕,模板解析完成,已经把组件挂载到页面上
    attached() {
      console.log('组件 attached')
      console.log(this.test)
      // 一般页面中的交互会在 attached 钩子函数中进行执行
      this.setData({
        name: 'jerry'
      })
    },
    // 组件被销毁时
    detached() {
      console.log('组件 detached')
    }
  }
})

组件所在页面的生命周期

具体效果可以看实际操作

  // 组件所在页面的生命周期
  pageLifetimes: {
    // 监听组件所在的页面展示(前台切后台)状态
    show() {
      console.log('组件所在页面被展示')
    },
    // 监听组件所在的页面隐藏(前台切后台,点击 tabBar)状态
    hide() {
      console.log('组件所在页面被隐藏')
    }
  }

小程序生命周期总结

使用 Component 构造页面

Component({
  // 为什么需要使用 Component 方法进行构造页面
  // Component 方法功能比 Page 方法强大很多
  // 如果使用 Component 方法构造页面,可以实现更加复杂的页面逻辑开发
  
  // 小程序页面也可以使用 Component 方法进行构造
  // 注意事项:
  // 1.要求 .json 文件中必须包含 usingComponents 字段
  // 2.里面的配置项需要和 Component 中的配置项保持一致
  // 3.页面中 Page 方法有一些钩子函数,事件监听方法,这些钩子函数,事件监听方法必须放在methods对象中
  // 组件的属性 properties 也可以接受页面的参数,在unLoad 钩子函数中可以通过 this.data 进行获取
  properties: {
    id: String,
    title: String
  },
  data: {
    name: 'tom'
  },
  methods:{
    // 更新 name
    updateName() {
      this.setData({
        name: 'jerry'
      })
    },
    onLoad() {
      console.log('页面加载 - 2')
      console.log(this.data.id)
      console.log(this.data.title)
      console.log(this.properties.id)
      console.log(this.properties.title)
    }
  }
})

拓展:组件复用机制 behaviors

// behavior.js
const behavior = Behavior({
  /**
   * 组件的属性列表
   */
  properties: {
    label: {
      type: String,
      value: '我已同意该协议'
    }
  },

  /**
   * 组件的初始数据
   */
  data: {
    name: 'Tom',
    obj: {
      name: 'Tyke'
    }
  },

  /**
   * 组件的方法列表
   */
  methods: {
    updateName(){
      this.setData({
        name: 'Jerry'
      })
      console.log('我是 behavior 的方法~~~~')    }
  },
  lifetimes: {
    attached(){
      console.log('我是 behavior 的生命周期函数~~~~')
    }
  }
})

export default behavior




// custom08.js
// components/custom08/custom08.js
import behavior from './behavior'
Component({
  behaviors: [behavior],
  // 在以后开发中,使用behaviors进行代码复用的时候
  // 组件 和 behaviors 可能存在相同的字段

  // 如果存在相同的 properties,就近原则,使用组件内部的数据
  properties:{
    label: {
      type: String,
      value:'匿名提交'
    }
  },
  // 如果存在相同的 data
  // 如果是对象类型,属性会进行合并
  // 如果不是对象类型的数据,就近原则,展示的以组件内部为准
  data: {
    name: '在组件中的 name',
    obj: {
      name: '组件中的 obj name',
      age: 100
    }
  },
  // 如果存在相同的方法,就近原则,使用组件内部的数据
  methods: {
    updateName(){
      console.log('我是组件内部的方法!!!!')
    }
  },
  // 如果存在相同的生命周期函数,生命周期的函数都会被触发
  lifetimes: {
    attached(){
      console.log('我是组件内部的生命周期函数 ~~~~~~')
    }
  }
})

拓展:外部样式类

组件使用者
<!-- 属性是在 externalClasses 里面定义的元素 -->
<!-- 属性值必须是一个类名 -->
<custom09 extend-class="my-class" />


组件逻辑
Component({
  externalClasses: ['extend-class']
})

组件结构
<!-- 在同一节点上,如果存在外部样式类 和 普通样式类 -->
<!-- 两个类的优先级是未定义 -->
<!-- 建议:在使用外部样式类的时候,样式需要通过 !important 添加权重 -->
<view class="extend-class box">通过外部样式类修改组件的样式</view>

完善复选框案例以及总结自定义组件

// 如果 styleIsolation 属性值是 shared

  // 这时候呢 externalClasses 选项会失效

  externalClasses: ['xxxxx'],

// 如果要让点击文本之后,按钮也被选中,可以使用label标签包裹起来

使用 npm

自定义构建 npm

Vant Weapp 组件库的使用

Vant Weapp 组件样式覆盖

小程序分包加载

配置分包加载以及打包、引用原则

因为小程序会先下载主包,在主包下载好之后,分包就可以使用主包的公共资源
  "subPackages": [
    {
      "root": "modules/goodModule",
      "name": "goodModule",
      "pages": [
        "pages/list/list",
        "pages/detail/detail"
      ]
    }

独立分包

因为此时主包和其他页面的包还没有被加载
"subPackages": [
    {
      "root": "modules/goodModule",
      "name": "goodModule",
      "pages": [
        "pages/list/list",
        "pages/detail/detail"
      ]
    },
    {
      "root": "modules/marketModule",
      "name": "marketModule",
      "pages": [
        "pages/market/market"
      ],
      "independent": true
    }

分包预下载

  "preloadRule": {
    "pages/index/index": {
      "network": "all",
      "packages": ["modules/goodModule"]
    },
    "modules/marketModule/pages/market/market": {
      "network": "all",
      "packages": ["__APP__"]
    }
  }

  

获取微信头像

逻辑  
  // 用来获取微信头像
  chooseavatar(event) {
    console.log(event)
    // 目前获取的微信头像是临时路径
    // 临时路径时有失效事件的,在实际开发中,需要将临时路径上传到公司的服务器
    const {avatarUrl} = event.detail
    this.setData({
      avatarUrl
    })
  },

页面结构
<view>
  <button class="btn" open-type="chooseAvatar" bindchooseavatar="chooseavatar">
    <image class="avatar" src="{{avatarUrl}}" mode=""/>
  </button>
</view>

获取微信昵称

页面结构
<!-- 需要使用 form 组件包裹住 input 以及button组件 -->
<form bindsubmit="onSubmit">
<!-- input 输入框组件的 type 属性设置为 nickname,用户点击输入框,键盘上方才会显示微信昵称 -->
<!-- 如果添加了 name 属性,form 组件就会自动收集带有 name 属性的表单元素的值  -->
  <input type="nickname" name="nickname" placeholder="请输入昵称" />

  <!-- 如果将 form-type="submit" , 就将按钮变成提交按钮 -->
  <!-- 在点击提交按钮的时候,会触发 表单的 bindsubmit 提交事件 -->
  <button type="primary" plain form-type="submit">点击获取按钮</button>
</form>


.js
  // 获取微信昵称
  onSubmit(event) {
    // console.log(event)
    const {nickname} = event.detail.value
    console.log(nickname)
  }

转发功能

分享到朋友圈

.js 
 // 监听页面按钮的转发 以及 右上角的转发按钮
  onShareAppMessage(obj) {
  console.log(obj)
    return {
      title: '这是一个非常神奇的页面~~~~',
      path: '/pages/cate/cate',
      imageUrl: '../../assets/bgimage.png'
    }
  },
  // 监听右上角 分享到朋友圈 按钮
  onShareTimeline() {
    return {
      title: '帮我砍一刀~~~',
      query: 'id=1',
      imageUrl: '../../assets/bgimage.png'
    }
  },

.wxml
<button open-type="share">转发</button>

手机号验证组件

.js  
// 手机号快速验证
  getPhoneNumber(event) {
    // 通过事件对象,可以看到,在 event.detail 中可以获取到 code
    // code 动态令牌,可以使用 code 换取用户的手机号
    // 需要将 code 发送给后端,后端在接收到 code 以后
    // 也需要调用API,换取用户的真正手机号
    // 在换取成功以后,会将手机号返回给前端
    console.log(event)
  },
  // 手机号实时验证
  getRealtimePhoneNumber(event) {
    console.log(event)
  },

.wxml
<button
  type="primary"
  plain
  open-type="getPhoneNumber"
  bindgetphonenumber="getPhoneNumber"
>快速验证组件</button>

<button
  type="warn"
  plain
  open-type="getRealtimePhoneNumber"
  bindgetrealtimephonenumber="getRealtimePhoneNumber"
>实时速验证组件</button>

客服功能

框架接口-getApp()

app.js
App({
  // 全局共享的数据
  globalData() {
    token: ''
  },
  // 全局共享的方法
  setToken(token) {
    // 如果想获取 token,可以使用 this 的方式进行获取
    this.globalData.token = token
    // 在 App() 方法中如果想获取 App() 实例,可以通过this的方式进行获取
    // 不能通过getApp()方法获取
  },
})


profile.js
// getApp() 用来获取全球唯一的 APP() 实例
const appInstance = getApp()
Page({
  login() {
    // 不要通过 app 实例调用钩子函数
    console.log(appInstance)
    appInstance.setToken('fghionodgnedmnteiy')
  },
})

cart.js
const appInstance = getApp()
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    console.log(appInstance.globalData.token)
  },

页面间通信

//打开页面 
 // 点击按钮触发的事件处理函数
  handler() {
    wx.navigateTo({
      url: '/pages/list/list',
      events: {
        // key: 被打开页面通过 eventChannel 发射的事件
        // value: 回调函数
        // 为事件添加一个监听器,获取到被打开页面传递给当前页面的数据

        currentevent: (res)=>{
          console.log(res)
        }
      },
      success(res) {
        console.log(res)
        // 通过 success 回调函数的形参,可以获取 eventChannel 对象
        // eventChannel 对象提供了 emit 方法,可以发射事件,同时携带参数
        res.eventChannel.emit('myevent', {name: 'tom'})
      }
    })
  }


// 被打开页面
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad(options) {
    console.log(options)
    console.log('小程序页面 - list - onLoad')

    // 通过 this.getOpenerEventChannel() 这个方法可以获取 EventChannel 对象
    const EventChannel = this.getOpenerEventChannel()

    // 通过EventChannel提供的 on 方法来监听页面发射的自定义事件
    EventChannel.on('myevent', (res)=>{
      console.log(res)
    })

    // 通过 EventChannel 提供的 emit 方法也可以向上一级页面传递参数
    // 需要使用 emit 定义自定义事件,携带需要传递的数据
    EventChannel.emit('currentevent', {age: 10})
  },

组件通信-事件总线

import PubSub from 'pubsub-js'

sendData() {
      // publish 发布,发射自定义事件
      // 1.自定义事件的名称
      // 2.需要传递的数据
      PubSub.publish('myevent',{name: this.data.name,age: 10})
    }


  lifetimes: {
    attached() {
      // subscribe 订阅,监听自定义的事件
      // 1.需要订阅,监听的自定义事件名称
      // 2.回调函数,回调函数有两个参数
      //  2.1 msg: 自定义事件的名称
      //  2.2 data: 传递过来的数据
      PubSub.subscribe('myevent', (msg, data)=>{
        console.log(msg, data)
        this.setData({
          name: data.name
        })
      })
    }
  }

自定义导航栏

.json
{
  "usingComponents": {},
  "navigationBarTitleText": "商品分类",
  "navigationBarBackgroundColor": "#00AF92",
  "enablePullDownRefresh": true,
  "backgroundTextStyle": "dark",
  "navigationStyle": "custom"
}

.wxml
<swiper class="custom-swiper" indicator-dots autoplay interval="2000">
  <swiper-item>
    <image src="../../assets/banner/banner-1.png" mode=""/>
  </swiper-item>
  <swiper-item>
    <image src="../../assets/banner/banner-2.png" mode=""/>
  </swiper-item>
  <swiper-item>
    <image src="../../assets/banner/banner-3.png" mode=""/>
  </swiper-item>
</swiper>

上线发布

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值