Giter Club home page Giter Club logo

studywxsmallprogram's People

Contributors

cruxf avatar

Stargazers

 avatar

Watchers

 avatar  avatar

studywxsmallprogram's Issues

15.微信小程序路由参数丢失问题及解决方法

前言

场景描述:在B页面跳转到A页面,同时带参数;在B页面跳转到A页面时,触发了某个条件,从A页面自动或者手动回到B页面。在这过程中会发生参数丢失的问题,涉及的代码如下

indexPath1() {
  return `/pages/guide?activity_id=${this.activity_id}`
},
indexPath2() {
  return `/pages/index?activity_id=${this.activity_id}&returnurl=${this.indexPath1()}`
},

onLoad: function(e) {
  this.activity_id = e.activity_id;
  this.returnurl =e.returnurl ? e.returnurl:''
}

原因以及解决方式

由于在参数returnurl中同样带着参数,路由参数的解析是会从?之后第一个&符号开始被截取丢掉。,因此returnurl中的参数会被忽略掉。解决方式就是编码(encodeURIComponent)与解码(decodeURIComponent),代码如下

indexPath1() {
  return `/pages/guide?activity_id=${this.activity_id}`
},
indexPath2() {
  return `/pages/index?activity_id=${this.activity_id}&returnurl=${encodeURIComponent(this.indexPath1())}`
},

onLoad: function(e) {
  this.activity_id = e.activity_id;
  this.returnurl =e.returnurl ? decodeURIComponent(e.returnurl):''
}

5.微信小程序导出变量的两种方式

方式一:

// 导出
export const config = {
  api_base_url: 'http://bl.7yue.pro/v1/',
  appkey: 'P0OM21UZT9jtbsMT'
}
export let fun = function() {

}

// 导入
import { config,fun } from '/config.js'

方式二:

const config = {
  api_base_url: 'http://bl.7yue.pro/v1/',
  appkey: 'P0OM21UZT9jtbsMT'
}
let fun = function() {

}
export { config, fun }

// 导入
import { config, fun } from '/config.js'

10.微信小程序框架wepy学习之路

父子组件传值

与vue父子组件传值相类似,不同的有

  • 在更改数据的时候,需要执行this.$apply()
  • 组件文件与页面文件extends的对象是不一样的,页面是(wepy.page),组件是(wepy.component)
  • 在同一个页面组件复用的时候,命名需要留意
// 父组件
<template>
  <view>
    <view>{{num}}</view>
    <child1 name="leinov" :syncTitle.sync="parentTitle" :twoWayTitle="parentTitleChange"></child1>
    <child2 name="test"></child1>
  </view>
</template>

<script>
import wepy from 'wepy';
import child from '@/components/test';
export default class Demo extends wepy.page {
  data = {
    num: 333,
    parentTitle: '父组件向子组件单向传值',
    parentTitleChange: '子组件能够改变父组件的值'
  };
  watch = {
    num(newValue, oldValue) {
      console.log(`num value: ${oldValue} -> ${newValue}`);
    }
  };
  components = {
    child1: child,
    child2: child
  };
  onLoad() {
    setInterval(() => {
      this.num++;
      this.$apply();
    }, 1000);
  }
}
</script>

<style lang="less">
</style>


// 子组件
<template lang="wxml">
    <view>
      {{title}}{{twoTitle}}
    </view>
</template>

<script>
import wepy from 'wepy';
export default class test extends wepy.component {
  data = {
    title: '',
    twoTitle: ''
  }
  props = {
    // 静态传值
    name: String,
    // 父组件单向动态传值
    syncTitle: {
      type: String,
      default: '传入的不是字符串'
    },
    // 子组件能够改变父组件的值
    twoWayTitle: {
      type: String,
      default: '传入的值有问题',
      twoWay: true
    }
  };
  onLoad() {
    this.title = this.name
    this.$apply()
    console.log(this.name);
    console.log(this.syncTitle);
    console.log(this.twoWayTitle)
    this.twoTitle = this.twoWayTitle
    this.$apply()
    this.twoWayTitle = '改变值'
    this.$apply()
    console.log(this.twoWayTitle)
  }
}
</script>

<style lang="less">
</style>

插槽slot的使用

使用方法和vue一样,代码请看如下:

// 父组件
<template>
  <view>
    <view>{{num}}</view>
    <child1>
      <h1 slot="title">标题值传入</h1>
    </child1>
  </view>
</template>

<script>
import wepy from 'wepy';
import child from '@/components/test';
export default class Demo extends wepy.page {
  data = {
    num: 333
  };

  components = {
    child1: child
  };
  onLoad() {
    
  };
}
</script>

<style lang="less">
</style>


// 自组件
<template lang="wxml">
  <view>
    <slot name="title">Title</slot>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class test extends wepy.component {
  data = {
    title: ''
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>

methods方法

我们需要注意的是WePY中的methods属性与Vue中的用法是不一致的

<template>
  <view>
    <view @tap="clickMe">点击我</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Demo extends wepy.page {
  data = {
    num: 333
  };
  methods = {
    clickMe(){
      console.log("自定义事件能放在内部被直接调用")
      this.fn()
    },
    fn(){
      console.log("自定义事件不能能放在内部被间接调用")
    }
  };
  onLoad() {
    
  }
}
</script>

<style lang="less">
</style>

正确的写法是需要将其提到外部

<template>
  <view>
    <view @tap="clickMe">点击我</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Demo extends wepy.page {
  data = {
    num: 333
  };
  methods = {
    clickMe(){
      console.log("自定义事件能放在内部被直接调用")
      this.fn()
    }
  };
  fn(){
    console.log("自定义事件能放在外部被间接调用")
  }
  onLoad() {
    
  }
}
</script>

<style lang="less">
</style>

组件通信与交互

首先我们来看看父组件向子组件通信,父组件先通过$broadcast发布一个事件

<template>
  <view>
    <view @tap="clickMe">点击我</view>
    <child></child>
  </view>
</template>

<script>
import wepy from 'wepy';
import Child from '@/components/child';
export default class Parent extends wepy.page {
  data = {};
  components = {
    child: Child
  };
  methods = {
    clickMe() {
      this.$broadcast('index-broadcast', '我正在测试哈哈哈哈');
    }
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>

接着子组件订阅该事件

<template lang="wxml">
  <view>
    <view>子组件数据</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Child extends wepy.component {
  data = {
    title: ''
  };
  events = {
    'index-broadcast': (...args) => {
      console.log(args);
      //可以通过以下方法拿到子组件名称+拿到数据的事件名称+事件的来源
      let $event = args[args.length - 1];
      console.log($event);
      console.log(`${this.$name} receive ${$event.name} from ${$event.source.$name}`);
    }
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>

然后我们来看看子组件如何向父组件通信,子组件通过$emit发布一个事件

<template lang="wxml">
  <view>
    <view>子组件数据</view>
    <view @tap="clickChild">子组件点击事件</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Child extends wepy.component {
  data = {
    title: [1,2,3]
  };
  methods = {
    clickChild(){
      this.$emit('chilEmit',this.title)
    }    
  }
  onLoad() {}
}
</script>

<style lang="less">
</style>

接着父组件订阅该事件

<template>
  <view>
    <view @tap="clickMe">点击我</view>
    <child></child>
  </view>
</template>

<script>
import wepy from 'wepy';
import Child from '@/components/child';
export default class Parent extends wepy.page {
  data = {};
  components = {
    child: Child
  };
  methods = {
    clickMe() {
      console.log(233)
    }
  };
  events = {
    'chilEmit':(title)=>{
      console.log(title)
    }
  }
  onLoad() {}
}
</script>

<style lang="less">
</style>

最后是一个页面对另一个组件中的方法直接调用,有点小坑,被调用方是组件,而不能是页面

<template>
  <view>
    <view @tap="clickBorther">兄弟组件事件</view>
  </view>
</template>

<script>
import wepy from 'wepy';
import Child from '@/components/child';
export default class Par extends wepy.page {
  data = {};

  components = {
    borther: Child
  }
  methods = {
    clickBorther() {
      this.$invoke('borther', 'minus',1000000)
    }
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>

被调用方代码

<template lang="wxml">
  <view>
    <view>子组件数据</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Child extends wepy.component {
  data = {
    title: [1,2,3]
  };
  methods = {
    minus(num) {
      console.log(num);
    }
  }
  onLoad() {}
}
</script>

<style lang="less">
</style>

组件自定义事件处理函数

这种自定义事件往往和组件之间通信有关,一方发布一个自定义事件,另一方订阅该自定义事件,并且另一方通过定义某个方法触发该事件

// 父组件
<template>
  <view>
    <view @tap="clickMe">父组件事件</view>
    <child @childFn.user="parentFn"></child>
  </view>
</template>

<script>
import wepy from 'wepy';
import Child from '@/components/child';
export default class Parent extends wepy.page {
  data = {};
  components = {
    child: Child
  };
  methods = {
    clickMe() {
      console.log(233);
    },
    parentFn(des) {
      console.log("从子组件传递过来的内容:"+des)
    }
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>


// 子组件
<template lang="wxml">
  <view>
    <view @tap="clickMe">子组件自定义事件</view>
  </view>
</template>

<script>
import wepy from 'wepy';
export default class Child extends wepy.component {
  data = {
    des: "子组件自定义的事件被触发"
  };
  methods = {
    clickMe(){
      this.$emit("childFn", this.des)
    }
  };
  onLoad() {}
}
</script>

<style lang="less">
</style>

实用的参考文章

13.兼容性:不能在animation中有切换图片的行为

为了让某张图片看上去有闪烁的动画效果,有时候我们可能会使用animation切换背景图来达到目的,比如:

.light-click{
  position: absolute;
  overflow: hidden;
  height: 172rpx;
  width: 172rpx;
  left: 50%;
  margin-left: -70rpx;
}
.cus-btn1{
  height: 172rpx;
  width: 172rpx;
  animation: breathe 1.5s linear 0.5s infinite;
}
@keyframes breathe {
  0% {
    background-image: url('giftblack.png');
  }
  100% {
    background-image: url('giftlight.png');
  }
}

这样做会留有坑,尤其是在IOS中,会出现背景图不显示的问题,我们应该这么来写代码

.light-click{
  position: absolute;
  overflow: hidden;
  height: 172rpx;
  width: 172rpx;
  left: 50%;
  margin-left: -70rpx;
  z-index: 2200;
  background-image: url("giftlight.png");
}
.cus-btn1{
  height: 172rpx;
  width: 172rpx;
  opacity: 0.3;
  background-image: url("giftlight.png");
  animation: breathe 1.5s linear 0.5s infinite;
}

@keyframes breathe {
  0% {
    opacity:0;
  }
  50% {
    opacity:1;
  }
  100% {
    opacity:0;
  }
}

9.微信小程序之swiper组件

前言

看下面代码之前建议先到官网瞧一瞧看一看,然后再看下面的一个小demo

wxml文件

<view class="nofoot-cont has-bg" wx:if="{{isNone}}">
  <view class="mainFrame">
    <swiper class="container" indicator-dots="{{indicatorDots}}" indicator-dots="{{indicatordots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}" circular="{{circular}}" bindchange="bindChange">
      <block wx:for="{{project_data}}" wx:key="index">
        <swiper-item class="vol-swiper-item" bindtap="onItemClick">
          <view class="vol-card" data-id="{{item.id}}" catchtap="onPostTap">
            <view class='card-header'>
              <image src='../../../images/tip1.png' class='tip-image'></image>
              <view class='user-image'>
                <image src='../../../images/product.png'></image>
                <text class='pro-item-tt'>流浪地球</text>
              </view>
              <image src='../../../images/pro_2.png' class='tip-image' bindtap='aJump' data-url='../../member/createPro/createPro'></image>
            </view>
            <view class='card-body'>
              <view class='body-box'>
                <view class="item-oper">
                  <image src='../../../images/p1.png'></image>
                  <text>报名的大赛</text>
                </view>
                <view class="item-oper">
                  <image src='../../../images/p2.png'></image>
                  <text>投递的BP</text>
                </view>
              </view>
              <view class='body-box'>
                <view class="item-oper">
                  <image src='../../../images/p3.png'></image>
                  <text>融资信息</text>
                </view>
                <view class="item-oper">
                  <image src='../../../images/p4.png'></image>
                  <text>项目计划书</text>
                </view>
              </view>
            </view>
            <view class='card-footer'>
              <view class="pro-btn">
                <text>您的项目计划书没上传,您可以</text>
                <text>1.打开电脑并在浏览器输入www.chuangcheng.org.cn/file</text>
                <text>2.在打开的网页中输入您的手机号码&密钥:{{item.key}}</text>
              </view>
              <view class="pro-tip">
                <text>更多功能,请用电脑登录</text>
                <text>创成汇官网:https://www.chuangcheng.org.cn</text>
              </view>
            </view>
          </view>
        </swiper-item>
      </block>
    </swiper>
  </view>
</view>

wxss文件

.head-right {
  text-align: right;
  padding-right: 15rpx;
}

.head-right image {
  width: 40rpx;
  height: 40rpx;
  vertical-align: -8rpx;
}

.no-pro {
  margin-top: 200rpx;
  text-align: center;
}

.no-pro image {
  display: block;
  width: 400rpx;
  height: 400rpx;
  margin: 0 auto;
}

.no-pro text {
  display: block;
  font-size: 28rpx;
  color: #999;
  margin: 40rpx auto;
}

.no-pro a {
  display: block;
  margin: 0rpx auto;
  width: 260rpx;
  height: 80rpx;
  border: 1rpx solid #108ee9;
  line-height: 80rpx;
  color: #108ee9;
  border-radius: 40rpx;
  font-size: 28rpx;
}

.has-bg {
  background-color: #108ee9;
}

.mainFrame {
  margin-top: 0rpx;
  height: 100%;
  display: flex;
  flex-direction: column;
}

.container {
  height: 100vh;
  padding-top: 0rpx;
  background: #108ee9;
  box-sizing: border-box;
}

.vol-swiper-item {
  margin-top: 30rpx;
  box-sizing: border-box;
  padding-left: 30rpx;
  padding-right: 30rpx;
}

.vol-card {
  padding: 30rpx;
  border: 2rpx solid #ebebeb;
  border-radius: 10rpx;
  width: 75vw;
  background: #fff;
  margin: 0 auto;
}

.card-header {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.tip-image {
  display: inline-block;
  height: 80rpx;
  width: 80rpx;
  border-radius: 50%;
}

.user-image {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.user-image .pro-item-tt {
  margin-top: 8rpx;
  font-size: 4vw;
}

.user-image image {
  width: 120rpx;
  height: 120rpx;
  border-radius: 50%;
}

.card-body {
  margin-top: 40rpx;
  display: flex;
  justify-content: center;
  flex-direction: column;
  align-items: center;
}

.body-box {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  margin-top: 10rpx;
  width: 60vw;
}

.item-oper {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  box-shadow: #ddd 0 0 10px;
  padding: 20rpx;
  width: 20vw;
}

.item-oper image {
  width: 60rpx;
  height: 60rpx;
  margin-bottom: 27rpx;
}

.card-footer {
  margin-top: 30rpx;
}

.pro-btn {
  font-size: 24rpx;
  word-break: break-all;
  line-height: 35rpx;
}

.pro-btn text {
  display: block;
}

.pro-tip {
  font-size: 24rpx;
  margin: 30rpx auto 20rpx;
  text-align: center;
}

.pro-tip text {
  line-height: 40rpx;
}

.pro-tip text:last-child {
  color: #108ee9;
}

js文件

Page({

  /**
   * 页面的初始数据
   */
  data: {
    indicatorDots: false,
    autoplay: false,
    interval: 2000,
    indicatordots: false,
    duration: 1000,
    circular: true,
    isNone: true,
    project_data: [{
      click: 0,
      company_created_time: "2018-02-27",
      field: "高端",
      id: 6417,
      is_plan: true,
      key: "819476",
      logo: "/storage/image/190327/MuHJBpkohsHonz0ew6b2UJFhdSLsz6mDANJtafBW.jpeg",
      product_file_id: "172494",
      product_step: 1,
      state: 2,
      title: "流浪地球",
      user_id: 21491,
      view_num: 0,
      vote_num: 0,
    }, {
      click: 0,
      company_created_time: "2018-02-27",
      field: "高端",
      id: 6417,
      is_plan: true,
      key: "819476",
      logo: "/storage/image/190327/MuHJBpkohsHonz0ew6b2UJFhdSLsz6mDANJtafBW.jpeg",
      product_file_id: "172494",
      product_step: 1,
      state: 2,
      title: "流浪火星",
      user_id: 21491,
      view_num: 0,
      vote_num: 0,
    }]
  },

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

  },
  // swiper滑动事件
  bindChange(e){
    console.log(e)
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },
  onPostTap: function(event) {
    var postId = event.currentTarget.dataset.id;
    console.log(postId)
  },
  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },

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

  },

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

  },

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

  },

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

  },

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

  }
})

14.微信小程序页面传值的方式大全

开门见山的说,下面是一些微信小程序页面之间传值的方式

  • 方式一:利用数据缓存API
  • 方式二:利用父子组件传值
  • 方式三:利用路由传值
  • 方式四:利用getCurrentPages()方法,该方法十分的强大,能记录跳转的每一个页面的记录,能查找到页面重要的data数据以及route地址。该方法常应用的场景是点击按钮回到某一个页面中,仔细体会下面的代码
let elist = getCurrentPages()
let minebrouter = elist[elist.length - 2]
let workrouter = elist[elist.length - 3]
if(minebrouter.data.returnurl){
  this.replace(minebrouter.data.returnurl)
} else {
  wx.navigateBack({
    delta: 2,
  });
  workrouter.onLoad(workrouter.options)
}

4.在微信小程序中使用iconFont

前言

我们有时候想要自己搞一个项目,然而无奈有些icon不会制作,那么此时我想你可以来iconfont这个网站来看看,这里有大量的icon图标,基本能满足平时的任何开发需要,下面讲解一下具体的使用方法。

开发步骤

  • 进入iconfont官网
  • 选择好icon图标添加到项目中,然后选择“下载至本地”
    image
  • 将iconfont.css文件中内容全部拷贝到局部的wxss文件中或者是全局的wxss文件中
  • 最后直接在wxml文件中直接进行调用即可
<text class='iconfont 图标名'></text>

2.可能会遇到的面试题目

wx.setstoragesync和wx.setstorage的区别是什么?

这是关于同步缓存和异步缓存的区别。以Sync(同步,同时)结尾的都是都是同步缓存,二者的区别是

  • 异步不会阻塞当前任务
  • 同步缓存直到同步方法处理完才能继续往下执行。

通俗点说,异步就是不管保没保存成功,程序都会继续往下执行。同步是等保存成功了,才会执行下面的代码。使用异步,性能会更好;而使用同步,数据会更安全。

bindtap点击事件与catchtap点击事件的区别是什么?

  • bindtap点击事件会向上冒泡
  • catchtap点击事件不会向上冒泡
<view class='view1' bindtap='view1click'>
  <text>view1</text>
  <view class='view2' bindtap='view2click'>
    <text>view2</text>
    <view class='view3' catchtap='view3click'>
      <text>view3</text>
    </view>
  </view>
</view>

6.封装一个HTTP请求(基础)

前言

像我这样的菜鸟在开发项目的时候,往往不懂得如何去封装一些公共方法使开发更加便捷与优雅,导致慢慢的对代码失去些热情,还好及时意识到 “要想学得更快和更多,首先得学会付出——花钱”。趁年轻,好好花钱投资自己的头脑,这永远也不亏!

开发步骤

首先我们需要创建一个工具库函数,用来存放可能会改变的变量,比如域名以及appkey什么的

const config = {
  api_base_url: 'http://bl.***.pro/v1/',
  appkey: ''
}
export {
  config
}

接下来这个是重头戏,使用一个类,封装了公共的HTTP请求方法,并且定义了公共的错误处理函数。在HTTP请求方法中,当访问成功的时候会利用回调函数把数据返回到特定的Page对象中

import {
  config
} from '../config.js'
// 错误提示
const tips = {
  1: '抱歉,出现了一个未知错误',
  1005: 'appkey无效,请前往www.***.pro申请',
  3000: '期刊不存在'
}

class HTTP {
  // 网络请求函数
  request(params) {
    if (!params.method) {
      params.method = 'GET'
    }
    wx.request({
      url: config.api_base_url + params.url,
      method: params.method,
      data: params.data,
      header: {
        'content-type': 'application/json',
        'appkey': config.appkey
      },
      success: (res) => {
        let code = res.statusCode.toString()
        // 判断状态码是否以2开头
        if (code.startsWith('2')) {
          // 回调函数
          params.success(res.data)
        } else {
          let error_code = res.data.error_code
          this._show_error(error_code)
        }
      },
      fail: (err) => {
        this._show_error(1)
      }
    })
  }

  // 错误处理函数
  _show_error(error_code) {
    if (!error_code) {
      error_code = 1
    }
    wx.showToast({
      title: tips[error_code],
      icon: 'none',
      duration: 2000
    })
  }
}

export {
  HTTP
}

最后我们再来调用这个公共的HTTP请求方法

import {HTTP} from '../../utils/http.js'
let http = new HTTP()
Page({
  /**
   * 页面的初始数据
   */
  data: {

  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    http.request({
      url:'classic/latest',
      success:(res)=>{
        console.log(res)
      }
    })
  }
})

通过以上对一个HTTP请求方法的封装,我们在编写代码就能省非常多的力气,并且使代码更加容易维护和高大上。

1.开发过程中遇到的小问题及解决方式

1、本地资源无法通过 WXSS 获取

场景:在wxss中无法这么来设置背景图片background-image:url('../img/logo.jpg');

解决方式

可以使用网络图片,或者 base64,或者使用标签。下面来讲解一下使用base64的过程

  • 首先来到某个能把图片转成base64的网站
  • 接着选择图片文件,将其转成base64格式
  • 最后将background-image:url('../img/logo.jpg');替换成转换后的代码即可。

2、如何让text内容空格?

在text标签中一定得加上decode="{{true}}",然后在需要显示空格的地方放&nbsp;想空几个空格就放几个&nbsp;

<text decode="{{true}}" space="{{true}}">&nbsp;&nbsp;</text>



3、微信小程序 image组件的mode属性 以及 图片出现横向滚动轴

4、如何引用相同的WXSS代码文件?

@import '../doctorTeam/doctorTeam.wxss';



5、text元素中的文本无法设置行高

那是因为text默认的display值默认为inline,需要设置为inline-block或者block那么才可以设置行高。

6、定时器问题

我们要特别留意一点,所有页面的脚本逻辑都跑在同一个JsCore线程,页面使用setTimeout或者setInterval的定时器,然后跳转到其他页面时,这些定时器并没有被清除,需要开发者自己在页面离开的时候进行清理。

7、this.setData({})无法修改 对象[属性]问题解决

在vue中,我们可以对同一种对象的属性进行统一操作,代码如下

showInfo: {
  base: false,
  experience: false,
  code: false,
  full: false
}

this.showInfo[type] = true

在微信小程序中这么做却是会报错的

showInfo: {
  base: false,
  experience: false,
  code: false,
  full: false
}

this.setData({
  showInfo[type]: true
})

我们只能通过这种方式来解决该问题

showInfo: {
  base: false,
  experience: false,
  code: false,
  full: false
}

this.setData({
  'showInfo.base': true
})



8.在微信小程序中使用wxs

前言

wxs文件的概念请移步到官网进行查看,下面我们在谈谈如何运用。

过滤时间

比如在调后台接口的时候,返回一个时间参数,格式为“2019-03-30 18:55:26”。而前端页面只需要取的月日和星期即可,那么该如何实现呢

步骤一:在同目录下创建一个wxs外部文件

var monthDay = function (value) {
  var date = getDate(value);
  var Month = date.getMonth() + 1;
  var Day = date.getDate();
  var M = Month < 10 ? '0' + Month: Month;
  var D = Day + 1 < 10 ? '0' + Day: Day;
  return M +'-'+D;
}
var week = function (value) {
  var weekArr = ['周一','周二','周三','周四','周五','周六','周日'];
  var date = getDate(value);
  var week = date.getDay();
  return weekArr[week];
}
module.exports = {
  monthDay: monthDay,
  week: week
}

步骤二:在wxml文件中进行引用

<wxs module='filter' src='filter.wxs' />
<view>
{{filter.monthDay(item.start_time)}} {{filter.week(item.start_time)}}
</view>

错误排查

在编写wxs最让人奔溃的一件事情就是代码由于马虎写错了一些却没有任何的报错信息,目前我的解决办法是通过console.log()进行排查,以下代码第四行出现拼写错误,那么‘243’则不会被打印到控制台。

var dateObj = function (value) {
  console.log(22)
  var date = getDate(value);
  var Year = data.getFullYear();
  var Month = date.getMonth() + 1;
  var Day = date.getDate();
  var Hour = date.getHours();
  var Minu = date.getMinutes();
  var M = Month < 10 ? '0' + Month : Month;
  var D = Day + 1 < 10 ? '0' + Day : Day;
  var H = Hour < 10 ? '' + Hour: Hour;
  var Mi = Minu < 10 ? '' + Minu: Minu;
  console.log(243)
  return Year+'/'+M+'/'+D+' '+H+':'+Mi;
}

12.兼容性:解决视频或其他组件层级较高,遮挡住弹框的情况(IOS)

小程序首页用了一个video组件,然后在真机测试中,事件弹出的悬浮窗就被这个video覆盖了,因为原生组件的层级太高,用z-index是没有办法解决的。

<video 
  src="{{videoTil}}" 
  id="videoT" 
  controls="{{false}}" 
  show-center-play-btn="{{false}}" 
  autoplay=true 
  loop=true 
   muted=true 
  custom-cache="{{false}}">

</video>

<!--提示浮层-->
<view class="tooltip" wx:if="{{showInfo.suc}}">
  <view class="close" wx:if="{{bind_mobile}}" @tap="close('suc')"></view>
  <view class="tip-text1">领取成功!</view>
  <view class="tip-text2">请到游戏内查看</view>
  <view class="bind-phone" wx:if="{{bind_mobile}}" @tap="bindMobile()"><text>绑定手机领好礼</text></view>
</view>

我们根据小程序官方文档这么进行修改

<!--提示浮层-->
<cover-view class="tooltip" wx:if="{{showInfo.suc}}">
  <cover-view class="close" wx:if="{{bind_mobile}}" @tap="close('suc')">
    <cover-image src="https://ossweb-img.qq.com/images/b20181106/cus-tip-close.png" />
  </cover-view>
  <cover-view class="tip-text1">领取成功!</cover-view>
  <cover-view class="tip-text2">请到游戏内查看</cover-view>
  <cover-view class="bind-phone" wx:if="{{bind_mobile}}" @tap="bindMobile()">
    <cover-image class="text-img" src="https://ossweb-img.qq.com/images/b20181106/cus-icon-gift.png" />
    <cover-view class="text-p">绑定手机领好礼</cover-view>
  </cover-view>
</cover-view>

16.微信小程序输入框内容无法获取的问题

前言

这是一个难以被发现的坑,场景:有时候我们在监听表单输入框内容的时候,会使用bindinput这个方法来进行双向数据即时绑定。在一些输入法中,这会发生十分可怕的事情

部分输入法在输入英文的时候会有一个红框那块的内容,假如你没有点击那块的内容,那么就算输入框表面上看有那个值,程序却无法捕捉到输入框内容变化了,导致了输入框内容没有被写进程序

image

解决方式

解决这个问题很简单,只要遵循开发规范就好了,凡是涉及表单的提交的,都必须采用form+button这种方式进行。

11.微信小程序在工作比较常用到的小demo

1、巧用三目运算

我们在开发中遇到“要么...就...”的逻辑判断,往往会用三目运算做一个简单判断输出,然而当我们没有什么开发经验的时候,遇到“要么...就(要么...就...)...”的问题就会一脸懵逼,甚至写if来做分步判断,其实完全没必要这么做,更简洁的写法如下

{{isCapture==1?'队长':(isCapture==2?'队员':'未加入')}}



2、一个箭头指示效果

结构代码

<view class='demo'>
  <i class="ani-first" decode='true'>{{'>'}}</i><i class="ani-second">{{'>'}}</i>
</view>

样式代码

.demo {
  padding: 5rpx 20rpx;
  background-color: black;
  width: 100rpx;
}
.ani-first {
  opacity: 1;
  animation: ani-first 1s 0s linear infinite;
  color: #fdfff4;
}
.ani-second {
  opacity: 0;
  animation: ani-second 1s 0s linear infinite;
  color: #fdfff4;
}
@keyframes ani-first {
  0% {
    opacity: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes ani-second {
  0% {
    opacity: 0;
  }
  50% {
    opacity: 0;
  }
  60% {
    opacity: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}



3、音乐播放的应用:基于wepy框架,数据绑定有差异(一)

页面结构代码

<view class="music {{playing?'music-active':''}}" bindtap="musicAct"></view>

样式代码

.music {
  width: 50rpx;
  height: 50rpx;
  background-image: url("https://ossweb-img.qq.com/images/huaxia/music-btn-gray.png");
  background-size: 100% 100%;
}
.music-active {
  background-image: url("https://ossweb-img.qq.com/images/huaxia/music-btn.png");
  animation: rotation 3s linear infinite;
  background-size: 100% 100%;
}
@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

脚本代码

Page({

  /**
   * 页面的初始数据
   */
  data: {
    playing: false
  },
  // 播放音乐
  musicAct(){
    this.setData({
      playing: !this.data.playing
    })
    const music = wx.getBackgroundAudioManager()
    music.title = "华夏周年庆"
    music.src = 'https://ossweb-img.qq.com/images/huaxia/music.mp3'
    music.onError(()=>{
      wx.showToast({
        title: '播放加载失败',
      })
    })
    music.onEnded(()=>{
      music.title = "华夏周年庆"
      music.src = 'https://ossweb-img.qq.com/images/huaxia/music.mp3'
    })
    if(this.data.playing){
      music.play()
    } else {
      music.pause()
    }
  }
})

或者是更合理的脚本代码

Page({

  /**
   * 页面的初始数据
   */
  data: {
    playing: false,
    music: null
  },
  // 播放音乐
  musicAct() {
    this.setData({
      playing: !this.data.playing
    })
    if(!this.data.music) {
      this.data.music = wx.getBackgroundAudioManager()
      this.data.music.title = "华夏周年庆"
      this.data.music.src = 'https://ossweb-img.qq.com/images/huaxia/music.mp3'
      this.data.music.onError(() => {
        wx.showToast({
          title: '播放加载失败',
        })
      })
      this.data.music.onEnded(() => {
        this.data.music.title = "华夏周年庆"
        this.data.music.src = 'https://ossweb-img.qq.com/images/huaxia/music.mp3'
      })
    }
    if (this.data.playing) {
      this.data.music.play()
    } else {
      this.data.music.pause()
    }
  }
})

全局app.json配置(requiredBackgroundModes),目的是支持后台播放

{
  "pages": [
    "pages/demo/demo"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#fff",
    "navigationBarTitleText": "WeChat",
    "navigationBarTextStyle": "black"
  },
  "requiredBackgroundModes": ["audio"],
  "sitemapLocation": "sitemap.json"
}



4、视频播放的应用(一)

页面结构代码

<view class="video">
  <video src="{{video}}" id="video"></video>
  <view class="controls" wx:if="{{!isVideoPlay}}">
    <view class="play">
      <view class="play-icon" bindtap="videoPlay"></view>
    </view>
  </view>
</view>

样式代码

.video {
  width: 100%;
  height: 391rpx;
  position: relative;
}
.video video {
  width: 100%;
  height: 100%;
}
.controls {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-image: url("https://ossweb-img.qq.com/images/celebration/audio_bg_new.jpg");
  background-size: 100% 100%;
  z-index: 1000;
}
.play {
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.3);
  box-sizing: border-box;
  text-align: center;
}
.play-icon {
  width: 143rpx;
  height: 143rpx;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
  background-image: url("https://ossweb-img.qq.com/images/b20181106/play.png");
  background-size: 100% 100%;
}

脚本代码

Page({
  /**
   * 页面的初始数据
   */
  data: {
    video: 'https://apd-sochy.apdcdn.tc.qq.com/vcloud1022.tc.qq.com/1022_9b98f5a107e84491b50a03951ca95c2a.f0.mp4?vkey=E70F2BF8EE0EBC1F265EB2D06169C442A1222739468DCD2227AFC63B6B095B10D382F2A882F1769D6BCD88B3FA895284304DD28863E4B9BB8C1B219204F5CE6D6D18F296A82B0A775E1506DF3D2A5DBA8C0A1898CDD3AC4B&sha=0&ocid=600924937',
    isVideoPlay: false,
  },
  // 播放视频
  videoPlay(){
    let videoObj = wx.createVideoContext('video')
    this.setData({
      isVideoPlay: true
    })
    videoObj.play()
  }
})



5、图片轮播与预览

页面结构代码

<view class="photo-swiper" bindtap="preview">
  <swiper current="{{swiperIndex}}" bindchange="swiperChange">
    <swiper-item wx:for="{{photoList}}" wx:key="index">
      <view>
        <image src="{{item}}" mode="aspectFit" />
      </view>
    </swiper-item>
  </swiper>
  <view class="swiper-button-prev" wx:if="{{swiperIndex>0}}" catchtap="swiperAction" data-id="sub"></view>
  <view class="swiper-button-next" wx:if="{{swiperIndex<photoList.length-1}}" catchtap="swiperAction" data-id="add"></view>
</view>

样式代码

.photo-swiper {
  position: relative;
  width: 670rpx;
  height: 450rpx;
  background-image: url(https://ossweb-img.qq.com/images/celebration/stewardBox.png);
  background-size: 100% 100%;
  margin: 20rpx auto;
}
.photo-swiper swiper {
  width: 660rpx;
  height: 390rpx;
}
.photo-swiper swiper view {
  width: 100%;
  height: 100%;
  display: flex;
  justify-content: center;
  margin-top: 40rpx;
}
swiper image {
  height: 100%;
  width: 635rpx;
}
.swiper-button-prev {
  background-image: url("https://ossweb-img.qq.com/images/celebration/stewardleft.png");
  left: 4rpx;
  right: auto;
}
.swiper-button-next, .swiper-button-prev {
  position: absolute;
  top: 50%;
  width: 77rpx;
  height: 150rpx;
  margin-top: -75rpx;
  z-index: 10;
  cursor: pointer;
  background-size: 100% 100%;
  background-position: center;
  background-repeat: no-repeat;
}
.swiper-button-next {
  background-image: url("https://ossweb-img.qq.com/images/celebration/stewardright.png");
  right: 4rpx;
  left: auto;
}

脚本代码

Page({
  /**
   * 页面的初始数据
   */
  data: {
    photoList: [
      'https://static.svip.game.qq.com/cms/file/170459_9572dfala_342e6a7067.jpg',
      'https://static.svip.game.qq.com/cms/file/170459_7974z7yyf_382e6a7067.jpg',
      'https://static.svip.game.qq.com/cms/file/170459_62790mpa3_31342e6a70.jpg'
    ],
    swiperIndex: 1,
  },
  // 图片预览
  preview(e) {
    wx.previewImage({ current: this.data.photoList[this.data.swiperIndex], urls: this.data.photoList });
    console.log(e)
  },
  // 图片轮播
  swiperChange(e) {
    this.setData({
      swiperIndex: e.detail.current
    })
  },
  // 图片左右轮播
  swiperAction(e) {
    if (e.currentTarget.dataset.id == 'add') {
      this.setData({
        swiperIndex: this.data.swiperIndex + 1
      })
    } else {
      this.setData({
        swiperIndex: this.data.swiperIndex - 1
      })
    }
  }
})



6、小程序支持动态更新内联样式

这是十分友好的一个特点,在开发中能够带来很多的便利,请看下面代码自行体会

<block wx:for="{{imgs}}">
  <view style="background-image: url('{{item}}'); height: 300rpx; width: 200rpx"></view>
</block>

js脚本代码

data: {
  imgs: [
    "https://p.ssl.qhimg.com/dmfd/400_300_/t0120b2f23b554b8402.jpg",
    "https://cw1.tw/CW/images/article/201712/article-5a261fb3057e6.jpg",
    "http://farisl.com/wp-content/uploads/2014/07/085626mbP.jpg"
  ]
}

3.scroll-view左右横向滑动效果实现

开发要点

  • 1.scroll-view 中的需要滑动的元素不可以用 float 浮动;
  • 2.scroll-view 中的包裹需要滑动的元素的大盒子用 display:flex; 是没有作用的;
  • 3.scroll-view 中的需要滑动的元素要用 dislay:inline-block; 进行元素的横向编排;
  • 4.包裹 scroll-view 的大盒子有明确的宽和加上样式--> overflow:hidden;white-space:nowrap;

源代码

<view class="scroll_box">
  <scroll-view class="scroll-view_x" scroll-x style="width: auto;overflow:hidden;">
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
    <view class="item_list">
      <view class="item_book_text">测试数据</view>
    </view>
  </scroll-view>
</view>
.scroll_box {
  width: 100%;
  height: 307rpx;
  overflow: hidden;
  padding: 20rpx;
  background: #fff;
  white-space: nowrap;
}

.item_list {
  width: 160rpx;
  height: 100rpx;
  margin-right: 23rpx;
  display: inline-block;
  background-color: green;
}

7.微信小程序开发 scroll-view 实现锚点标记

参考文章

代码

wxml文件

<view class='list'>
  <view bindtap='jumpTo' data-opt="list0">list0</view>
  <view bindtap='jumpTo' data-opt="list11">list11</view>
  <view bindtap='jumpTo' data-opt="list29">list29</view>
</view>
<scroll-view 
  scroll-into-view="{{toView}}" 
  scroll-y="true" 
  scroll-with-animation="true" 
  class="scr">
    <view 
      wx:for="{{list}}" 
      id="{{item}}" 
      wx:key="*this" 
      data-rol="{{item}}" 
      class="test">
      {{item}}
    </view>
</scroll-view>

wxss文件

page {
  height: 100%;
}
.scr {
  position: relative;
  height: 100%;
}
.test {
  height: 80rpx;
}
.list {
  position: fixed;
  z-index: 9;
  top: 30rpx;
  right: 10rpx;
}

js文件

Page({
  data: {
    list: ["list0", "list1", "list2", "list3",  "list4",  "list5",  "list6",  "list7",  "list8",  "list9",  "list10",  "list11",  "list12",  "list13",  "list14",  "list15",  "list16",  "list17",  "list18",  "list19",  "list20",  "list21",  "list22",  "list23",  "list24",  "list25",  "list26",  "list27",  "list28",  "list29"],
    toView:   'eeede'
  },

  onLoad: function() {

  },
  jumpTo: function (e) {
    // 获取标签元素上自定义的 data-opt 属性的值
    let target = e.currentTarget.dataset.opt;
    this.setData({
      toView: target
    })
  },
  onShareAppMessage: function() {

  }
})

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.