NView数据绑定

除了标准字符串模式的文本、属性设置外,NView模板支持将NView实例数据绑定至NView控件上。

插值

NView模板的文本、属性插值方式相同,均使用大括号({})表示当前为Javascript表达式,不是直接字符串赋值,如下为一个简单示例:

  1. <template>
  2. <nviews cacheMaxAge="86400">
  3. <nview id="nview1" style="position:static;top:200px;height:50px;">
  4. <Font>{data.product_name}</Font>
  5. </nview>
  6. </nviews>
  7. </template>
  8. <script>
  9. module.exports = {
  10. data: {
  11. product_name:'产品名称'
  12. }
  13. };
  14. </script>

NView模板中的Javascript表达式,要求必须是单个表达式或JSON对象,如下都是合法的:

  1. <nview id="nview1" style={{
  2. //这里是json对象
  3. position:"static",
  4. top:data.top
  5. }}>
  6. <Font>{data.rem * 17}</Font>
  7. <img id="img1" style={{
  8. //三元表达式
  9. width:data.full?"100%":"80%"
  10. }}>
  11. </nview>

备注:两个大括号{{}}的含义,外层大括号{}表示接下来为Javascript运算符,内层大括号{}表示当前为一个JSON对象。

下面的例子则不生效,因为他们是语句,而不是表达式

  1. <font>{data.rem = 10}</font>

数据源

NView模板可以绑定JavaScript动态计算的数据,数据的提供主要有两种方式:

  • 直接通过data属性提供默认值,这种方式适用于数据相对固定,跟具体业务无关的场景,比如设置界面、开发商等
  • 在init属性中,编写JavaScript代码,根据业务场景动态计算(请求)数据

data属性

默认数据可直接在data属性中提供,data支持Object、Function两种方式,例如:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            city:'北京'  
        }  
    };  
</script>

下面是Function示例,返回值要求是Object类型;Function适合需要简单计算的场景,比如根据屏幕分辨率动态计算文字大小、宽高等场景:

<script>  
    module.exports = {  
        data: function() {  
            return {  
                fontSize:window.screen.width > 360 ? "17px" : "15px",//动态计算  
                vendor:'DCloud'  
            }  
        }  
    };  
</script>

init属性

跟业务相关的数据,可以在init中通过JavaScript编程实现,使用方式如下:

<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //url为新开webview加载的地址,可以通过url分析出部分业务参数  
            //TODO 获取数据,存储为newData  
            var newData = {};  
            ...  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

动态计算NView数据,通常有三种场景:

  • 通过页面url地址,分析出所需业务参数,适合页面url和业务数据有明确对应关系的场景
  • 通过前页获取数据,比如列表页已经显示了商品的名称,则详情页可以直接复用列表页的商品名称数据
  • 通过ajax请求获取数据,这样可以在Document加载完成之前提前发起请求并渲染

如上三种方式可混合使用,每次调用setData()方法,都会覆盖之前的数据(merge覆盖,非完全替换),如下是示例:

<script>  
    module.exports = {  
        data: {  
            vendor:'DCloud',  
            author:'CHB',  
            product:{  
                name:'wap2app'  
            }  
        },  
        init: function(url) {  
            var newData = {  
                author:'FXY',  
                product:{  
                    description:'基于M站的强化方案'  
                }  
            };  
            //必需:重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

如上代码运行后,最终的模板数据为:

{  
    vendor:'DCloud',//保留  
    author:'FXY',//替换  
    product:{  
        name:'wap2app',//保留  
        description:'基于M站的强化方案'//新增  
    }  
}

通过url分析业务数据

这种模式适合页面url和业务参数有明确对应关系的场景,比如页面地址为http://www.example.com/detail/%id%,该页面上图片轮播地址固定为:

http://www.example.com/images/%id%/1.png  
http://www.example.com/images/%id%/2.png  
http://www.example.com/images/%id%/3.png

我们可以通过分析页面url,解析出id参数,然后拼接轮播组件图片源地址,如下是一个示例代码:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="nvew2" style="height:200px;">  
            <!--图片轮播-->  
            <imageslider images={data.imgList}></imageslider>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data: {  
            //默认数据  
        },  
        init: function(url) {  
            //页面url地址为http://www.example.com/detail/%id%  
            //分析页面id  
            var id = url.substring(url.lastIndexOf("/")+1)  
            var newData = {};  
            var list = new Array();  
            //循环,构建原生轮播图片源信息  
            for (var i = 1; i <= 3; i++) {  
                var item = {};  
                //图片源地址  
                item.src = "http://www.example.com/images/" + id + "/" + i +".png";  
                item.width = "100%";  
                list.push(item);  
            }  
            //设置轮播组件信息  
            newData.imgList = list;  
            //重新设置data  
            this.setData(newData);  
        }  
    };  
</script>

复用前页数据

下图是一个示例,从列表打开详情(列表页就是前页),详情页的部分数据和列表页相同(如商品图片、标题、价格等),此时就可以复用列表页的数据,提前渲染:

数据绑定 - 图1

复用前页数据的思路:

  • 用户在前页点击时,将可复用信息存储到本地缓存中
  • 在新页面创建后,从本地缓存中读取数据并渲染到NView中

我们以列表打开详情页,详情页使用NView加速渲染为例,演示如何实现复用前页(列表页)数据。

前页存储本地缓存

用户点击时存储数据的代码,建议在M站编写,也可以在HBuilder客户端编写,然后通过appendJS的方式插入到原站。如下是一个示例代码:

假设前页列表HTML代码如下:

<!-- 列表开始 -->  
<div id="list">  
    <!-- 第一个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/1.png" alt="" />  
        <p class="title">Item 1</p>  
    </div>  
    <!-- 第二个列表项 -->  
    <div class="item">  
        <img src="http://www.example.com/img/2.png" alt="" />  
        <p class="title">Item 2</p>  
    </div>  
</div>  
<!-- 列表结束 -->

我们可以增加如下JS代码,当用户点击列表项时,将列表项数据缓存到plus.storage中,示例如下:

(function() {  
    //非5+引擎环境,退出  
    if(navigator.userAgent.indexOf("Html5Plus") == -1) {  
        return false;  
    }  

    //判断DOM是否加载完成,如果M站已封装了类似方法,可以直接使用,例如jQuery.ready()  
    var readyRE = /complete|loaded|interactive/;  
    if(readyRE.test(document.readyState)) {  
        domReady();  
    } else {  
        document.addEventListener('DOMContentLoaded', function() {  
            domReady();  
        }, false);  
    }  

    function domReady() {  
        var cacheId = "detail"; //缓存的ID,NView模板会通过该ID读取缓存数据  
        var container = document.querySelector("#list"); //列表容器,根据M站实现改造  
        var eventType = "click"; //点击事件,根据M站实现更改,比如tap  

        //容器添加点击事件监听  
        container && container.addEventListener(eventType, function(e) {  
            var target = e.target;  
            for(; target && target !== container; target = target.parentNode) {  
                if(target.classList && target.classList.contains("item")) { //列表项  
                    var data = {};  
                    //获取图片路径  
                    var imgElem = target.querySelector("img"); //获取当前列表项下图片对象  
                    if(imgElem) {  
                        data.imgPath = imgElem.getAttribute("src"); //获取图片资源路径  
                    }  
                    //获取标题  
                    var titleElem = target.querySelector(".title"); //获取当前列表项下的标题对象  
                    if(titleElem) {  
                        data.title = titleElem.innerHTML.trim(); //获取标题  
                    }  
                    //将当前数据存储到缓存中  
                    plus.storage.setItem(cacheId, JSON.stringify(data));  
                    return;  
                }  
            }  
        });  
    }  
})();

NView模板中读取缓存数据

NView模板封装了一个wap2app.getFromCache()方法,该方法有两个功能:

  • 从plus.storage中读取缓存数据并自动转成object对象
  • 读取缓存数据后,自动清除数据,防止下次打开同类页面时(本例为打开其它详情页),数据错乱

wap2app.getFromCache()使用方法如下:

wap2app.getFromCache(cacheId,function(data){  
    //data是plus.storage.getItem(cacheId)返回的数据,已自动转成object类型  
})

继续上如列表示例,详情页NView模板完整代码如下:

<template>  
    <nviews cachemaxage="86400">  
        <nview id="detailNview" style="height:225px;">  
            <canvas>  
                <!--缩略图-->  
                <img style="top: 0;width:100%;height:225px;" src={data.imgPath}/>  
                <!--标题-->  
                <font style="bottom: 10px;height: 20px;">{data.title}</font>  
            </canvas>  
        </nview>  
    </nviews>  
</template>  
<script>  
    module.exports = {  
        data:{//默认数据,可选  
            imgPath:'http://www.example.com/img/default.png',  
            title:''  
        },  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //从缓存中读取数据  
            //'detail'为前页存储数据时的key  
            wap2app.getFromCache('detail', function(data) {  
                if(data) {  
                    //读取缓存数据成功,更新数据,刷新NView  
                    self.setData(data);  
                }  
            });  
        }  
    };  
</script>

ajax获取服务端数据

NView模板也支持动态从服务端获取数据,wap2app封装了一个wap2app.getFromWebService()方法来实现AJAX请求,如下为示例代码:

<script>  
    module.exports = {  
        init: function(url) {  
            var self = this;//this作用域在回调函数中会变化,复制给变量self  
            //动态初始化数据  
            wap2app.getFromWebService({  
                url: 'your-server-url',  
                data: {},  
                type: 'post'  
            }, function(data) {  
                //TODO 如果服务端返回数据格式和模板需要的格式不同,则需要做一下转换  
                self.setData(data);  
            })  
        }  
    };  
</script>