说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

【前端框架】Backbone.js在大型单页面应用中的应用实践

HTML文档下载 WORD文档下载 PDF文档下载
本文选自《程序员》2013年3月刊,全面介绍了轻量JavaScript MVC框架Backbone.js,并分享了豌豆荚PC客户端借助Backbone.js在开发大型单页面应用上做出的大量实践。

Backbone.js是什么?

Backbone.js是一个JavaScript MVC框架,提供了良好的代码组织能力,可以方便地将应用程序解耦成可以复用的部分,为建立大型的单页面应用提供框架支持,目前的版本是0.9.10(注:现在已到1.2.1版本)。通过将应用程序分解成MVC模式中不同职责的模块,带来了以下几点好处。

  1. 降低维护成本。数据、控制器、视图的更新都是独立进行的,互相之间都是松散耦合的。
  2. 解耦数据和视图,便于直接对业务逻辑进行单元测试。
  3. 便于团队合作,负责UI开发和业务逻辑开发的工程师可以分工并行工作。对于Web前端开发来讲,负责HTML模板和CSS的界面工程师和负责业务逻辑的JavaScript工程师可以协同工作。

Backbone.js算是比较轻量的MVC框架,所谓轻量,是说它只关注一个框架应该关注的最基本的事情——如何给应用分层、如何组织各种功能的代码。至于在实际开发中需要用到的Utils或UI组件,Backbone.js则没有提供任何支持。但Backbone.js所依赖的Underscore.js是一个功能比较全面的非侵入式工具函数类库,算是在Utils方面的一个补充。

轻量并不意味着功能薄弱。首先,Backbone.js的精髓是它定义前端MVC的方式和编码哲学,并依据这些规定了如何去给代码分层,因此Backbone.js能够让前端工程在可维护性和扩展性上都得到质的提升;同时,由于其良好且易于理解的结构,各个模块之间都是松散耦合的,虽然目前官方并没有提供根据实际需求build文件的功能,但如果你愿意,完全可以自己手工删掉源码中的Bakcbone.View只使用Model和Collection;最后,Backbone.js的任何一个部分都是非常容易扩展的。因此,Backbone.js的功能实际上非常强大的。下面将介绍Backbone.js的主要组件(架构如图1所示)。


图1 架构图

Backbone.Events和Backbone.Sync

Backbone.Events和Backbone.Sync两个组件是Backbone.js异步通信、事件驱动的编程模型的基础。

Backbone.js中所有的组件都通过_.extend()的方法“继承”了Backbone.Events所提供的功能,可以维护一套自己的事件订阅和回调列表。通过Events.on(event,[callback],[context])和Events.off([event], [callback], [context])两个方法来实现对事件的订阅和取消订阅。


早期版本中的事件订阅和取消订阅是通过Events.bind()和Events.unbind()两个方法实现的,目前的版本中还保留了这两个别名方法,但不推荐使用。

Backbone.js的所有组件都有一些内置的事件,可以查阅官方文档。除了预置事件外,通过Events.trigger(event,[*args])方法也可以方便地触发自定义事件。


从0.9版开始,Backbone.Events提供了Events.listenTo(other,event,callback)和Events.stopListening([other],[event],[callback])两个新方法来通过另外一种形式实现事件的订阅和取消订阅。

与on()和of f()不同,这种方式将监听的主动权转换了。举个例子来说:有对象A和对象B,B.on('someThingHappened',A.doSomeThing)是当对象BsomeThingHappened时候知对象A去doSomeThing;而A.listenTo(B,'someThingHappend',A.doSomeThing)是对象A主动去盯着对象B,当它someThingHappend的时候去doSomeThing。

第二种方式最大的意义是变被动为主动,从而实现了IoC(Inversionofcontrol,控制反转)。监听者和被监听者之间没有了耦合,只要被监听的对象能够抛出指定的事件,就可以和监听者组合在一起,甚至不需要去关心被监听对象的类型,这对代码的复用和行为抽象有很大的帮助。在测试层面,可以轻易地把被监听对象换成mock的测试代码来模拟真实情况。

Backbone.Sync则将同服务器的通信封装了起来,当Collection和Model需要和服务器通信交换数据时,会去调用Backbone.Sync中对应的方法并发送请求,如果服务器端支持RESTfulAPI就可以将整个通信过程描述得非常优雅并易于扩展。Sync的实现可以是jQuery.ajax()的封装,也可以是其他的类库提供的异步通信工具的封装。

Backbone.Model和Backbone.Collection

Backbone.js中的Model和Collection共同构成了MVC中的M层。Model的本质就是一组以keyvalue形式保存的数据,可以通过Backbone.Model.extend()来定义自己的Model。


上面的示例代码中defaults属性定义了一组默认值,当Model初始化时,如果没有指定defualts中所定义的属性的值,就会用默认值来填充Model;initialize()方法会在Model被实例化时调用,用来进行一些初始化的操作;validate()方法会在Model的save()或set()方法被调用时执行,可以根据具体需求进行扩展。

通过Model的getters和setters可以实现对Model中属性的读写,并且当set()方法被调用时,Model会将属性变化的事件广播给所有订阅者(通常是视图),驱动视图重新渲染或其他关联的Model的数据更新。

Collection是一组Model的集合,通过Collection可以将一组数据结构相同的Model有序地组织在一起,进行批量操作和管理等。同时,Collection代理了Undersore.js中众多用来操作Collection的工具方法,例如find、filter、map等。

Model和Collection都可以通过RESTfulAPI同服务器进行数据交换。

Backbone.View

Backbone.View是基于Backbone.js开发的Web App中的核心部分,负责用户交互事件的捕捉和处理、把用户输入导向Model或Collection、渲染视图、操作DOM等。Backbone.js的内部实现依赖$变量,因此DOM操作的库可以在jQuery、Zepto或Ender等中选择。从目前的情况来看,在桌面浏览器中,Sizzle.js(jQuer y所使用的SelectorEngine)的性能还是甩开Zepto几条街的,因此面向桌面浏览器的开发还是推荐使用jQuery,移动端考虑到文件体积等因素推荐使用Zepto。

对于一个Backbone.View来讲,最重要的就是$el属性,$el是一个jQuery对象(取决于所采用的DOM操作类库),是一个视图的最外层容器。容器所采用的HTML标签可以通过tagName属性来指定,可以是ul也可以是header或其他任何标签,默认情况下是div。

容器内部的DOM渲染可以通过模板引擎来完成。Underscore.js本身提供了一个_.template()的方法,因此Backbone.js不需要额外的模板引擎支持。当然,如果有特殊的需求,例如和后端共用模板文件,也可以选用Mustache等其他的模板引擎。


这样一个View就被渲染到界面上了。上面的代码中还监听了Model的change事件,当数据发生变化时,驱动视图重新渲染。当Model的数据比较丰富时,只有一个属性变化就重新渲染整个视图显然会带来性能上的隐患,因此这里的最佳实践就是把render的过程break-down成粒度更细的片段。


值得注意的是,当一个View不再被需要时,一定要记得销毁,除了销毁DOM对象外,也要销毁所有的事件监听器。在只有Events.on()和Events.off()的年代,由于销毁View时需要逐一取消订阅所有的消息,经常由于忘记解除某个绑定导致产生被称为GhostView的垃圾对象,既无法被释放也无法被回收。这也是Events.listentTo()方法带来的另外一个好处——只要调用Events.stopListening()方法即可将此对象的所有事件监听器销毁。

所有的DOM事件也是通过$el来代理的,在Backbone.View中可以通过以下方法来方便地管理DOM事件。


Backbone.js的内部实现里,在View的构造方法中调用View. initialize( )后将继续调用View.delegateEvents()方法,这个方法将解析events属性所定义的事件和回调列表,并将全部事件代理到$el对象上。由于使用的是事件代理,某些不支持冒泡的DOM事件则必须另外监听,如滚动条事件。


Backbone.Router和Backbone.History

Router是用来在URLHash和特定的动作或视图之间做映射的。


最后一句History.start()是告诉Backbone.js开始对URLHash的变化进行监视,也可以随时通过History.stop()来停止监视。同时,如果目标平台是支持HTML5Histor yAPI的,那么在start时传入{pushstate:true}的参数,就可以去掉URL中的#字符,对SEO有一定帮助。

Backbone.js的适用场景

经常能在各种场合听到前端工程师们讨论“你们的XXX是用什么做的啊?”“为什么不用XXX啊?”这样的问题。前端的类库和框架林林总总,算在一起数量没有一千也有五百,因此在面对一个新项目时难免会产生选择恐惧症。

但说到底,技术方案都是由需求决定的,任何一个类库或框架都有其适用范围和最佳的使用场景,Backbone.js也不例外。Backbone.js的最佳使用场景是大型的单页面应用:通过RESTfulAPI同服务器通信,然后根据数据的变化来驱动视图重新渲染,整个程序建立在异步通信和事件驱动的编程模型之上。

单页面应用给用户带来的使用体验是沉浸式的、相对重型的,对于普通的Web Page和数据相对稳定、视图不需要频繁重新渲染的场景来讲,Backbone.js显然就没有用武之地了。

Backbone.js和MV*不得不说的那点事儿

四十年前,Trygve Reenskaug基于Smartalk语言设计出了MVC模式,经过几十年的发展,MVC出现了众多的衍生。而我们今日说的MVC在不加特殊说明的情况下,通常指的是在服务器端Web应用开发中大量使用的WebMVC。

对于典型MVC模式来讲,View是无法直接获得用户输入的,而Controller则是用户输入和View之间的桥梁。但在浏览器中,View层的载体是HTML,用户输入和交互行为都是基于HTML的,对事件的捕捉、输入都由浏览器代劳了,并且输入会首先进入View层,因此对于前端开发来讲,严格意义的MVC是无法实现的。

因此,包括Backbone.js在内的JavaScript MVC框架的实现并没有严格遵循MVC的定义,Controller的部分职责被转移到了View层。Backbone.js对于前端MVC的定义非常易于理解,但对于没接触过MVC模式的同学来说在初期会有一些迷惑,原因是Backbone.js核心组件的命名。Backbone.js的核心组件包括Backbone.Collection、Backbone.Model、Backbone.View和Backbone.Router,而在早期的版本中,Backbone.Router组件的名称是Backbone.Controller,这很容易让人直接将其和MVC三层中的C层联系起来。但事实上,Backbone.Controller的作用是根据URLHash来在对应的行为和事件中做路由的,其功能同MVC中的C相比要简单很多,因此在0.5前后Controller改名叫做Router了。从实体代码的角度看,View层其实是模板代码和Backbone.View中部分代码的综合体,而Backbone.View中剩余的部分才是MVC模式中Controller的概念,负责操作View以及数据在View和Model层中的流转。

对于前端开发来说,用户直接面对的一层并不是Controller而是View,用户输入也会首先进入View,因而用MVP和MVVM模式来描述架构更加合理。相比AngularJS等框架,Backbone.js的模式显然更易于理解,学习曲线比较平缓,因为它并没有引入过多的需要重新认知和理解的新概念而是尽量在靠近传统的MVC模式,对于以前接触过MVC模式开发的同学来说非常容易上手,而AngularJS中的Directive等概念还是需要一定认知成本的。

但如果从架构的角度讨论,AngularJS其实是更为纯粹并更接近严格意义上的MVC模式。为了把View的功能提升到一个应有的高度,引入了Directive的概念,通过扩展HTML标签和自定义属性来描述View,在Directive中来解析这些扩展出来的内容,理解成本和代码的复杂程度都有所提高,但View层功能则得到了质的提升。

反观Backbone.js,并没有在前端开发中真正的View的载体HTML上做太多文章,即便采用模板引擎也仅仅是把数据和HTML组合起来。但得益于其强大的扩展性,可以很容易将Knockout等Data-binding框架集成进来,从而实现MVVM的架构和分层。例如前文提到将render的过程Breakdown就完全可以用Data-binding来取代,省掉了手工更新DOM的烦琐。

Backbone.js在豌豆荚PC客户端2.0中的实践

豌豆荚PC客户端2.0的UI是完全建立在Web前端基础上的。借助Backbone.js,豌豆荚PC客户端在开发大型单页面应用中做了大量的实践。通过在客户端中捆绑一个Webkit引擎并对其进行扩展,使得跑在Webview中的前端代码跳出沙箱的限制,可以操作文件系统并调用系统API,以此来进行桌面应用的开发。这样做的好处有以下几点。

  1. 极大提高开发效率:桌面应用的开发中,UI开发效率一直很低,但借助HTML5和CSS3的新功能,Web前端可以轻易地做出精细程度和交互体验都不输桌面应用的UI,但开发效率和维护成本都极大降低。
  2. 易于跨平台:UI依赖于Webkit引擎,而Webkit引擎本身是跨平台的,因此可以很容易地移植到Web上或其他桌面平台。
  3. 快速迭代和改进:由于维护和扩展成本的下降,可以快速的将原型设计产品化并进行验证,提高产品迭代和改进的速度。

但与此同时,用Web前端技术开发桌面应用也要面临巨大的挑战。首先就是内存消耗。用户在使用浏览器和使用桌面应用时的心理预期是不一样的,即使一段有内存泄漏问题的前端代码跑在浏览器里,当出现运行缓慢时大不了一下刷新页面,但对桌面应用来讲,大多数情况下没有刷新Webview的机会,因此必须对内存实现更精细的控制。由于Webview本身依赖于GC,前端无法主动管理和回收内存,因此必须借助ChromeDeveloper tools中的Profiles等工具查找出现内存泄漏的地方从而进行改善,这也依赖于大量的经验积累。

其次是运行速度和界面响应速度。由于Webview是单线程的,但单页面应用面临的是数百倍于Web Page的业务逻辑复杂度,同时业务逻辑的执行和UI共用一个线程,如何优化执行速度也是一个很大的挑战。虽然目前WebUI的界面流畅程度无法完全达到桌面应用的水平,但依然是很有竞争力且有提高空间的。(责编:陈秋歌)

作者简介

赵望野:豌豆荚前端团队负责人。

本文选自《程序员》2013年3月刊。2000年创刊至今所有文章目录请查看程序员封面秀。欢迎订阅程序员电子版(含iPad版、Android版、PDF版)。

欢迎加入CSDN前端交流群:218126086,进行前端技术交流。  

让开发者高效编程的10个新框架 Google Analytics中显示访客停留时间为“0”的秘密 大数据之惑 麻省理工三位物理学家自建数据库服务Cloudant 融资1200万美元 网页浏览器进入再造新时代 AMD揭露HSA运算架构新技术hUMA细节 美团悄然上线云主机服务:与亚马逊殊途同归,还是另有谋划? 微软发布deep-tech团队招募令,期望获得下一代开发者的支持 2013谷歌I/O开发者大会:发布多个软件产品和服务 C语言实现二分法求解方程 开发测试云与虚拟化解决方案 学苹果?微软淘汰Points支付系统改用Gift cards 甲骨文改变Java版本号命名方式 [CTO俱乐部第97期]中科院、腾讯、深圳明源研发团队管理经验分享 Android Studio来了,它能取代Eclipse吗? Google Play Game不够开放,被OpenKit炮轰 Google Play Game Service详解 不仅提供API更提供后端支持 IBM Power走向Linux,是必然的! 美国国家安全局解密特工培训手册:如何利用谷歌等大众搜索工具搜集保密数据 微软IE10如何保护上网安全(大图) 谷歌无畏苹果的理由:强力的算法和基础设施架构 开发者热议异构统一内存访问技术(hUMA) 千万级并发实现的秘密:内核不是解决方案,而是问题所在! Apache RewriteRule重写规则语法入门 IDC:2013 Q1 Android和iOS出货量占92% WP首超黑莓 传雅虎欲10亿美元收购轻博客网站Tumblr A Beautiful Mess:如何赚男人女人的钱 CSS、JavaScript开发者必备的10款最佳工具 IBM推出API管理平台 抢占API经济市场份额 2013中国云计算榜单之一:15云平台,谁主沉浮? 移动周报:百万壁纸、85后程序媛,我为梦想代言! 请教关于TImageList中存储多幅图片的问题 100分赠送 寻架构? 请教高手:如何在VB开发的程序中准确判断用户的可用内存? 用jb怎么在另一个类中控制frame中的一个label的text的实时的变化?多谢 如何制作PB应用程序的安装程序?高分求救。 WinXP里怎样备份norton antivirs的升级数据? 我只是给自己加点分啦 快救救我吧,我的存储过程返回值有问题?? 日文原码想在中文环境中运行可不可能 JBoss高手看过来! 下面的js执行错误,请看看 请教高手:如何当一个程序被反复调用时利用command$? 声明游标时可否用变量? 能不能提供几个漂亮的repeater控件的模版? dbs.Execute "SELECT * INTO 在校学生 FROM [Excel 8.0;DATABASE=" & App.Path & "\MyExcel.xls].[WorkSheet1] "报错,在线等待 有没有什么工具或办法可以将Tc 下的程序移植到linux下运行? 求助! 请教!急! 世间什么才是最珍贵的? 大家來說說2003年版<射雕>的敗筆. 请教:如何在VB开发的程序中判断一个程序在硬盘上的安装路径? 帮忙!谢谢! 此类问题如何查询? 请教个问题:每次启动机器都会打开IE跳到我们这边的一个内部网站去,本来启动就慢----火死了,怎么去掉---在注册表了改么? combo控件问题. 问一个关于刚开机的win.com的问题。请高手帮帮忙呀! dbs.Execute "SELECT * INTO 在校学生 FROM [Excel 8.0;DATABASE=" & App.Path & "\MyExcel.xls].[WorkSheet1] "报错,在线等待 请问我如何在注册网站成功后,在exchange中也建立一个与注册网站时同名的帐号呢? ASP(javascript)自动回复问题?? ★★母亲的生日★★ 哪位有没有用spcomm控件进行串口通讯的例子? 大家帮我看看这是用哪个做的? 关于打印... 两路由器的使用方法比较,哪个好些? 在线求助:有没有改变电脑所连的打印机打印属性方向的API函数?多谢 我要送分 设置ejb的几个接口时,我有点弄不明白 有没有什么办法把ACCESS的表打印出来?格式改变一下? 烦啊~~~~ 谢谢!如何让对话框的大小不受屏幕分辩率的影响??? 请问怎样避免多用户同时访问数据库中的表? 简单问题:怎样用url打开一个文档?多谢 怎么控制小数的位数? 这个QQ炸弹好厉害,是什么原理呢? 我的问题怎么老是出现在这个地方。。。。 一个对话框程序调用dll中函数的问题! 请教有关类的扩展 请问WIN2000专业版IIS为什么连接限制是10 急,为什么我的数据库会出现这样的错误? 寻求一个好的全屏翻译软件(在线等候,在线给分) 是谁发现了大气压力快啊 我很急啊 家庭联产承包责任制与土地改革有什么区别麻烦告诉我 寻呼机是靠电磁波传递信息吗,影碟机了 毛细血管出血用什么办法止血 气管支气管黏膜上皮是不是分为腺上皮和纤毛上皮? 初三人教版物理十一到十五章定义书丢了,给50分饿, 1.2.说出下列各式的值(求过程 用旋光仪测糖溶液的浓度为什么让气泡位于盛液管的鼓起部位?又为什么让有鼓起部分的一端朝上? 求一些有关英语中非谓语动词的习题加解释 计算下列各式的值(写出详细的步骤) |√3+√2|+|√2-√3| 螺孔M10大径是5,那么小径是多少呢?有没有螺钉和螺孔大径和小径的公式啊. 请教一个机械制图两头对称的轴标注的问题这张图怎么标比较正规啊两侧对称中间放两个6304轴承 两头卡轴用挡圈 You'd better ___ (not go) out.It ___ (rain) hard. 大侠们,请问螺孔的大径和小径,有效长度和总长度有没有关系? 最自我安慰的成语是? You'd better not go out.It ____ (rain) soon 'c 螺孔标号5-M20,我知道20是其大径为20mm,我还想知道,槽高或牙高(也就是大径和小径的差)是多少?我是这么计算槽高的:三角槽的角度为60度,螺距(牙距)在GB4459.1里面是2.5mm,那么计算得出位1. 我想凭实力去一高上 但我英语 物理不是太理想 怎么办啊 It ___(rain) heacily outside ----You'd better not ___(go)out solidworks如何画不垂直于表面的螺孔,也就是画和基本参考平面成一角度的螺孔我自己来回答吧,呵呵,可以不要建斜面,直接用简单孔就可以了 新初三学子物理题(急)河面和海面上浮的立方体木块压强压强区别解题思路 脑部神经总是抽痛怎么回事? 如何治疗皮脂腺增生 现在感觉物理和化学很难.期中很不理想怎么办?初三在电路这就不懂了,怎么办? 为什么我的广联达绘图中独立基础的属性中没有参数化图形呢?我想画四棱台的独立基础却画不了. 肠腺是器官吗?如题,我在辅导书上看到肠腺是由上皮组织构成的,那它是不是一个器官呢? 能体现地域文化特征是【 】地域文化对城市建筑的【 】 【 】 【 】 等方面都有影响 哺乳动物的消化腺有( ) ( ) ( ) ( )等. 小肠内的内分泌细胞是绒毛,肠腺都有吗?有无主要分布区?作用呢? 地域文化对人口的影响 消化腺包括哪些 肠腺是由什么分泌的 根据意思写成语 比喻艰苦危险的处境 消化腺都各自分泌什么?能消化什么?是填空:——,能分泌——,能消化——. 腺体轻度肠化1(诊断描述:食管:黏膜光滑柔软,血管文理清晰,扩张度好.贲门:齿状线清晰,位置正常,黏膜光滑.胃底:红白相间,黏液湖色清.胃体:黏膜红白相间,以红为主,蠕动良好.:胃角 从农村、城市、某一地区经济、政治、思想、文化等领域的现状和发展趋势出发.做调 消化腺有什么作用 小肠绒毛的上皮细胞在哪里?肠腺的位置?最好根据图说明,附图. 热带地区城市多分布在哪里及原因 如何抑制皮脂腺分泌 测量未知浓度时,为何可以不考虑温度对测量结果的影响这是用旋光仪测定溶液浓度的实验 中国热带城市有哪些? 生物问题!腺上皮属于组织吗?1.具有支持,连接,保护,营养等功能的组织是?上皮 肌肉 神经 结缔组织2.人体消化食物和吸收营养物质是依靠哪一系统?呼吸 消化 运动 神经3.不是病毒的特 雷声的传播不需要介质吗?谁可以回答呢? 热带地区的城市为什么主要分布在高原上?从气候,地形等自然因素考虑 请问鸡蛋是球形吗?一年级数学判断题.谢谢!答案摸不着头绪,给个解释好吗? 我要10句排比句,快. 广联达中构件尺寸距左边线距离是什么意思? 蔗糖转化试验中可以把蔗糖倒进盐酸中吗?为什么? 腺来源于原始上皮,原始上皮是什么? 广联达钢筋算量 构件定义错误要是修改之后 怎么汇总不变 在蔗糖与盐酸反应,把盐酸加到蔗糖去,可否把蔗糖加到盐酸中去?为什么? 腺上皮分布在哪 请问为什么火车进入隧道后手机无信号? 判断题:球形可以看成圆顶形的组合.对还是错 土地改革与家庭联产承包责任制的异同不要复制知道里面一些文不对题的答案~ 马上就要期末考了,要升初三了,但是我的物理一直不好.教材是人教版新课标的在短时间内,巩固一下所学知识, 配置蔗糖和盐酸溶液时,是将将盐酸加到蔗糖中去,是否可以将蔗糖加到盐酸中? 甲状腺是被覆上皮构成还是腺上皮构成?上皮组织主要分为被覆上皮和腺上皮.甲状腺的实质由甲状腺滤泡和滤泡旁细胞组成甲状腺滤泡由单层立方上皮(被覆上皮)构成.但是甲状腺是内分泌 节能灯需要做哪些认证 东北三省史上最严重雾霾仍将持续 长春第一作者:格鲁吉亚德马尼西头骨化石价美国空军军官打盹致核导弹库防护门曾多斯里兰卡一化工厂发生毒气泄漏导致72加拿大卡尔加里市长胜选连任 笃信伊斯美国首家厕所主题餐厅开业 真马桶上阵外媒:日本也流行“土豪金”苹果发布新款平板电脑iPad Air日本猫站长阿玉担任“粉红丝带”宣传大浙江温州一在建祠堂坍塌致7人受伤浙江海事局下放海员证和油污保险证办理浙江省新增1例人感染H7N9禽流感病云南晋宁传唤嫌犯引发群体性事件 多名荷兰针对俄扣押其破冰船向国际法庭提起50多个国家将参加第五届外洽会吸引中日网上传视频主张独岛主权 韩国敦促日东盟各国持续热议中国与东盟合作前景美加州大学戴维斯分校打造奢华宿舍吸引温州将建10条BRT 3条线路近期先中石油与俄油气公司签署LNG购销协议星巴克回应售价质疑 称在中国利润不比新华国际时评:行动铸就中非黄金般情谊深圳队摘粤“省长杯”青少年足球联赛女中日女排队伍抵达澳门备战澳门站大奖赛云南鲁甸地震灾区:一个消防军嫂给救灾[鲁甸6.5级地震]废墟上的坚守福建莆田市委书记梁建勇转任龙岩市委书杭州老牌百货淡季出新招:史上最大规模马英九:台湾无法回避两岸经贸合作《和平的眉角》等一批两岸关系研究新作拉丹遗言:ISIS太狠!别惹 损害“王毅会见缅甸联邦议会议长兼人民院议长杭州“清三河”成效显著 后横港河清澈食药监总局:9-10月将严查校园及周深足预备队首发11人3门将 2人客串河北专项整治违法排污企业 以渗坑排查“寻找最美城镇”走进浙江 四城市获“杨洁篪会见白俄罗斯青少年来华疗养团老婆打掩护老公伸黑手 “雌雄大盗”双伊总统指派总理候选人海德尔·阿巴迪组中国使馆推出赴荷旅游行为指南受好评王毅与缅甸外长举行会谈
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘