Bootstrap

微信小程序 Skyline Worklet ios Andorid 项目实战

微信小程序 最新推出的Skyline渲染以及打包ios、andorid查看各个技术平台很少有详细介绍与项目案例,下面是一个简单的壁纸项目开发实战案例,涵盖了从项目创建到功能实现的整个过程。

项目概述

我们开发的是一个小程序手机、平板、pc端壁纸项目。用户可以点赞、收藏、下载壁纸。虽然项目很简单,但项目中我们会涉及多语言、主题外观、适配ios andorid、手势系统、自定义tabbar、自定义appbar、复杂组件开发测试、自定义路由、 元素共享动画、以及一些算法如:发布订阅、线性插值、矩形插值等高阶内容。

项目初始化

首先你需要拥有微信小程序AppID,以及下载微信开发者工具,再打开微信开发者工具创建一个不使用微信云以及官方JS-基础模版的小程序,这里我们就不再细聊,我们默认用户拥有一定开发基础。

编译项目后能正常运行。接下来需要配置Skline,打开app.json配置文件,添加如下配置。

 "renderer": "skyline",
  "componentFramework": "glass-easel",
  "rendererOptions": {
    "skyline": {
      "defaultDisplayBlock": true,
      "defaultContentBox": true
    }
  },

再点击微信开发者工具右侧详情-本地设置勾选开启Skyline渲染调试,以及将JS编译成ES5。当然如果你还需要真机调试,需要在真机下点击小程序胶囊-开发调试-Siwtch Render  选择Skline

创建项目配置skyline

获取微信小程序基本布局信息以及系统基本信息

打开 app.js文件先删除部分内容只留下基本的框架 留下如下代码        

App({
  onLaunch() {
    this.globalData = {
      appName: '多时壁纸', // app名称
      windowInfo: null, // 设备布局与APP基础信息
    }
  }
})

获取基本信息

    // 获取窗口信息
    const windowInfo = wx.getWindowInfo()
    // 获取设备基础信息
    windowInfo.deviceInfo = wx.getDeviceInfo()
    // 获取菜单按钮(右上角胶囊按钮)的布局位置信息。坐标信息以屏幕左上角为原点。
    windowInfo.clientRect = wx.getMenuButtonBoundingClientRect()
    // APP基础信息
    windowInfo.appBase = wx.getAppBaseInfo()
    // 计算appbar高度
    windowInfo.appbarHeight = windowInfo.clientRect.bottom + windowInfo.clientRect.top - windowInfo.statusBarHeight
    // 计算胶囊边距
    windowInfo.padding = windowInfo.windowWidth - windowInfo.clientRect.right
    // 计算头部导行高度
    windowInfo.headerHeight = windowInfo.appbarHeight - windowInfo.statusBarHeight
    // 设备宽高比例
    windowInfo.ratio = windowInfo.screenWidth / windowInfo.screenHeight
    // 加入全局数据
    this.globalData.windowInfo = windowInfo

获取设备信息

自定义tabbar

我们还是先删除掉没用的页面以及内容和utils文件夹子下utils.js里面的全部内容。删除pages文件夹下的全部文件夹,以及删除app.json下pages下的配置。再再pages文件夹下创建四个文件夹分别是:index、classify、seeker、mine。 注意我们在这四个文件下创建的是组件components而不是页面page,app.jaon中pages[]和普通的配置一样。

现在文件目录应该是这个样子的,而四个页面index.js内容是如下代码:

const app = getApp()
Component({
  behaviors: [],
  properties: {},
  observers: {},
  data: {},
  lifetimes: {
    created: function () {},
    attached: function () {
    },
    ready: function () {},
    detached: function () {}
  },
  pageLifetimes: {
    show: function () {},
    hide: function () {}
  },
  methods: {}
})

pages文件夹下index.json配置如下,四个都一样哈。

{
  "navigationStyle": "custom",
  "navigationBarTextStyle": "black",
  "disableScroll": true,
  "componentFramework": "glass-easel",
  "renderer": "skyline",
  "component": true,
  "usingComponents": {}
}

好了现在对应的tabbap四个页面都创建完成,自己为每个页面添加个背景色,一会切换测试看得清楚些。        

在根目录下创建存放静态资源的status文件夹, 图片请下载原码。再在根目录下创建一个custom-tab-bar文件夹以及在文件下创建index组件。这就是我们需要自定义的tabbar布局组件。当然你还是需要配置一下app.json 下的 tabBar。

 "tabBar": {
    "custom": true,
    "list": [
      {
        "pagePath": "pages/index/index"
      },
      {
        "pagePath": "pages/classify/index"
      },
      {
        "pagePath": "pages/seeker/index"
      },
      {
        "pagePath": "pages/mine/index"
      }
    ]
  }

开始编写自定义tabbar:

const { runOnJS, shared, timing, Easing, spring, sequence } = wx.worklet
const app = getApp()
const wininfo = app.globalData.windowInfo // 基础信息
Component({
  options: {
    addGlobalClass: true // 使用全局样式
  },
  lifetimes: {
    attached: function () {
      // wx.worklet.shared用于跨线程共享数据和驱动动画数据
      // Y抽偏移距离
      this._offsetY = shared(100)
      // 主题颜色
      this._backgroundColor1 = shared(app.globalData.theme === 'light' ? '#f4e2d8a6' : 'rgba(0,0,0,0.3)')
      this._backgroundColor2 = shared(app.globalData.theme === 'light' ? '#f4e2d82d' : 'rgba(0,0,0,0.3)')
      // 获取组件节点更新属性
      this.applyAnimatedStyle('#tabbar', () => {
        'worklet'
        return {
          transform: `translateY(${this._offsetY.value}px)`,
          background: `linear-gradient(145deg, ${this._backgroundColor1.value}, ${this._backgroundColor2.value})`
        }
      })
    },
  },

  ready() {
    this._offsetY.value = spring(0)
  },

  data: {
    index: 0,
    list: [
      '../static/index',
      '../static/classify',
      '../static/seeker',
      '../static/mine'
    ]
  },

  methods: {
    // 显示隐藏
    onShowHide(bool = true, defaultNumber = 0, hideNumber = 100) {
      if (bool) this._offsetY.value = spring(defaultNumber)
      else this._offsetY.value = spring(hideNumber)
    },

    // 切换背景颜色
    switchBackgroundColor(theme = app.globalData.theme) {
      if (theme === 'light') {
        this._backgroundColor1.value = '#f4e2d8a6'
        this._backgroundColor2.value = '#f4e2d8a6'
      } else {
        this._backgroundColor1.value = 'rgba(0,0,0,0.3)'
        this._backgroundColor2.value = 'rgba(0,0,0,0.3)'
      }
    },

    // 根据下标获取相应的页面
    currentIndexGetPage(index) {
      switch (index) {
        case 0:
          return '/pages/index/index'
        case 1:
          return '/pages/classify/index'
        case 2:
          return '/pages/seeker/index'
        case 3:
          return '/pages/mine/index'
        default:
          return '/pages/index/index'
      }
    },

    // 切换页面
    switchTab(e) {
      // 重复中一个同一个tabbar处理
      if (this.data.index === e.currentTarget.dataset.index) {
        // 当不是探索直接返回
        if (e.currentTarget.dataset.index !== 2) return
        // 当在探索时发布下载事件
        const eventChannel = this.getOpenerEventChannel()
        if (!eventChannel) return
        eventChannel.emit('download', { index: e.currentTarget.dataset.index })
      }
      // 当前点击下标
      const index = +e.currentTarget.dataset.index
      // 根据下标选择路由路径
      let url = this.currentIndexGetPage(index)
      // 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面
      wx.switchTab({
        url: `${url}?index=${index}`, // 路由路径
        routeType: 'wx://cupertino-modal', // 路由类型
        success: () => {
          this.setData({ index }, () => {
            // 短时间的振动
            wx.vibrateShort({ type: 'medium' })
            // tabbar在探索Y抽移动负40像素
            if (index === 2) this._offsetY.value = spring(-40)
            // 默认移动0
            else this._offsetY.value = spring(0)
          })
        }
      })
    }
  }
})

<view id="tabbar">
  <view wx:for="{{list}}" wx:for-index="i" wx:key="*this" bind:tap="switchTab" data-index="{{i}}">
    <image src="{{item}}{{index == i? 1: 0}}.svg"/>
  </view>
</view>
#tabbar {
  width: 600rpx;
  height: 100rpx;
  position: absolute;
  left: 75rpx;
  border-radius: 30rpx;
  pointer-events: auto;
  bottom: calc(env(safe-area-inset-bottom) + 8px);
  backdrop-filter: blur(10rpx);
  display: flex;
  align-items: center;
}

#tabbar>view {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 1;
  height: 100%;
}

#tabbar>view>image {
  width: 50rpx;
  height: 50rpx;
}

自定义tabbat

;