EP-WachatApp/lib/SPage.js

345 lines
8.9 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 引入事件模块 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()
}())