Ques是一套组件化系统,解决如何定义、嵌套、扩展、使用组件。

传统开发模式的痛点

  • 无法方便的引用一个组件,需要分别引用其JavascriptTemplateCSS文件
  • 我们期望能以MV*的方式去写代码,结果发现只有JavascriptMV*
  • UI库打包成一坨(类似Bootstrap),但是实际上UI库伴随产品迭代在反复变更,每次打开网站,用户依然反复下载UI库
  • CSS没有命名空间导致两个组件容易冲突
  • 组件无法嵌套或者无法扩展,所以实际上组件根本无法复用
  • 组件无法复制后可用,在组件无法嵌套或无法扩展的情况下,连定制一个组件都困难连连
  • 每次性能优化都将代码弄的很恶心,不好维护

UI组件

UI组件使用来专门做UI的组件,其特点为只有模版、样式文件。系统会根据用户在页面已使用的UI组件动态引用其依赖的资源。注意,UI组件的前缀必须是ui-

下面是一个简单的ui-button的例子:

定义
  • CSS文件
.ui-button {display: inline-block;padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: 400; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; touch-action: manipulation; cursor: pointer; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 4px; text-transform: none; -webkit-appearance: button; overflow: visible; margin: 0; } .ui-default { color:#333; background-color:#fff; border-color:#ccc } .ui-default.focus,.ui-default:focus { color:#333; background-color:#e6e6e6; border-color:#8c8c8c } .ui-default:hover { color:#333; background-color:#e6e6e6; border-color:#adadad } // 后面可添加更多样式的按钮

  • 模版文件
<button class="ui-button"><content></content> </button>

效果
  • 在页面上直接引用:
<ui-button class="ui-default">DEFAULT</ui-button> <ui-button class="ui-success">SUCCESS</ui-button> <ui-button class="ui-info">INFO</ui-button> <ui-button class="ui-warning">WARNING</ui-button> <ui-button class="ui-danger">DANGER</ui-button>

  • 展示

这样我们就实现了一个ui-button组件,其可以在任意其他组件中嵌套使用。其以来的资源会动态引用,也就是说,只有我们使用了ui-button他的模版和样式才会被引入。

备注
  • 由于我们使用了强大的cssnext,所以CSS吐出来的时候会根据配置转换成兼容版本,也就是说我们只需要按照标准去写CSS,系统会自动帮我们适配:
.ui-button {display: inline-block;padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: 400; line-height: 1.42857143; text-align: center; white-space: nowrap; vertical-align: middle; -ms-touch-action: manipulation; touch-action: manipulation; cursor: pointer; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; background-image: none; border: 1px solid transparent; border-radius: 4px; text-transform: none; -webkit-appearance: button; overflow: visible; margin: 0; } .ui-default { color:#333; background-color:#fff; border-color:#ccc } .ui-default.focus,.ui-default:focus { color:#333; background-color:#e6e6e6; border-color:#8c8c8c } .ui-default:hover { color:#333; background-color:#e6e6e6; border-color:#adadad }

  • 注意到我们引用了Shadow DOM中的<content>标签,<content>标签作为Component内部的插入点(或者可以理解成占位符),当外部引用该Component时可以从外部向内部插入节点,例如:
<ui-button class="ui-default">DEFAULT</ui-button>

则表示向Component的插入点插入DEFAULT这个文字节点。关于<content>标签我们后面还会提到其高级应用。

Component

Component是最常见的组件,其拥有模版、样式以及逻辑文件,使得这种Component更像一个自定义的元素(Custom Element)。体验上像引入一个<input>标签一样,我们可以设置她的值,绑定她的事件,调用她的函数。

下面是一个dialog组件的例子:

定义
  • CSS文件:
.$__mask {position: fixed;width: 100%;height: 100%; padding: 0px; margin: 0px; left: 0px; top: 0px; z-index: 999; background-color: rgba(0,0,0,.6) !important; display: none; } .$__mask.show { display: block; } .$__$ { position: fixed; top: 10%; opacity: .5; left: 50%; width: 490px; margin-left: -245px; z-index: 999; background: #fff; font-size: 14px; border-radius: 4px; overflow: hidden; transition: all 200ms ease-in-out; } .$__mask .$__$.show { top: 50%; opacity: 1; } .$__$ .header { height: 30px; line-height: 30px; text-indent: 12px; background: #039ae3; color: #fff; font-size: 14px; } .$__$ .body { padding: 30px 40px; position: relative; line-height: 24px; max-height: 500px; overflow-y: auto; overflow-x: hidden; } .$__$ .msg { margin-left: 66px; position: relative; top: 10px; word-break: break-all; } .$__$ .bottom { margin: 20px; text-align: right; } .icon-info-large { background: url(http://9.url.cn/edu/img/sprite/common.a8642.png) -41px -276px no-repeat; width: 36px; height: 36px; display: block; float: left; margin-top: 4px; }

  • 模版文件:
<div class="$__mask" q-class="show: isShow"> <div class="$__$"> <div class="header"> <content select="header *"></content> </div> <div class="body"> <div class="icon-info-large"></div> <div class="msg"> <content select="article *"></content> </div> </div> <div class="bottom"> <ui-button class="ui-info" q-on="click: submit">确定</ui-button> <ui-button class="ui-default" q-on="click: cancel">取消</ui-button> </div> </div> </div>

  • Javascript文件:
var $ = require('jquery'); module.exports = { data: { isShow: false }, methods: { submit: function () { this.$emit('submit'); }, cancel: function () { this.$emit('cancel') .hide(); }, show: function () { this.$set('isShow', true); }, hide: function () { this.$set('isShow', false); } }, ready: function () { var dialog = $('.$__$', this.$el); this.$watch('isShow', function (val) { if (val) { setTimeout(function () { dialog.addClass('show'); }, 20); } else { dialog.removeClass(dialog, 'show'); } }, false, true); } }

效果
  • 在页面直接引入<dialog>
<dialog id="my-dialog"><header> 欢迎使用Ques </header> <article> Hello World! </article> </dialog>

  • 则可以在Controller中直接使用,例如拿到其实例,再调用其show方法,将其展示:
var Q = require('Q'); Q.get('#my-dialog') .show();

  • 展示

备注
  • 由于CSS没有命名空间,所以我们引入了两个$__$__$两个占位符来充当命名空间,系统会自动转换成当前Component的名字,所以CSS最终变成:
.dialog__mask {position: fixed;width: 100%; height: 100%; padding: 0px; margin: 0px; left: 0px; top: 0px; z-index: 999; background-color: #000000 !important; background-color: rgba(0,0,0,.6) !important; display: none; } .dialog__mask.show { display: block; } .dialog { position: fixed; top: 10%; opacity: .5; left: 50%; width: 490px; margin-left: -245px; z-index: 999; background: #fff; font-size: 14px; border-radius: 4px; overflow: hidden; -webkit-transition: all 200ms ease-in-out; transition: all 200ms ease-in-out; } .dialog__mask .dialog.show { top: 50%; opacity: 1; } .dialog .header { height: 30px; line-height: 30px; text-indent: 12px; background: #039ae3; color: #fff; font-size: 14px; } .dialog .body { padding: 30px 40px; position: relative; line-height: 24px; max-height: 500px; overflow-y: auto; overflow-x: hidden; } .dialog .msg { margin-left: 66px; position: relative; top: 10px; word-break: break-all; } .dialog .bottom { margin: 20px; text-align: right; } .icon-info-large { background: url(http://9.url.cn/edu/img/sprite/common.a8642.png) -41px -276px no-repeat; width: 36px; height: 36px; display: block; float: left; margin-top: 4px; }

可以看见$__被转换成了dialog__,而$__$被转换成了dialog

  • 逻辑层我们使用了MVVM库Q.js,这里就不细说了。

  • 这里还用到<content>标签的高级功能,select属性。select属性是用来选择外部符合选择器的节点进行替换。例如:

<content select="header *"></content>

的意思是选择外部<header>标签内所有东西进行替换,所以“欢迎使用Ques”就被替换进去了。

第三方Component

第三方Component是一套兼容方案,使得业务方不依赖Q.js也能定义一个Component,但是由于系统无法控制第三方组件DOM的作用域,以及实现其扩展似乎没啥意思,所以第三方无法嵌套和扩展。总的来说第三方Component本质上就是系统给第三方一个容器,他在里面干什么,系统就不管了。第三方组件一定以third-为前缀。

下面是一个高亮代码third-code的例子:

定义
  • CSS文件:
.$__pre {width: 900px;margin: 10px; } /** 引入hightlight.js的css库 **/ @import "http://cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/styles/default.min.css";

  • 模版文件:
<pre class="$__pre"><code> <content></content> </code> </pre>

  • Javascript文件:
module.exports = {bind: function () {var el = this.el, script = document.createElement('script'); script.onload = function () { hljs.highlightBlock(el); } script.src = '//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.6/highlight.min.js'; document.body.appendChild(script); }, unbind: function () {} };

效果
  • 引入third-code
<third-code>&lt;ui-button class=&quot;ui-default&quot;&gt;DEFAULT&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-success&quot;&gt;SUCCESS&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-info&quot;&gt;INFO&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-warning&quot;&gt;WARNING&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-danger&quot;&gt;DANGER&lt;/ui-button&gt; </third-code>

  • 效果:

备注
  • 第三方Component需要实现两个接口bindunbind,即在容器创建时需要绑定什么,当容器删除时需要解绑什么。this会带来必要的东西,例如容器、父级ViewModel等等。

组件嵌套

当组件可以嵌套,组件件可以拆成较小的颗粒,使得复用性大大提升。

下面我们是一个codeclick组件,其用途是高亮展示代码片段,点击代码弹出dialog,也就是说我们准备嵌套上面做出来的third-codedialog组件:

定义
  • CSS文件:
/** 可以给组件定义一些特殊样式,但为了简单我们什么也不做 **/

  • 模版文件:
<div><third-code q-ref="code"><content></content></third-code><dialog q-ref="dialog"><header>欢迎使用Ques</header><article>你点击了代码</article></dialog>
</div>
  • Javascript文件:
var $ = require('jquery'); module.exports = { data: {}, ready: function () { var code = this.$.code, dialog = this.$.dialog; // 点击代码,弹出dialog $(code.el).on('click', function () { dialog.show(); }); } };

效果
  • 在页面上引用:
<codeclick>&lt;ui-button class=&quot;ui-default&quot;&gt;DEFAULT&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-success&quot;&gt;SUCCESS&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-info&quot;&gt;INFO&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-warning&quot;&gt;WARNING&lt;/ui-button&gt; &lt;ui-button class=&quot;ui-danger&quot;&gt;DANGER&lt;/ui-button&gt; </codeclick>

  • 展示:

备注
  • 我们看到<content>标签另一个神奇的用法是可传递,我们从third-code传递到codeclick,再传递到最外部。使得我们可以在最外部改third-code内部的节点。

  • 我们注意到q-ref本来是Q.js用于组件嵌套从母Component(为了和扩展中的父Component其分开来,这里称之为母Component)拿到子Component的引用,同样可以拿到第三方Component的引用。

组件扩展

组件可扩展,则差别不大的组件可以继承同一个父组件。

下面dialog组件扩展的例子,效果是弹出一个dialog,要求输入内容:

定义
  • CSS文件:
/** 同样为了简单我们什么也不做 **/

  • 模版文件:
<dialog extend><header><h2>欢迎使用Ques</h2></header> <article> <p>请输入要设置的值</p> <ui-input value="" q-model="curVal" q-on="keyup: submit | key enter" q-focus="focus"></ui-input> </article> </dialog>

  • Javascript文件:
var filters = require('filters'); module.exports = { methods: { submit: function () { if (!this.curVal) { this.$set('focus', true); } else { this.$emit('submit', this.curVal); this.$set('curVal', ''); this.hide(); } }, show: function () { // call super.show this.constructor.super.options.methods.show.call(this); this.$set('focus', true); } }, directives: { focus: function (val) { val && this.el.focus(); } }, filters: { key: filters.key } };

效果
  • 在页面上引用inputval
<inputval id="my-dialog"></inputval>

  • 在Controller调用其show方法:
var Q = require('Q'); Q.get('#my-dialog').show();

  • 则页面弹出一个弹出,要求输入值:

备注
  • 这里我们引入extend属性,用于表示该组件继承哪个组件。

  • 我们还复写了dialogsubmitshow方法,并且可以调用其父Componnet的方法,如:

this.constructor.super.options.methods.show.call(this);

嵌套使用扩展组件

我们可以嵌套使用扩展后的组件。

下面是一个复杂的例子,一个按钮点击后弹出inputval,输入后alert出输入的内容。

定义
  • CSS文件
.$__anchor {padding: 13px 35px 17px;box-shadow: inset 0 -4px 0 #2a6496;border: 0;color: #fff;transition: all .2s ease-in-out;background-color: #337ab7;border-color: #2e6da4;display: block;margin-bottom: 0;font-size: 14px;font-weight: 400;line-height: 1.42857143;text-align: center;white-space: nowrap;vertical-align: middle;touch-action: manipulation;cursor: pointer;user-select: none;border-radius: 4px;text-decoration: none;margin: 0 auto;
}.$__anchor:hover,
.$__anchor:active
.$__anchor:focus {background-color: #286090;border-color: #204d74;
}
  • 模版文件:
<div><a href="javascript:void(0);" class="$__anchor" q-on="click: setMessage"> <content></content> </a> <inputval q-ref="input"></inputval> </div>

  • Javascript文件:
module.exports = {data: {},methods: {setMessage: function (e) { var self = this; this.$.input.$once('submit', function (value) { value && alert('输入了:' + value); }); this.$.input.show(); } } };

效果
  • 在页面引用:
<clkme>请点击我</clkme>

  • 效果:

DIY组件

DIY组件允许页面通过Markup的方法引用NodeJS组件,这样我们可以使用该NodeJS组件分析我们的代码来做一些神奇的事情。

例如我们提供的diy-preload组件提供的CGI预加载方案,整个过程没有改变开发人员的编码体验,只是简简单单标记一下哪个CGI需要预加载,则系统会自动预加载CGI。

使用
  • 在页面引入diy-preload组件
<diy-preload></diy-preload>

  • 在页面对应的数据层配置文件,这里我们的规范是该文件名为db.*.js,的对应CGI设置成preload = true:
    var DB = require('db'); DB.extend({ ke: DB.httpMethod({ url: 'http://ke.qq.com/cgi-bin/index_json', type: 'JSONP', preload: true }) }) module.exports = DB;

  • diy-preload组件会找到db.*.js,然后分析出什么CGI需要预加载,在<diy-preload>标签对应的位置插入预加载脚本。整个过程开发人员感知不到,体验上还是调取一个CGI,但是实际上在页面文档打开后CGI请求立刻发出,而不是等待Javascript加载完后才发出。

转载于:https://www.cnblogs.com/justany/p/4660228.html

Ques前端组件化体系相关推荐

  1. 技术期刊 · 路尘终见泰山平 | 微前端及插件化架构在 Wix 的实践;编辑器架构的第二路径;业务中的前端组件化体系……

    蒲公英 · JELLY技术期刊 Vol.47 不想当架构师的程序员不是"合格"的程序员?这一类的言论在很多文章中应该很常见吧,我们需要架构思维,要有抽象能力,要学会分层--需要的太 ...

  2. 「前端组件化」该怎么理解?

    大家好,我是若川.今天分享一篇关于「前端组件化」的好文.欢迎点击下方卡片关注我. 以下是正文~ 这里我们一起来学习前端组件化的知识,而组件化在前端架构里面是最重要的一个部分. 讲到前端架构,其实前端架 ...

  3. 前端面试题,前端组件化、工程化、模块化的概念

    1.前端模块化: 可以理解为一组自定义业务的抽象封装,是根据项目的情况来进行封装组合到一起的,比如我们可以分为登录模块,评论模块.模块可维护性好,组合灵活,方便调用,多人协作互不干扰. 2.前端组件化 ...

  4. 用 JavaScript 实现手势库 — 事件派发与 Flick 事件【前端组件化】

    前端<组件化系列>目录 「一」用 JSX 建立组件 Parser(解析器) 「二」使用 JSX 建立 Markup 组件风格 「三」用 JSX 实现 Carousel 轮播组件 「四」用 ...

  5. 前端组件化的实施方案

    常规系统开发流程 一个典型的系统,它的开发过程可能是这样的: 前端独立系统 后端独立系统 中间有类似 swagger 的接口约定机制 缺点: 形成这个问题的原因是整个研发过程两极分化,断裂得很厉害,前 ...

  6. 如何通过 Vue+Webpack 来做通用的前端组件化架构设计

    目录:   1. 架构选型     2. 架构目录介绍     3. 架构说明     4. 招聘消息 目前如果要说比较流行的前端架构哪家强,屈指可数:reactjs.angularjs.emberj ...

  7. 组件化开发实战_一篇文章搞懂什么是前端“组件化”开发

    学过网页的朋友都知道,制作一个网页离不开HTML.CSS和JavaScript技术.对于初学者来来说,掌握这3门技术就已经很不容易了,为什么前端为什么又要搞出来一个"组件化"开发的 ...

  8. 前端组件化-抽象公共组件类

    优化上次的组件化小demo 上次的组件化demo只是为了简单的实现前端组件化的思想,这次我们稍微优化一下抽离公共类 下面代码 html <div id="wrapper"&g ...

  9. 前端组件化和模块化最大的区别是什么_7招提升你的前端开发效率

    前言 前端工程师其实是一个工作很杂的职位,除了要负责切图.写html/css/js外,还要解决一系列的浏览器兼容性.网页性能优化等问题,所以提高前端工程师的开发效率是势在必行的,也是前端工程化的体现. ...

  10. React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起

    React.js 小书 Lesson1-2 - 前端组件化(一):从一个简单的例子讲起 本文作者:胡子大哈 本文原文:http://huziketang.com/books/react/lesson2 ...

最新文章

  1. python gevent
  2. Python脚本文件和函数的基本运用
  3. Xcode12快捷键配置
  4. 关于工作的选择之软件开发还是软件维护的建议
  5. HDU 1525 类Bash博弈
  6. java常用类的特征_Java常用类-包装类
  7. windows 7 精彩新功能
  8. 【电路仿真】基于matlab GUI Simulink钟摆自由控制【含Matlab源码 991期】
  9. tomcat 如何查看tomcat版本及位数
  10. 新手如何使用JavaScript读取json文件
  11. 在线点餐系统的测试用例
  12. 计算机专业科研经费排名2015,2017中国大学科研经费排名
  13. win10系统 双击bat文件无法运行,只是以普通txt文件打开该文件,简单解决
  14. 记一次 “HTTP 405 Method Not Allowed”的解决方法
  15. python编写回文程序上海自来水来自海_2019春Python程序设计练习3(0402--0408)
  16. ZigBee Routing Tables 路由表
  17. Python之axis函数
  18. CSS3 2D转换3D转换
  19. Linux内核引导选项
  20. OSD的主要实现方法和类型

热门文章

  1. 修改macOS中鼠标滚轮方向
  2. 大数据架构之-- Lambda架构
  3. EXCEL表格复制到空白的EXCEL表格变形 解决方法
  4. 关于响应式布局,你必须要知道的
  5. android录屏存在什么位置,安卓视频录制在哪里
  6. ORACLE 行转列谓词推入
  7. python中怎么调用函数_python怎样调用函数
  8. 关于sip软电话嵌入到网页web端的学习----第一天(2)(高手指点)遇到问题了jssip
  9. Java与数据结构——树(一)
  10. solr配置索引库启动tomcat报错记录及解决