Framework7学习笔记(三):高级
Template7是一个移动优先(mobile-first)的模板引擎,其使用Handlebars风格的语法。
T7非常轻量,速度很快。F7已经内置T7,无需包含额外的JS文件。T7也可以单独使用。
使用T7时,性能瓶颈会出现在编译阶段——把字符串编译为纯粹的JavaScript函数时,亦即调用 Template7.compile() 时。因此,不要编译同一个模板多次。
- {{title}} 输出当前上下文中title变量的值
- {{../title}} 输出父上下文中title变量的值
- {{../../title}} 输出父父上下文中title变量的值
- {{this}} 输出当前上下文对象
- {{person.name}} 输出当前上下文中person变量name属性的值
- {{../person.name}} 输出父上下文中person变量name属性的值
- {{@index}} 访问额外数据变量,这些数据变量可以在助手中访问
- {{#helperName}} 块表达式开始
- {{/helperName}} 块表达式结束
- {{else}} 反转块表达式开始
- {{#helperName name="value"}} 块表达式开始,提供一个哈希参数(Hash argument),此参数的名/值分别为name/value
举例: {{join myArray delimiter=", "}} 表示知晓join助手,传递上下文变量myArray以及哈希参数delimiter。
用于遍历传入的数组的元素/对象的属性。在此助手内部,可以访问额外变量:
- @index 仅在遍历数组时有效,当前迭代的索引
- @first 仅在遍历数组时有效,当前是否第一个元素
- @last 仅在遍历数组时有效,当前是否最后一个元素
- @key 仅在遍历对象时有效,当前属性的名称
遍历数组的例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | <script type="text/template7" id="example">     <p>People list: </p>     <ul>         {{#each people}}         <li>{{firstName}} {{lastName}}</li>         {{else}}         <li>No people</li>            {{/each}}      </ul> </script> <script type="text/javascript">     app.templates.example( {         people : [ {             firstName : 'Alex',             lastName : 'Wong'         }, {             firstName : 'Meng',             lastName : 'Lee'         }, ]     } ); </script> <!-- 输出如下: --> <p>People list: </p> <ul>   <li>Alex Wong</li>   <li>Meng Lee</li> </ul>    <script type="text/javascript">     app.templates.example( {} ); </script> <!-- 输出如下: --> <p>People list: </p> <ul>   <li>No people</li> </ul>    | 
遍历对象的例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <script type="text/template7" id="example">     <p>People list: </p>     <ul>         {{#each alex}}         <li>{{@key}}: {{this}}</li>         {{/each}}      </ul> </script> <script type="text/javascript">     app.templates.example( {         alex : {             firstName : 'Alex'             lastName : 'Wong'         }     } ); </script> <!-- 输出如下: --> <p>People list:</p> <ul>     <li>firstName: Alex</li>     <li>lastName: Wong</li> </ul> | 
用于进行分支判断,只有传入的上下文变量不是false时,才会渲染if分支中的内容。下面是一个例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 | <script type="text/template7" id="example">     <a href="#" {{#if active}}class="active"{{/if}}>{{title}}</a> </script> <script type="text/javascript">     app.templates.example( {         active : true,         title : 'Link'     } ); </script> <!-- 输出如下: --> <a href="#" class="active">Link</a> | 
与上一个助手类似,但是在传入的上下文变量是false时,渲染unless分支的内容。
用于修改上下文对象。下面是一个例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <script type="text/template7" id="example">     {{#with a}}     <a href="#" {{#if active}}class="active"{{/if}}>{{title}}</a>     {{/with}} </script> <script type="text/javascript">     app.templates.example( {         a : {             active : true,             title : 'Link'         }     } ); </script> <!-- 输出如下: --> <a href="#" class="active">Link</a> | 
如果块表达式中的助手名称是上下文中的变量,则效果与 {{#each variableName}} 一致。
基于分隔符把数组元素连接为字符串。
返回转移后的HTML字符串,HTML特殊字符被转写为 &**; 形式。
立即执行一个JavaScript表达式,并把返回值输出。
要访问当前上下文对象,必须使用 this 。
T7允许通过下面的方法注册新的助手:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /**  * @param name 助手的名称  * @param helper 助手函数,用于处理上下文  */ Template7.registerHelper(name, helper); /**  * 助手函数规格,在此函数中,this指向表达式的执行上下文  * @param condition 包含传递进来的上下文或条件,例如{{#if true}}中condition为true  * @param options 包含若干属性和方法:  *      hash 传递给助手的哈希参数对象  *      fn 调用此方法,把块表达式的内容传递给编译器处理  *      inverse 调用此方法,把反转块表达式({{else}})的内容传递给编译器处理  *      data 包含额外的表达式数据,例如@index  * @return 可选,助手输出的内容  */ function helper(condition, options) {} | 
若要解除注册,可以调用: Template7.unregisterHelper(name) 。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | /* 简单的join助手 */ Template7.registerHelper( 'join', function( arr, options ) {     if ( typeof arr === 'function' ) arr = arr.call( this );     //返回值直接输出到助手在模板中的位置     return arr.join( options.hash.delimiter ); } ); /* ifeq助手:{{#ifeq var1 var2}}..{{else}}..{{/if}} */ Template7.registerHelper( 'ifeq', function( var1, var2, options ) {     if ( var1 == var2 ) {         return options.fn( this, options.data );     }     else {         return options.inverse( this, options.data );     } } ); | 
全局上下文可以在任何地方访问,使用 Template7.global 可以指定全局上下文,例如:
| 1 2 3 4 5 | Template7.global = {     os : 'iOS',     browser : 'Chrome',     username : 'Alex' }; | 
访问全局上下文,必须使用前缀 {{@global.}} 。
某些时候需要访问传递给模板的根上下文对象,此时可以使用 {{@root}} 变量。例如:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <script type="text/template7" id="example"> {{#each persons}}     <h2>{{name}}</h2>     {{#if @root.showHobby}}         <h3>Hobby:</h3>         <ul>             {{#each hobby}}                 <li>{{this}}</li>             {{/each}}         </ul>     {{/if}} {{/each}}  </script> <script type="text/javascript">     app.templates.example( {         persons : [ {             name : 'Alex',             hobby : [ 'Clectronics', 'Biology' ]         }, {             name : 'Meng',             hobby : [ 'Accountancy' ]         },         ],         showHobby : true     } ); </script> | 
在特殊标签中定义的模板,可以被F7自动编译:
| 1 2 3 4 5 6 7 | <!--      type="text/template7" 告诉F7这是一个T7模板,可以被自动编译     id="myTemplate" 指定模板的标识符,后续可以依据此标识符访问 --> <script type="text/template7" id="iTemplate">     <p>Hello, my name is {{name}} and i am {{age}} years old</p> </script> | 
需要在应用初始化参数中启用自动编译功能:
| 1 2 3 4 | var app = new Framework7( {     // 在初始化阶段自动编译模板     precompileTemplates : true, } ); | 
所有编译好的模板会存放到对象 Template7.templates 中, app.templates 是此对象的别名。在应用初始化后,可以这样使用模板:
| 1 2 3 4 | var iHTML = Template7.templates.iTemplate( {     name : 'Alex Wong',     age : 30 } ); | 
片段就是普通模板,只是它们供其它模板调用。通过片段,可以实现模板重用。通过下面的方法可以注册/解除注册片段:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | /**  * 注册片段  *   * @param name 片段的名称  * @param template 片段的内容,字符串  */ Template7.registerPartial( name, template ); /**  * 解除注册片段  *   * @param name 片段的名称  */ Template7.unregisterPartial( name ); | 
通过特殊的助手: {{> "partialName"}} 可以调用既有的片段。
T7片段的一个强大特性是,片段可以调用自身。下面是一个嵌套评论(针对评论的回复)的例子:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | /* 此模板只包含一个对片段的调用 */ var template = '{{> "comments"}}'; /* 注册片段  */ Template7.registerPartial(     'comments',      '<ul>' +          '{{#each comments}}' +             '<li>' +             '<h2>{{author}}</h2>' +             '<p>{{text}}</p>' +             '{{#if comments}}{{> "comments"}}{{/if}}' + //如果有针对评论的评论,则递归调用              '</li>' +         '{{/each}}' +     '</ul>' ); // 编译模板 var compiledTemplate = Template7.compile( template ); // 渲染模板 var output = compiledTemplate( {     comments : [ {         author : 'Meng Lee',         text : 'Good article!',         comments : [ {             author : 'Alex Wong',             text : 'Thanks!'         }, {             author : 'CaiCai Wong',             text : 'Very funny.'         } ]     }, {         author : 'WenJun Wong',         text : 'Not good!'     } ] } ); | 
输出结果如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <ul class="comments">     <li>         <h2>Meng Lee</h2>         <p>Good article!</p>         <ul class="comments">             <li>                 <h2>Alex Wong</h2>                 <p>Thanks!</p>             </li>             <li>                 <h2>CaiCai Wong</h2>                 <p>Very funny.</p>             </li>         </ul>     </li>     <li>         <h2>WenJun Wong</h2>         <p>Not good!</p>     </li> </ul> | 
在Framework7学习笔记(一)中我们提到过F7处理页面的4种方式,最后一种Template7页面在这里讲解。
F7允许把新的Ajax页面、Dynamic页面作为Template7模板来解析,要启用此功能,需要提供应用初始化参数:
| 1 2 3 | var myApp = new Framework7({     template7Pages: true }); | 
要解析模板,必须提供必要的上下文(数据)对象。可以通过应用初始化参数template7Data设置全局的上下文:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | var myApp = new Framework7({     template7Pages: true,     //指定上下文对象     template7Data: {         // 下面这个上下文专用于URL为about.html的页面(模板)         'url:about.html': {             name: 'John Doe',             age: 38,             company: 'Apple',             position: 'Developer'         },         // 下面这个上下文专用于名称为contacts(data-page="contacts")的页面(模板)         'page:contacts': {             tel: '(999)-111-22-33',             email: 'contact@john.doe'         },         // 简单数据对象(Plain data object)         'languages': {             'frontend': [                 { name:'JavaScript', desc: 'Most commonly used as part of web browsers' },                 { name:'CSS' ,desc: 'Style sheet language used for describing the look and formatting of a document'},             ],             'backend': [                 { name: 'PHP', desc: 'Server-side scripting language designed for web development' },                 { name: 'Ruby', desc: 'Dynamic, reflective, object-oriented, general-purpose programming language'}             ]         }     } }); | 
可以看到,上下文对象分为三种:
- url:*,用于特定URL的页面(模板)的上下文
- page:*,用于特定名称页面(模板)的上下文
- 简单数据对象:用于提供可供不同页面(模板)重用的、定制化的上下文
在任何时候你都可以修改模板上下文对象,你可以通过全局对象 Templates.data 或者其别名 app.template7Data 修改之。
template7Data中提供的简单数据对象,用于提供复杂的、定制化的上下文。利用普通链接和 data-context-name 属性,你可以指定该链接要加载的页面(模板)所使用的上下文对象,此对象可以是一个简单数据对象,或者其点号导航的子属性([]语法不支持)。
下面的代码示意了如何使用简单数据对象作为模板上下文:
| 1 2 3 4 5 6 | <!-- 模板languages.html将使用上下文app.template7Data.languages来渲染  --> <a href="languages.html" class="item-link item-content" data-context-name="languages">     <div class="item-inner">         <div class="item-title">Languages</div>     </div> </a> | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <div class="page" data-page="languages">   <div class="page-content">     <div class="content-block-title">Frontend</div>     <div class="list-block">       <ul>         <!-- 遍历app.template7Data.languages.frontend -->         {{#each this.frontend}}         <li>           <!-- 嵌套的模板,支持基于点号导航(languages.frontend.1是合法的)来访问子对象 -->           <a href="language-details.html" class="item-link item-content" data-context-name="languages.frontend.{{@index}}">               <div class="item-inner">                 <div class="item-title">{{this.name}}</div>               </div>           </a>         </li>         {{/each}}       </ul>     </div>   </div> </div>  | 
| 1 2 3 4 5 6 7 8 | <div class="page" data-page="language-details">   <div class="page-content">     <div class="content-block-title">{{name}}</div>     <div class="content-block">       <p>{{desc}}</p>     </div>   </div> </div> | 
你也可以通过导航/路由 API来指定上下文对象:
| 1 2 3 4 | mainView.router.load({     url: 'language-details.html',     contextName: 'languages.frontend.0' }) | 
除了通过template7Data指定的全局上下文以外,你还可以使用即时指定的定制上下文。HTML方式:
| 1 2 | <!-- 赋值串行化的JSON对象给data-context属性 --> <a href='contacts.html' data-context='{"tel": "(999)-111-22-33", "email": "contact@john.doe"}'>Contacts</a> | 
JavaScript方式:
| 1 2 3 4 5 6 7 | mainView.router.load( {     url : 'contacts.html',     context : {         tel : '(999)-111-22-33',         email : 'contact@john.doe'     } } ); | 
F7会自动编译 <script id="templateName" type="text/template7"> 声明的模板。要将其作为Template7页面使用,可以通过HTML方式:
| 1 2 | <a href="#" data-template="templateName"></a> <a href="#" data-template="templateName" data-context='{"name": "value"}'></a> | 
或者JavaScript方式:
| 1 2 3 4 5 6 | mainView.router.load( {     template : Template7.templates.templateName,     context : {         name : 'value'     } } ); | 
特殊的上下文属性 url_query 用于访问URL上的GET参数:
| 1 | <a href="person.html?firstname=Alex&lastname=Wong&age=30">Alex</a> | 
| 1 2 3 4 5 |  <div class="page" data-page="person">     <div class="page-content">         <p>Hello, my name is {{url_query.firstname}} {{url_query.lastname}}. I am {{url_query.age}} years old.</p>     </div> </div> | 
Framework7提供了简单易用的插件API,利用这些API你可以扩展自己的F7插件。
只需要为 Framework7.prototype.plugins 添加一个属性,即可注册新插件。例如:
| 1 2 3 4 5 6 7 8 | /**  * myPlugin 新插件的名字  * app 已初始化的F7应用对象  * params 可选的插件参数  */ Framework7.prototype.plugins.myPlugin = function( app, params ) {     //插件代码 }; | 
要引用新插件,只需要将其JS文件包含到HTML中,位于F7主JS文件之后:
| 1 2 | <script src="path/to/framework7.js"></script> <script src="path/to/framework7.myplugin.js"></script> | 
在F7应用初始化的时候,可以向插件传递参数:
| 1 2 3 4 5 6 7 8 9 | var myApp = new Framework7( {     pushState : true,     /*      * 为myPlugin传递参数      */     myPlugin : {         foo : 'bar'     } } ); | 
F7插件系统包含三种扩展机制:
- hooks:与通常的回调类似,由F7在框架的很多核心部分调用。可以在特定时刻/场景执行插件代码、处理数据
- prevents:用于阻止F7默认行为,例如阻止默认页面动画而使用自己的
- processes:类似于预处理器,每个处理方法可以接收被处理数据
插件函数的返回值必须是一个对象,其包括hooks、prevents和processes属性。例如:
| 1 2 3 4 5 | return {     hooks : {         appInit : function(){}     } }; | 
可用的钩子包括:
| 钩子 | 说明 | 
| appInit | 当应用完全初始化后调用 | 
| navbarInit (navbar, pageData) | 和navbarInit事件一样 | 
| pageInit (pageData) | 和navbarInit事件/回调一样 | 
| pageBeforeInit (pageData) | 和pageBeforeInit事件/回调一样 | 
| pageBeforeAnimation (pageData) | 和pageBeforeAnimation事件/回调一样 | 
| pageAfterAnimation (pageData) | 和pageAfterAnimation事件/回调一样 | 
| pageBeforeRemove (pageData) | 和pageBeforeRemove事件/回调一样 | 
| addView (view) | 当用户通过app.addView()添加新的视图时触发,入参是已实例化的视图对象 | 
| loadPage (view, url, content) | 在新页面开始被加载时调用,此时页面尚未加入到DOM中 | 
| goBack (view, url, preloadOnly) | 在返回操作开始前调用 | 
| swipePanelSetTransform (views, panel, percentage) | 侧面板滑出/滑入的过程中调用 | 
 
            
Leave a Reply