组件化

组件介绍

组件由模板+模块组成. 模板使用.html结尾, 模块使用.js结尾, 我们推荐默认使用路径名作为组件的名称.

*组件有3种表现形式: *

  1. 通过bui.load跳转的页面组件;
  2. 通过component标签加载的局部组件;
  3. 通过bui.page弹窗加载组件;

BUI版本1.6.0以上的版本才有这些功能.

组件特点

  • 自执行
  • 独立作用域
  • 生命周期
  • 封闭或开放

BUI的组件加载后是一条线, 虽然组件允许相互嵌套, 我们并不建议把页面拆的太过零散. 加载以后的组件依然在一条线上操作. 页面可以看成是一个大的组件, 页面组件可以加载 component 组件, 也可以加载 page 组件. 线的末端可以操控前面的页面.

例如: 路由从A跳转到B再到C, C除了可以操作当前页面的component1,component2,还可以操作B,跟A,以及A下面的component, 链接起来就是一条线. C的component也可以操控B的component1及component2 或C,A,B 等. 底下的组件交互案例会有详细说明.

  1. 单页路由跳转路线
  2. main--------->页面A--------->页面B------------>页面C
  3. | | |
  4. | | |
  5. Acomponent1 Bcomponent1 Ccomponent1
  6. | | |
  7. | | |
  8. Acomponent2 Bcomponent2 Ccomponent2

组件标签

使用component作为组件的加载标签, 跟view标签的区别在于, view标签只加载了模板, component标签是加载了模板并执行了相同文件名的js.

例如: 局部加载一个 pages/components/slide 组件. 默认路径名便是组件名, 另外 "/pages/xxx""pages/xxx" 是不同的, 为了确保在webapp,打包都能正确加载, 包括路由的路径,图片的路径,script引入的路径等, 都应该使用 "pages/xxx" 之类的写法.

  1. <component name="pages/components/slide"></component>

组件属性

component有3个内置的属性. 支持自定义属性, 具体查看组件的传参.

  • name="xxx" 模块名.
  • render="true" 代表已经渲染结束,不会再次渲染.
  • delay="true" 代表暂时不加载,直到调用 loader.delay方法. 查看组件的延迟加载

自定义组件

例如: pages目录下有一个slide.html slide.js, 那么该组件的名称为 pages/slide;

模板: pages/slide.html

  1. <div id="uiSlide" class="bui-slide"></div>

模块: pages/slide.js

  1. // 定义一个模块
  2. loader.define(function(require,exports,module){
  3. // 轮播图控件初始化
  4. var uiSlide = bui.slide({
  5. id: "#uiSlide",
  6. height: 380,
  7. autopage: true,
  8. data: [{
  9. image: "images/banner01.png",
  10. url: "pages/ui_controls/bui.slide_title.html",
  11. },{
  12. image: "images/banner02.png",
  13. url: "pages/ui_controls/bui.slide_title.html",
  14. }]
  15. })
  16. })

自定义的组件如何被加载进页面呢? 我们把快速开始的例子改写一下.

  1. <div class="bui-page bui-box-vertical">
  2. <!-- 固定顶部区 -->
  3. <header>
  4. <div class="bui-bar">
  5. <div class="bui-bar-left">
  6. <a class="bui-btn"><i class="icon-back"></i></a>
  7. </div>
  8. <div class="bui-bar-main">BUI标准页面</div>
  9. <div class="bui-bar-right"></div>
  10. </div>
  11. </header>
  12. <main>
  13. <!-- name 默认是路径名 -->
  14. <component name="pages/slide"></component>
  15. <!-- 如果需要复用,内部的初始化还需要改改 -->
  16. <component name="pages/slide"></component>
  17. </main>
  18. <footer>
  19. <!-- 固定底部区 -->
  20. </footer>
  21. </div>

组件复用

如果当前组件要被同一个页面多次复用, 那组件的js还需要改改.

模块: pages/slide.js

  1. // 定义一个模块
  2. loader.define(function(require,exports,module){
  3. // module.id 如果component没有id则随机生成, 通过外层component生成的id 来区分不同的控件slide
  4. var uiSlide = bui.slide({
  5. id: `#${module.id} .bui-slide`,
  6. height: 380,
  7. autopage: true,
  8. data: [{
  9. image: "images/banner01.png",
  10. url: "pages/ui_controls/bui.slide_title.html",
  11. },{
  12. image: "images/banner02.png",
  13. url: "pages/ui_controls/bui.slide_title.html",
  14. }]
  15. })
  16. })

组件传参

组件内部需要通过不同参数来区分不同的控件, 比方新闻轮播图,图片轮播图,视频轮播图. type是自定义属性.

  1. <!-- 新闻轮播图 -->
  2. <component name="pages/slide" type="news"></component>
  3. <!-- 图片轮播图 -->
  4. <component name="pages/slide" type="photo"></component>
  5. <!-- 视频轮播图 -->
  6. <component name="pages/slide" type="video"></component>

组件接收参数

在内部通过 bui.history.getParams(module.id)来获取. 所有属性的参数都会被拿到.

模块: pages/slide.js

  1. // 定义一个模块
  2. loader.define(function(require,exports,module){
  3. // 通过模块的id来获取不同的参数, 所有属性的参数都会被拿到.
  4. var params = bui.history.getParams(module.id);
  5. // 区分不同的接口
  6. var url = "http://localhost/api/"+params.type;
  7. // module.id 如果component没有id则随机生成, 通过外层component生成的id 来区分不同的控件slide
  8. var uiSlide = bui.slide({
  9. id: `#${module.id} .bui-slide`,
  10. height: 380,
  11. autopage: true,
  12. data: []
  13. })
  14. // 请求数据后渲染
  15. bui.ajax({
  16. url:url,
  17. success: function(res){
  18. // 测试数据
  19. res = [{
  20. image: "images/banner01.png",
  21. url: "pages/ui_controls/bui.slide_title.html",
  22. },{
  23. image: "images/banner02.png",
  24. url: "pages/ui_controls/bui.slide_title.html",
  25. }]
  26. // 修改轮播图的数据
  27. uiSlide.option("data",res);
  28. }
  29. })
  30. })

组件延迟加载

常用于tab的按需加载. 第1个新闻轮播图的 component会由路由去编译, 有delay="true"属性则不编译.

例子:

pages/tab.html

  1. <div id="uiTab" class="bui-tab">
  2. <div class="bui-tab-head">
  3. <ul class="bui-nav">
  4. <li class="bui-btn">新闻</li>
  5. <li class="bui-btn">图片</li>
  6. <li class="bui-btn">视频</li>
  7. </ul>
  8. </div>
  9. <div class="bui-tab-main">
  10. <ul>
  11. <li>
  12. <!-- 新闻轮播图 默认编译 -->
  13. <component id="tab0" name="pages/slide" type="news"></component>
  14. </li>
  15. <li style="display: none;">
  16. <!-- 图片轮播图延迟 暂不编译 -->
  17. <component id="tab1" name="pages/slide" type="photo" delay="true"></component>
  18. </li>
  19. <li style="display: none;">
  20. <!-- 视频轮播图延迟 暂不编译 -->
  21. <component id="tab2" name="pages/slide" type="video" delay="true"></component>
  22. </li>
  23. </ul>
  24. </div>
  25. </div>

pages/tab.js

tab有多种操作跳转,滑动,点击,都会触发to事件.

  1. // 定义一个模块
  2. loader.define(function(require,exports,module){
  3. var uiTab = bui.tab({
  4. id:"#uiTab"
  5. })
  6. // tab有多种操作跳转,滑动,点击,都会触发to事件, 在这里拿到对应的索引, 执行加载.
  7. uiTab.on("to",function(){
  8. var index = this.index();
  9. // 加载delay属性的组件
  10. loader.delay({
  11. id:`#tab${index}`
  12. })
  13. })
  14. })

预览效果

组件编译

component 默认是由 router 跳转时进行编译, 如果需要手动编译, 比方延迟加载,我们使用 loader.delay 方法, 只编译有delay属性的 component, 没有delay属性的编译呢? 有以下3种方法.

1. 编译一个: loader.component

  1. <component id="tab0" name="pages/slide"></component>
  1. // 调用一次编译一次
  2. loader.component({
  3. id:"#tab0"
  4. })

2. 编译多个: loader.components

  1. <div id="tabs">
  2. <component name="pages/slide"></component>
  3. <component name="pages/slide"></component>
  4. </div>
  1. // 编译tabs 下面的2个component
  2. loader.components({
  3. id:"#tabs"
  4. })

3. 动态编译: loader.load

component的区别便是它可以把任意一个组件加载到某个容器下.

  1. <component id="slide"></component>
  1. loader.load({
  2. id: "#slide",
  3. url: "pages/slide.html"
  4. })

组件全局方法

npm run build 在新的工程执行这个命令以后, js 文件全部变成了闭包, 原本你的var 声明的全局变量, 变成了局部变量, 控制面板会抛出一堆错误. 如果有这个情况, 建议及早处理. 在1.6.2版本. 使用 loader.global() 来定义全局方法.

例子:

js/common.js

  1. // 定义全局方法
  2. loader.global(function(global){
  3. return {
  4. config: {},
  5. getDate: function(){
  6. console.log("获取日期")
  7. }
  8. }
  9. })

全局使用

  1. bui.ready(function(){
  2. // 全局调用
  3. loader.globals.getDate();
  4. })

模块里面调用, 新增第4个参数.

  1. loader.define(function(require,exports,module,global){
  2. // 全局调用
  3. global.getDate();
  4. })

综合案例

最新安装了buijs的开发者, 可以使用以下命令, 创建一个更加复杂的163 component示例.

  1. buijs create 163 -t case-163

163新闻