EP-WachatApp/lib/SPage.js

345 lines
8.9 KiB
JavaScript
Raw Permalink Normal View History

2023-03-24 11:17:57 +08:00
// 引入事件模块 https://github.com/GravityC/SPage
const SEvent = require('SEvent.js')
wx.$event = {
on(eventName, handler) {
return SEvent.getEvent(eventName).on(handler)
},
once(eventName, handler) {
SEvent.getEvent(eventName).once(handler)
},
emit(eventName) {
const args = Array.from(arguments).slice(1)
SEvent.getEvent(eventName).emit(...args)
},
off(nameOrId, handler) {
if(handler && typeof (handler) === 'function'){
SEvent.getEvent(nameOrId).off(handler)
}else{
SEvent.off(nameOrId)
}
},
remove(eventName) {
SEvent.removeEvent(eventName)
}
}
// 引入request模块
const SRequest = require('SRequest.js')
const $http = new SRequest()
wx.$http = $http
wx.$request = $http.request.bind($http)
wx.$get = $http.get.bind($http)
wx.$post = $http.post.bind($http)
wx.$put = $http.put.bind($http)
wx.$delete = $http.delete.bind($http)
/* ----------------------------------------------------------------------------- */
wx.$pages = {}
// 获取当前页面实例
wx.$getCurPage = function() {
return getCurrentPages()[getCurrentPages().length - 1]
}
// 获取当前页面实例对应的页面名
wx.$getCurPageName = function() {
return wx.$getCurPage().$name
}
// $place与$take,$take调用完即删除引用
let channel = {}
wx.$place = function(id, value) {
channel[id] = value
}
wx.$take = function(id) {
const v = channel[id]
channel[id] = null
return v
}
/**
* 封装wx.navigateTo
* @url {string} - 跳转路径
* @query {object} - 携带参数
*/
wx.$route = function(url, query) {
const page = getPage(url)
query = query || {}
query.from = wx.$getCurPageName() // Page || Component
// 若page已加载可调用onNavigate方法
if (page && page.onNavigate) {
page.onNavigate(query)
}
url = url + '?' + parseQuery(query)
wx.navigateTo({
url
})
}
// -----------------------------以下是工具函数----------------------
//装饰器
//@afterOrigin {Boolean} - true:装饰函数在原函数之后触发
const decorator = function(originFn, decorateFn, afterOrigin) {
const origin = originFn
originFn = function(args) {
if (afterOrigin) {
if (origin) origin.call(this, args)
decorateFn.call(this, args)
} else {
decorateFn.call(this, args)
if (origin) origin.call(this, args)
}
}
return originFn
}
// 解析query对象成string
const parseQuery = function(query) {
return Object.keys(query).map(k => `${k}=${query[k]}`).join('&')
}
// 从url中得到pageName
const getPageName = function(url) {
url = url.includes('?') ? url.split('?')[0] : url
const arr = url.split('/')
return arr[arr.length - 1]
}
/**
* @str - pageName或者url
*/
const getPage = function(str) {
const name = str.includes('/') ? getPageName(str) : str
return wx.$pages[name]
}
// 判断是否是空对象
const isEmpty = function(obj) {
return !Object.keys(obj).length
}
/**
* 扩展computed计算属性
*/
const extendComputed = function(option) {
let page
// 为$setData方法响应computed
option.$setData = function(obj) {
this.setData(obj)
page = this // 绑定page实例
const needUpdate = calcComputed() // 将需要改变的computed属性添加到接下来要setData的对象中
if (!isEmpty(needUpdate)) {
this.setData(needUpdate)
}
}
const computed = option.computed || {}
const computedKeys = Object.keys(computed)
let computedCache = {}
// 计算需更改的计算属性
const calcComputed = function(isInit) {
const needUpdate = {}
const that = isInit ? option : page
for (const key of computedKeys) {
const value = computed[key].call(that)
if (value !== computedCache[key]) needUpdate[key] = computedCache[key] = value
if (isInit) option.data[key] = needUpdate[key] // 初始化操作
}
return needUpdate
}
// 页面unload时清空computedCache
option.onUnload = decorator(option.onUnload, function() {
computedCache = {}
})
calcComputed(true);
}
/**
* 为所有Page和Component扩展方法
*/
const extendFunctions = function(option) {
option.$route = wx.$route
option.$place = wx.$place
option.$take = wx.$take
// 封装wx.request
option.$request = wx.$request
option.$get = wx.$get
option.$post = wx.$post
option.$put = wx.$put
option.$delete = wx.$delete
// 事件机制
option.$on = function(eventName, handler){
this.$listeners = this.$listeners || []
this.$listeners.push(wx.$event.on(eventName, handler))
}
option.$once = wx.$event.once
option.$emit = wx.$event.emit
option.$off = wx.$event.off
option.$remove = wx.$event.remove
}
/**
* -------------扩展App-------------------
*/
let initPageObject
let initCompObject
const extendApp = function() {
const originApp = App
App = function(option) {
if (option.$mixinP) {
initPageObject = option.$mixinP
}
if (option.$mixinC) {
initCompObject = option.$mixinC
}
originApp(option)
}
}
/**
* -------------扩展Page----------------
*/
const extendPage = function() {
const originPage = Page
Page = function(option) {
// 混合app.$mixinP
if (initPageObject) {
const hooks = ['onLoad', 'onShow', 'onReady', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll', 'onResize', 'onTabItemTap']
for (const k in initPageObject) {
if (hooks.includes(k)) {
option[k] = decorator(option[k], initPageObject[k])
} else if (k === 'data') {
option.data = Object.assign({}, initPageObject.data, option.data)
} else if (!option.hasOwnProperty(k)) {
option[k] = initPageObject[k]
}
}
}
// 若定义了$name, 则添加到wx.$pages中
if (option.$name) {
wx.$pages[option.$name] = option
} else {
option.$name = 'unKnow' //此处强行给$name赋值为了后续区分是Page还是Component
}
// 添加$status属性
option.$status = {
isFirstShow: true
}
// 是否已执行过onNavigate函数
option.$$isNavigated = false
// 扩展computed属性
extendComputed(option)
// 扩展方法
extendFunctions(option)
// 装饰onNavigate
option.onNavigate = decorator(option.onNavigate, function(query) {
option.$$isNavigated = true
})
// 装饰onLoad
option.onLoad = decorator(option.onLoad, function(query) {
// 若页面有onNavigate方法但还没运行则运行onNavigate方法
if (option.onNavigate && !option.$$isNavigated) {
option.onNavigate(query)
}
})
// 装饰onShow
option.onShow = decorator(option.onShow, function() {
this.$status.isFirstShow = false
}, true)
// 隐藏页面时隐藏标题栏加载动画坑爹的微信官方bug
option.onHide = decorator(option.onHide, function() {
wx.hideNavigationBarLoading()
})
// 装饰onUnload
option.onUnload = decorator(option.onUnload, function(){
// 卸载本页面的监听器
if (this.$listeners && this.$listeners.length) {
for (const id of this.$listeners) {
wx.$event.off(id)
}
}
})
//原生Page构造
originPage(option)
}
}
/**
* --------------------------------------------扩展Component
*/
const extendComponent = function() {
const originComponent = Component
Component = function(option) {
option.methods = option.methods || {}
// 混合app.$mixinC
if (initCompObject) {
const mixinObj = ['properties', 'data', 'observers', 'methods', 'options']
for (const k in initCompObject) {
if (k === 'lifetimes' || k === 'pageLifetimes') {
if (!option[k]) {
option[k] = initCompObject[k]
} else {
for (const h in initCompObject[k]) {
option[k][h] = decorator(option[k][h], initCompObject[k][h])
}
}
} else if (mixinObj.includes(k)) {
option[k] = Object.assign({}, initCompObject[k], option[k])
} else if (!option.hasOwnProperty(k)) {
option[k] = initCompObject[k]
}
}
}
// 扩展computed属性
extendComputed(option)
// 扩展方法
extendFunctions(option.methods)
option.lifetimes = option.lifetimes || {}
// 装饰detached
option.lifetimes.detached = decorator(option.lifetimes.detached, function () {
// 卸载本组件的监听器
if (this.$listeners && this.$listeners.length) {
for (const id of this.$listeners) {
wx.$event.off(id)
}
}
})
// 获取当前页面实例
option.methods.$getCurPage = wx.$getCurPage
// 获取当前页面实例对应的页面名
option.methods.$getCurPageName = wx.$getCurPageName
// 重新定义$setData便于扩展其他功能
const originData = option.$setData
option.methods.$setData = function(obj) {
return originData.call(this, obj)
}
//原生Component构造
originComponent(option)
}
}
module.exports = (function() {
extendApp()
extendPage()
extendComponent()
}())