[15章]深入学习小程序框架底层原理,培养双线程思维

giadnbhaytgw · · 828 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。
前端高手特训 从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 } 通过应用这些进阶技巧和最佳实践,可以进一步提升小程序的性能和开发效率,同时优化代码质量,为用户提供更好的使用体验。 ![1.png](http://static.itsharecircle.com/231218/8a25ee4c256b2635f57d9933d74f8c23.png)
828 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传