tpCore APIs
概述
TypechoCore 是一个专为单页 Typecho 设计的小型前端支持。其能够简化动态页面附载的 JS 处理流程,同时还提供若干实用方法。常规情况下,Boinky 会自动加载此核心文件,及其能够正常工作所必需的 jQuery
、jQuery.pjax
与 jQuery Lazyload
。若要编写主题脚本,则应确保所有其它文件在 tpCore
之后声明。
作为全局变量,TypechoCore 中的所有属性允许直接通过名称进行访问。它分为以下内部对象:
机读名称 | 描述 |
---|---|
_core | 父对象。作为一个引用,分配至所有子命名空间中。 |
xhr | 包含用于处理 XmlHttpRequest 行为与事件的工具函数。 |
engine | 包含用于协调基本资源与服务器响应的工具函数。 |
ui | 包含对 DOM 执行的所有操作,例如显示通知、插入元素或对话框。 |
storage | 包含用于处理 LocalStorage 的简易工具。 |
content | 这部分专为 Typecho 设计,主要目的是为了解析与后处理正文内容。 |
除此之外,还包含了四个基本父命名空间以允许扩展。
机读名称 | 描述 |
---|---|
Element | 用于声明、注册元素触发器函数的基本命名空间。 |
State | 用于标识、设置与读取当前页面的加载状态。 |
Callback | 在这个命名空间中直接实现回调函数,然后 tpCore 会自动在某些情况下对其进行调用处理。 |
Processor | 用于保存其它可能加载到 tpCore 中的杂项方法。 |
所有这些命名空间共同组织整个 tpCore
。你可以根据命名空间的首字母大小写情况来判断它是一个基本空间,还是一个内部空间。通常不建议将新的通用方法或属性导入内部空间,相反,它们应该被声明至 Processor
中。至于 Element
和 Callback
,它们均有各自的使用规范,请勿在其内部实现非必要成员。
基本模式与元素注册
随着 DOM 首次加载,tpCore
首先执行无阻塞的初始化。其中:
this.xhr.listen( this.elementInit );
它的关键任务是将 TypechoCore.elementInit
载入至 jQuery.pjax
的事件周期当中,以实现伴随页面动态加载的局部函数控制。它实际上是将前者绑定至 pjax:end
事件,该事件标志着整个 PJAX
请求与内容置换的结束;而 elementInit()
则负责处理新页面的 JavaScript。此函数实现逻辑:
- 查找所有携带
data-typecho-init
属性的元素。对于每个元素... - 查询该元素的
dataset.initialized
。若其为true
,则跳过;否则... - 获取此
data-typecho-init
属性值,并查询其是否已被triggerElement()
显式绑定于TypechoCore.initRegistry
; - 获取此属性值作为键名在
initRegistry
中的映射名,然后执行此映射名函数。携带此typecho-init
属性的元素作为唯一形参。 - 将此元素的
dataset.initialized
标记为true
,以规避下一次轮询。
上述流程执行于每次页面加载完毕。TypechoCore 依此实现 PJAX
下的 JavaScript
控制。
将元素注册至 initRegistry
根命名空间提供方法 registerElement()
以允许向任意 DOM 元素注册动态脚本。
registerElement: function(initTrigger, alias = null, triggerOnRegister = true)
initTrigger
是目标元素的data-typecho-init
属性值字符串。- 参数
alias
为可选别名。该别名未提供或为null
时,tpCore
将自动使用initTrigger
的驼峰格式作为目标映射函数的名称。 - 参数
triggerOnRegister
为声明控制。若此参数为true
,则在调用registerElement
向tpCore
执行注册时,会自动触发一次针对目标元素的elementInit
。
若如此做,则下次 PJAX
请求获取目标页面时,若携带 data-typecho-init
属性值为 initTrigger
的元素存在于目标页,则下方的函数会被执行:
TypechoCore.Element.INIT_REGISTRY_NAME()
其中 INIT_REGISTRY_NAME
是目标映射函数的别名。它必须位于 Element
命名空间,且其名称符合下列情况之一:
- 若未在
registerElement
中提供参数alias
或其为null
,则必须严格为initTrigger
字符串值的驼峰写法。如:test-function => testFunction
; - 若传入字符串
alias
,则应与alias
一致。如:test_alias_function => test_alias_function
。
最终一个符合上述命名要求且与元素触发标识 initTrigger
绑定的映射将被记录至属性 TypechoCore.initRegistry
。下面是一个完整的示例:
TypechoCore.Element.testFunction = function( $element ) {
const className = $element.attr( 'class' );
console.log( 'The class name of trigger element is: ' + className );
console.log( 'This is a test element-based function!' );
}
TypechoCore.registerElement('test-function');
<div class="some-class" data-typecho-init="test-function"></div>
载入携带目标 HTML 的页面,则控制台将会显示相应内容。最后,使用下面的函数来判断目标(原始)名称是否已注册至 initRegistry
:
TypechoCore.isElementRegistered( 'test-function' );
事件创建与销毁
在切换页面的整个过程中,我们经常需要创建事件、解绑事件,以及插入或销毁元素。实际上它们都是基于 PJAX 的。TypechoCore 提供的 xhr
集提供了若干简单的方法,它们可以帮助略微简化上述操作。将来版本的 tpCore
可能会支持更加复杂的行为。要声明 PJAX 事件监听器,使用:
TypechoCore.xhr.listen( callback, executeAtOnce = false, eventName = 'end' );
此代码将函数 callback
永久绑定至 pjax:eventName
事件。参数 executeAtOnce
控制目标函数是否在执行此绑定操作之后立刻执行一次。
很多情况下我们只希望在下次而非永久请求页面的时候执行某些操作,比如销毁特定的元素或对象。要如此做,则使用:
TypechoCore.xhr.listenOnce( callback, eventName = 'beforeReplace' );
这等价于 $(document).one('pjax:eventName', callback)
。查阅 PJAX 文档以了解所有 PJAX 事件的名称及详细信息。请注意:显然,被绑定的函数不会拥有上下文,这意味着目标函数中不应包含任何 this
或与之类似的调用。最后,xhr
空间还提供了对两个 jQuery 原生方法的借用:
TypechoCore.xhr.makeRequset(); // 等价 $.ajax
TypechoCore.xhr.makePopStateRequest(); // 等价 $.pjax
资源的动态请求
有时候我们只想让目标功能在被使用的时候,浏览器才会加载其脚本与样式表文件——若用户并未用到这些功能,则不会加载以节省资源。比如 Citizen 中随处可见的富文本编辑器。它的依赖文件大小高达 1MB,不加判断地直接引用这些依赖,显然会影响到用户的浏览体验。TypechoCore 允许函数以异步方式尝试获取这些文件。
const loadFancybox = async function() {
await TypechoCore.engine.requestResource( 'https://.../jquery.fancybox.min.js' );
...
}
上面的函数将会等待目标文件 jquery.fancybox.min.js
完全加载到本地,然后再执行之后的操作。当然,也可以使用等待链,以及一次性传入多个资源:
TypechoCore.engine.requestResource( [
'https://.../jquery.fancybox.min.js',
'https://.../jquery.fancybox.min.css'
] ).then( ... );
它的原理是通过 $.getScript
获取 JS;通过 $('head').append
获取 CSS。在 TypechoCore.engine
内部,此方法事实上是与名为 requestNew
的方法协同工作,后者负责将资源的文件名保存至 TypechoCore.resolvedRequests
中,然后检查与处理后续可能存在的重复请求项。使用下面的代码来判断指定资源是否已被请求:
TypechoCore.engine.isResolved( 'jquery.fancybox.min.js' );
无论何种情况,当 requestResource
开始准备请求资源时,触发 core:promisedLoadStart
事件;所有请求结束时,触发 core:promisedLoadEnd
事件。
categories 分类页面 没有内容撑起, 页面滚动 底部就会出现空白了. 文章页面又内容撑起 不会
OK 等俺有空修复这个小小的问题
很强!