资料
  • 资料
  • 专题
[15章]深入学习小程序框架底层原理,培养双线程思维
推荐星级:
类别: 软件/EDA/IP
时间:2023-12-18
大小:3.45KB
阅读数:584
上传用户:学习菜鸟小弟弟
查看他发布的资源
下载次数
13
所需E币
0
ebi
新用户注册即送 300 E币
更多E币赚取方法,请查看
close
资料介绍
前端高手特训 从0到1带你手写一个微信小程序底层框架,小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用。也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载。

框架 管理了整个小程序的页面路由,可以做到页面间的无缝切换,并给以页面完整的生命周期。开发者需要做的只是将页面的数据、方法、生命周期函数注册到 框架 中,其他的一切复杂的操作都交由 框架 处理。

wepy支持类似Vue的组件化开发,可以将页面拆分成多个独立的组件,提高代码复用性和开发效率。下面我们通过一个实际的案例来说明组件化开发在wepy中的应用。假设我们有一个小程序项目,其中包含一个商品列表页面和一个商品详情页面。我们可以将商品列表和商品详情抽象成两个组件,并在需要的地方引用它们。首先,我们创建一个名为GoodsList的组件。在src/components目录下创建GoodsList.wpy文件,并编写如下代码:
import axios from 'axios'
const defaultConfig = {
  timeout: 5000,
  baseURL: '/release/'
}
const axiosInstance = axios.create(defaultConfig)
// 添加请求拦截器
axiosInstance.interceptors.request.use(config => {
  return config
}, (err) => {
  // 对请求错误做些什么
  return Promise.reject(err)
})

// 请求拦截器,内部根据返回值,重新组装,统一管理。
axiosInstance.interceptors.response.use(res => {
  console.log('接口详情:',res)
  return res
})

export default {
  // 封装get
  httpGet(url: any, params = {}) {
    return axiosInstance.get(url, { params }).then(res => res.data).catch()
  },
  // 封装post
  httpPost(url: any, params = {}) {
    return axiosInstance.get(url, { params }).then(res => res.data).catch()
  }
}
封装一个openStore(),使用indexedDB.open()方法返回一个 IDBRequest对象,接着将这个对象上的三个事件分别放置进入:onsuccess、onerror、onupgradeneeded。

onsuccess表示打开数据库成功的事件。
onerror表示打开数据库失败的事件。
onupgradeneeded是数据库升级事件,如果版本号更新,并且大于之前的版本号则进行数据库升级,该事件回调里面,会创建我们所需要的对象仓库,类似于关系型数据库中的表的概念。
export default class DB {
  private dbName: string // 数据库名称
  constructor(dbName: string) {
    this.dbName = dbName
  }

  // 打开数据库
  public openStore(storeName: string, keyPath: string, indexs?: Array<string>) {
    const request = window.indexedDB.open(this.dbName, 2)
    request.onsuccess = (event) => {
      console.log('数据库打开成功')
      console.log(event)
    }
    request.onerror = (event) => {
      console.log('数据库打开失败')
      console.log(event)
    }
    request.onupgradeneeded = (event) => {
      console.log('数据库升级成功')
      const { result }: any = event.target
      const store = result.createObjectStore(storeName, { autoIncrement: true, keyPath })
      if (indexs && indexs.length > 0) {
        indexs.map((v: string) => {
          store.createIndex(v, v, { unique: true })
        })
      }
      store.transaction.oncomplete = (event: any) => {
        console.log('创建对象仓库成功')
      }
      console.log(event)
    }
  }
}

在子组件 headerCommon.vue中切换语言时,调用 saveLanguageApi接口,保存当前语言环境到 indexedDB中,并将当前语言包 zhCn或者 en作为参数传递给父组件 App.vue,代码片段如下:
// commonHeader.vue

function handleSelect(e: any) {
  if (e === 'zh') {
    emit('changeLang', zhCn)
    saveLanguage('zh')
  } else if (e === 'en') {
    emit('changeLang', en)
    saveLanguage('en')
  }
  console.log(e)
}

// Mock接口:保存当前语言环境
function saveLanguage(language: any) {
  saveLanguageApi(language).then(res => {
    const { success } = res
    if (success) {
      console.log('保存当前语言包成功')
    }
  })
}
通过调用 getLanguage接口获取到之前调用存储在 indexedDB中的语言环境,然后赋值给全局组件,代码片段如下:
// headerCommon.vue
// Mock接口:保存当前语言环境
function getLanguage() {
  fetchLanguageApi().then(res => {
    const { success, result } = res
    const { name } = result
    if (success) {
      if (name === 'zh') {
        emit('changeLang', zhCn)
      } else if (name === 'en') {
        emit('changeLang', en)
      }
      console.log('获取当前语言环境成功')
    }
  })
}
getLanguage()
使用@include 指令来引入定义好的样式函数,该函数的三个参数可以根据传入的值来对 flex布局进行自定义,默认值为:column、center、right,在 footerCommon.scss中我们重新自定义了该样式函数,分别传入 row、space-between、flex-start,代码片段如下:
// footerCommon.scss
.common-footer{
   border-top: 1px solid rgb(235, 235, 235);
  .footer{
    @include main-wrapper;
    @include layout(row,space-between,flex-start);
    padding: 20px 0;
    li{
      @include layout;
      h4{
        font-weight: bold;
      }
      a{
        margin-bottom: 10px;
        color: rgb(72, 72, 72);
        text-decoration: none;
        &:hover{
          text-decoration:underline;
        }
      }
    }
  }
}
订单中心模块会使用到的两个 Mock接口为 saveOrderApi、fetchOrderApi,一个是立即预定,另一个是查询订单列表,具体代码片段如下
// src/api/order/index.ts

const storeName = Object.keys(airbnb.orderObjectStore)[0]

// Mock接口:立即预定
export async function saveOrderApi(params: any) {
  const loading = ElLoading.service({
    lock: true,
    background: 'rgba(0, 0, 0, 0.1)'
  })

  // 是否存在相同订单Id
  const hasOrderId = await new Promise((resolve, reject) => {
    airbnb.airbnbDB.getList(storeName).then((res: any) => {
      setTimeout(() => {
        loading.close()
      }, 200)
      res && res.filter((item: any) => {
        if (item.orderId === params.orderId) { // 存在相同订单Id
          resolve(true)
        }
      })
      resolve(false)
    })
  })
  let result: IResultOr
  if (hasOrderId) {
    result = await new Promise((resolve, reject) => {
      resolve({ code: '000001', success: false, message: '数据已存在', result: null })
    })
  } else {
    result = await new Promise((resolve, reject) => {
      airbnb.airbnbDB.updateItem(storeName, params).then(res => {
        setTimeout(() => {
          loading.close()
        }, 200)
        resolve({ code: '000000', success: true, message: '操作成功', result: null })
      })
    })
  }
  return result
}
通过应用这些进阶技巧和最佳实践,可以进一步提升小程序的性能和开发效率,同时优化代码质量,为用户提供更好的使用体验。

版权说明:本资料由用户提供并上传,仅用于学习交流;若内容存在侵权,请进行举报,或 联系我们 删除。
相关评论 (下载后评价送E币 我要评论)
没有更多评论了
  • 可能感兴趣
  • 关注本资料的网友还下载了
  • 技术白皮书