Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

微信小程序相关 #71

Open
xccjk opened this issue Mar 17, 2022 · 7 comments
Open

微信小程序相关 #71

xccjk opened this issue Mar 17, 2022 · 7 comments

Comments

@xccjk
Copy link
Owner

xccjk commented Mar 17, 2022

video标签背景色

想比很多人都想修改video的那个黑色背景吧,还是别做梦了,还不支持哈。

官方针对video背景色解读

@xccjk
Copy link
Owner Author

xccjk commented Mar 17, 2022

微信小程序 swiper禁止手动切换

给swiper设置catchtouchmove为true,设置swiper-item的catchtouchmove返回false

<swiper
  class="swiper"
  indicator-dots="{{false}}"
  circular
  autoplay="{{true}}"
  vertical="{{true}}"
  interval="{{3000}}" 
  duration="{{300}}"
  easing-function="easeInOutCubic"
  catchtouchmove="true"
>
  <block wx:for="{{list}}" wx:key="index">
    <swiper-item catchtouchmove="stopChange">
      <view class="swiper-item">{{item.name}}</view>
    </swiper-item>
  </block>
</swiper>

stopChange() {
  return false
}

@xccjk
Copy link
Owner Author

xccjk commented Mar 17, 2022

微信小程序多音频场景处理

背景:页面中有多条数据,每条数据都可以单独播放,不同时播放

核心逻辑就是每个音频单独初始化一个方法,每个音频播放的进度等信息都单独控制

通过wx.createInnerAudioContext来控制

// wxml
<view wx:for="{{list}}" wx:key="id">
  <view play="{{play}}" url="{{item.url}}" id="{{item.id}}">播放</view>
</view>

// js
Component({
  data: {
    play: false,
    list: [
      { id: 1, url: '' },
      { id: 2, url: '' },
      { id: 3, url: '' },
    ],
    id: null,
  },
  onLoad: function () {},
  onShow() {},
  onHide() {
    this.audioPause();
  },
  onUnload() {
    this.audioPause();
  },
  handleAudioPlay(e) {
    const { play, url, id } = e.detail;
    if (!this[`innerAudioContext${id}`]) {
      this[`innerAudioContext${id}`] = wx.createInnerAudioContext();
    }
    if (play) {
      this[`innerAudioContext${id}`].pause();
    } else {
      this[`innerAudioContext${id}`].autoplay = true;
      this[`innerAudioContext${id}`].src = url;
      this[`innerAudioContext${id}`].play();
    }

    this.setData({
      play: !play,
      id,
    });
    this.innerAudioContext.onEnded(() => {
      this.setData({
        play: false,
      });
    });
  },
  audioPause() {
    const { id } = this.data;
    this[`innerAudioContext${id}`].pause();
    this.setData({
      play: false,
    });
  },
});

当采用这个方法时,还有三种常见的场景需要考虑:

  1. 页面返回键退出当前页面
  2. 右上角退出小程序
  3. 手机home键将小程序切换到后台

为什么需要考虑这三种情况呢,因为一般小程序退出当前页面或者切换到后台,需要停止当前播放的音乐

当通过返回键退出当前页面(或者点击页面跳转到其它页面),一般直接销毁音频初始化方法即可:

handlerBack() {
  router.back()
  const { id } = this.data
  if (this[`innerAudioContext${id}`]) {
    this[`innerAudioContext${id}`]. destroy()
  }
}

右上角退出小程序

onUnload() {
  const { id } = this.data
  if (this[`innerAudioContext${id}`]) {
    this[`innerAudioContext${id}`]. pause()
  }
}

当按home键切换到后台时:

onHide() {
  const { id } = this.data
  if (this[`innerAudioContext${id}`]) {
   this[`innerAudioContext${id}`]. pause()
  }
}

当前音频是单独播放,只是针对每个音频初始化一个实例,假如需要同时播放多个音频,这种方式可能会导致内存不足导致的崩溃

@xccjk
Copy link
Owner Author

xccjk commented Mar 17, 2022

微信小程序多音频场景处理 - 背景音频

提到音频播放控制,不得不提背景音频这个方法wx.getBackgroundAudioManager

很不幸,这个有坑。当使用场景为单音频播放或者不需要记录每个音频播放的位置时,使用它是一个合适的选择。当需要记录每个音频的播放位置时,这个就会有些问题了。问题来源backgroundAudioManager.seek这个API

重要的事情说3遍:backgroundAudioManager.seek在模拟器上正常,但是在真机上不生效,每次都会重新播
重要的事情说3遍:backgroundAudioManager.seek在模拟器上正常,但是在真机上不生效,每次都会重新播
重要的事情说3遍:backgroundAudioManager.seek在模拟器上正常,但是在真机上不生效,每次都会重新播

Component({
  data: {
    play: false,
    list: [
      { id: 1, url: '' },
      { id: 2, url: '' },
      { id: 3, url: '' },
    ],
    duration: {},
    id: null,
  },
  onLoad() {},
  onShow() {},
  onHide() {},
  onUnload() { },
  play() {
    wx.nextTick(() => {
      const { duration = {} } = this.data;
      const currentTime = duration[id] || 0;
      backgroundAudioManager.title = '每日快讯';
      backgroundAudioManager.epname = '';
      backgroundAudioManager.singer = '';
      backgroundAudioManager.coverImgUrl = '';
      backgroundAudioManager.src = url;
      if (currentTime) {
        // 跳转到指定的进度
        backgroundAudioManager.seek(currentTime);
        backgroundAudioManager.play();
      }
    });
  },
  handleAudioPlay(e) {
    const { play, url, id } = e.detail;
    const backgroundAudioManager = wx.getBackgroundAudioManager();
    if (play) {
      backgroundAudioManager.pause();
      // 记录当前音频播放的进度
      wx.getBackgroundAudioPlayerState({
        success(res) {
          const { currentPosition } = res;
          that.setData({
            duration: {
              ...duration,
              [id]: currentPosition,
            },
          });
        },
      });
      // 点击的不是当前播放的音频
      if (this.data.id !== id) {
        this.play()
      }
    } else {
      this.play()
    }
    this.setData({
      play: !play,
      id,
    }),
  },
});

@xccjk
Copy link
Owner Author

xccjk commented Mar 17, 2022

自定义字体在Android端不生效的问题

@xccjk
Copy link
Owner Author

xccjk commented Apr 1, 2022

微信小程序警告 [Component] property received type-uncompatible value: expected but get null value. Used empty string instead

问题产生原因:子组件properties中定义的字段类型不满足导致相关警告

比如定义组件中src属性为String类型时,当src传入null时,就会有上述警告出现

// imagex
Component({
  options: {},
  externalClasses: ['class'],
  properties: {
    src: String,
  },
  data: {
    loaded: false,
  },
  lifetimes: {
    attached() {},
  },
  methods: {},
});

使用

<imagex src="{{null}}" />

@xccjk
Copy link
Owner Author

xccjk commented Jan 5, 2023

微信小程序-基于node实现自动打包上传代码

在平时的小程序开发过程中,可能会遇到下面这些小问题,虽然不影响开发过程,但是开发体验确会差一点,具体如下:

  • 每次在编辑器中运行构建命令,第一次还需要手动打开微信开发者工具,打开指定项目
  • 每次准备发布体验版时,需要先在本地打包,等待打包完成,在开发者工具中点击上传代码

那么怎么避免重复的操作,特别是比较频繁的发布场景,可能每天需要多次的等待及上传操作。

对于问题1,相信很多人想的,就是每次输入命令时,微信开发者工具可以自动打开,并且可以打开当前指定的项目;对于问题2,每次输入构建发布命令时,先执行打包操作,然后自动执行上传操作,不需要人为等待打包结束已经人为点击发布按钮。

实现一个自动上传功能

miniprogram-ci

官方发布的cli命令,不需要开发者工具,进行小程序代码的上传、预览等操作等。网上这方面的文档挺多的,不细说。

采用这个方法的,需要提供小程序的秘钥与设置IP白名单,可能会存在一定的风险,比较适用于有独立的打包发布平台,在指定机器上进行打包操作

nodejs实现自动上传

其实,通过nodejs写的脚本或者shell之类的,可以快速实现自动上传的效果。核心原理就是通过child_process开启一个多进程,在执行完打包命令后,运行官方提供的命令行V2,常见的API如下:

// 登录
cli login
// 预览
cli preview
// 上传
cli upload
// 启动开发者工具
cli open

相比miniprogram-ci,使用脚本的方式实现时,会依赖开发者工具,当微信开发者工具未登录时,运行自动上传命令会报错,因此也添加了判断未登录时,会在命令行中生成二维码,扫码登录即可。

同时,采用child_process不依赖任何三方包,每个人的电脑只要安装node环境与微信开发者工具就行了

具体实现如下:

// upload.js
#!/usr/bin/env

const child = require('child_process');
const exec = child.execSync;

function getDays() {
  const date = new Date();

  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const strDate = date.getDate();
  const hours = date.getHours();
  const minutes = date.getMinutes();

  return `在${year}${month}${strDate}${hours}${minutes}分提交上传`;
}

function getName() {
  const arr = process.cwd().split('/');
  return arr[2];
}

const branch = child.execSync('git name-rev --name-only HEAD', { encoding: 'utf8' });

const config = {
  path: `/Applications/wechatwebdevtools.app/Contents/MacOS/cli`,
  projectPath: `${process.cwd()}/dist`,
  version: `1.2.1`,
  desc: `${getName()}${getDays()},发布分支${branch}`,
};

exec('npm run build', { stdio: 'inherit' });

child.exec(
  `${config.path} upload --project ${config.projectPath} -v ${config.version} -d ${config.desc}`,
  { stdio: 'inherit' },
  (err, res) => {
    if (res) {
      exec(`${config.path} login --qr-size small`, { stdio: 'inherit' });
      exec(
        `${config.path} upload --project ${config.projectPath} -v ${config.version} -d ${config.desc}`,
        { stdio: 'inherit' }
      );
    }
  }
);
// package.json
"scripts": {
  "upload": "node upload.js"
}

使用shell的方式实现自动上传

对于前端来说,平时写shell可能不是特别多,但是它真的可以解决非常多的问题,非常的便捷。

平时写shell,一般分两种,直接写shell,或者用三方包来写,比较知名的有shelljszx。对于shelljs,其实是对child_process做了一层封装,保证了多端语法一致性。而zx是Google出品的,语法更贴合前端。我们本次就是采用zx来实现。

// 全局安装zx
sudo npm install -g zx

具体实现如下:

// upload.mjs
#!/usr/bin/env zx

function getDays() {
  const date = new Date();

  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const strDate = date.getDate();
  const hours = date.getHours();
  const minutes = date.getMinutes();

  return `在${year}${month}${strDate}${hours}${minutes}分 提交上传`;
}

const branch = await $`git branch --show-current`;

const config = {
  path: `/Applications/wechatwebdevtools.app/Contents/MacOS/cli`,
  projectPath: `${process.cwd()}/dist`,
  version: `1.2.1`,
  desc: `${getDays()},发布分支${branch}`,
};

await $`npm run build`;

await $`${config.path} upload --project ${config.projectPath} -v ${config.version} -d ${config.desc}`;
// package.json
"scripts": {
  "upload": "zx upload.mjs"
}

自动打开开发者工具

// open.js
#!/usr/bin/env

const child = require('child_process');
const exec = child.execSync;

const path = '/Applications/wechatwebdevtools.app/Contents/MacOS/cli';
const projectPath = `${process.cwd()}/dist`;

child.exec('git branch --show-current', (err, res) => {
  console.log('当前分支:', res);
});

child.exec(`${path} open --project ${projectPath}`, (err, res) => {
  if (res) {
    exec(`${path} login --qr-size small`, { stdio: 'inherit' });
    exec(`${path} open --project ${projectPath}`, { stdio: 'inherit' });
    exec('npm run dev', { stdio: 'inherit' });
  } else {
    exec('npm run dev', { stdio: 'inherit' });
  }
});
// package.json
"scripts": {
  "open": "node open.js"
}

@xccjk xccjk changed the title 微信小程序相关问题 微信小程序相关 Jan 5, 2023
@xccjk
Copy link
Owner Author

xccjk commented Mar 15, 2024

微信小程序 图片预览,关闭预览会触发onShow生命周期

很多情况下在onShow生命周期进行接口请求,并且请求时设置了loading,在关闭预览时会出现loading动画

解决方案:

设置标识符,标记打开了预览弹窗

class App extends Component {
  constructor(props) {
    super(props);
    this.onShow = false
  }

  async componentDidShow() {
    if (this.onShow) {
      this.onShow = false;
      return;
    }
    await fn();
  }

  showModal = () => {
    this.onShow = true;
    wx.previewImage({});
  };
  ...
}

export default App;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant