网易杭州 - 前端技术部
component , widget , module , plugin ...etc
"A component in the Unified Modeling Language represents a modular part of a system, that encapsulates its content and whose manifestation is replaceable within its environment. A component defines its behavior in terms of provided and required interfaces"
$( ".selector" ).tabs( "option", "show", { effect: "blind", duration: 800 });
var tb = p._$$Tab._$allocate({ list: e._$getChildren( e._$get('box')), index:1, onchange:function(_event){ } }); tb._$go(2);
YUI().use('tabview', function(Y) { var tabview = new Y.TabView({ children: [{ label: 'foo', content: '<p>foo content</p>' }, { label: 'bar', content: '<p>bar content</p>' }, { label: 'baz', content: '<p>baz content</p>' }] }); tabview.render('#demo'); });
2011年,由Alex Russell提出
Custom Element: 自定义HTML元素
shadow DOM: 封装
HTML Imports: 打包一切
HTML Template: Lazy的DOM模板
<x-foo> Custom Elememnt </x-foo>
var xFoo = document.createElement('x-foo');
var XFooProto = Object.create(HTMLElement.prototype); // 生命周期相关 XFooProto.readyCallback = function() { this.textContent = "I'm an x-foo!"; }; // 设置 JS 方法 XFooProto.foo = function() { alert('foo() called'); }; var XFoo = document.register('x-foo', {prototype: XFooProto});
Your user agent does not support the HTML5 Video element.
DevTool > Settings > General> show shadow DOM
<div><h3>Light DOM</h3></div> <script> var node = document.querySelector('div'); var root = node.createShadowRoot(); root.innerHTML = '<style>h3{ color: red; }</style>' + '<h3> h3 in shadowRoot </h3>'; </script》
var tabPane = document.createElement('tab-pane'); tabPane.setAttribute('title', 'hello'); tabPane.setAttribute('content', 'hello'); tab.appendChild(tabPane);
tabs.push({ title: 'hello', content: 'hello' })
<pagination current={current} total={maxCount/20} on-nav={this.nav(1)}></pagination> <pagination current={current} total={maxCount/20} on-nav={this.nav(2)}></pagination>
<bootstrap-pagination id='pagination'></bootstrap-pagination> <script> // 获取元素 var pagination = document.querySelector('#pagination'); // 绑定事件 pagination.addEventListener('pagination-nav', function(event){ // blablablabal }) // 设置属性 $.ajax('/blogs').then(function( json ){ pagination.setAttribute('current', 0) pagination.setAttribute('total', json.length / 20) }) </script》
"是数据驱动允许将两个组件通过声明式编程建立内在联系"
Data-Driven是因(gong)
Declarative是果(shou)
"Foundation 与 Framework 职责是不同的"
答案是 ......
{%if login %} <h2>{{user.name}} </h2> {% endif %}
{ login: true, user: { name: '@leeluolee' } }
<h2>@leeluolee</h2>
Simple Usage ( compile + render )
Natrual Isomorphic( 100% dom 无关 )
Powerful Syntax
100% Stateless "v=f(d)"
"High Performance"
Hidden danger ( XSS, invalid tag... etc )
100% Stateless (??)
"Low Performance" (???!)
A proposal for extending HTML and the DOM APIs to support a sensible separation between the UI (DOM) of a document or application and its underlying data (model). Updates to the model are reflected in the DOM and user input into the DOM is immediately assigned to the model
from Google
<link rel="import" href="bower_components/polymer/polymer.html"> <!-- import the iron-input custom element --> <link rel="import" href="bower_components/iron-input/iron-input.html"> <dom-module id="editable-name-tag"> <template> <p> This is a <strong>{{owner}}</strong>'s editable-name-tag. </p> <!-- iron-input exposes a two-way bindable input value --> <input is="iron-input" bind-value="{{owner}}" placeholder="Your name here..."> </template> <script> Polymer({ is: "editable-name-tag", properties: { owner: { type: String, value: "Daniel" } } }); </script》 </dom-module>
"I definitely think it’s the wrong programming paradigm. I really hope that [web components] do not succeed"
from Pete Hunt
Foudation ( React Native, Flux, Immutable.js..etc)
Community ( 3w+ stars , 5000+ issues )
Size... ( 40kb Gzip & without JSX )
The next generation JavaScript language that will kill ALL the frameworks!
Create data-driven Components based on Living Template
<div class='example-container'> <pophover title='pophover title' placement='bottom'> pophover content </pophover> </div>
let pophover = new Pophover({ data: { title: 'pophover title', placement: 'bottom' }, $body: 'pophover content' }).$inject('.example-container')
Safe
20KB(Gzip)
Living Template( String-based + Dom-based )
Dirty Check(性能?)
Composite Component( != 标签化 )
Fully Tested( IE6+ )
Widely Used in 我厂( 网易杭州 )
将Component 转化为真正的Custom Element !!
与具体框架无关
组件化前, 共处一个Context
组件化后, 灵活性降低,分处于不同Context,通过事件和Data Flow维系
Non Visual: 只有业务逻辑,没有View
Visual: 业务逻辑 + View
Non Visual Component is Easy ,Visual Component is Hard
A + B = AB
属于无序列表的li元素
<ul class="pagination"> <li><a href="">Prev</a></li> <li><a href="">1</a></li> <li><a href="">...</a></li> <li><a href="">10</a></li> <li><a href="">Next</a></li> </ul>
属于有序列表的li元素
<ol class="rank"> <li><a href="">1</a></li> <li><a href="">2</a></li> <li><a href="">3</a></li> <li><a href="">4</a></li> <li><a href="">5</a></li> </ol>
<dropdown-button title='向上的箭头' style=success dropup on-select={}> <select-item header>我是标题</select-item> <select-item><span class='icon'></span>我是列表项1</select-item> <select-item divider /> <select-item disabled>我是禁止的</select-item> <select-item>我是列表项2</select-item> <select-item divider /> <select-item>我是列表项3</select-item> </dropdown-button>
<modal title='筛选器'> <tab> <tab.pane title='列表筛选' selected> <text-search select={select} ref=list ></text-search> </tab.pane> <tab.pane title='文本筛选' > <text-filter match ={match} ref=text ></text-filter> </tab.pane> <tab.pane title='条件筛选' > <condition-filter condition={condition} measures={measures} ref=condition ></condition-filter> </tab.pane> <tab.pane title='高级筛选' > <advanced-filter top={top} measures={measures} ref=advanced ></advanced-filter> </tab.pane> </tab> </modal>
<div class="item {mark.labels.length? 'z-act':''}"> <dropable name='mark.labels' direct=y on-toucheddrop={this.drop('mark.labels', $event)} > <div class="box"> {#list mark.labels as lpill} <dragable target={TARGET_PILL} on-dragend='dragend' > <pill pill={lpill} index={lpill_index} isolate = 1 /> </dragable> {/list} </div> </dropable> </div>
瞬间被后浪排死在沙滩的前浪
import { createStore } from 'redux'; // reducer function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1; case 'DECREMENT': return state - 1; default: return state; } } // Its API is { subscribe, dispatch, getState }. let store = createStore(counter); // You can subscribe to the updates manually, or use bindings to your view layer. store.subscribe(() => console.log(store.getState()) ); store.dispatch({ type: 'INCREMENT' });
从数据类型、Mutation、数据源、Data-Flow保证了状态本身的可预测性(predictable)
JS中的Object,Array等是可变数据结构
var a = {selected: true, content: 'hello'}; // action 1 a.selected = false; // action 2 a.selected = true; a === a;
往往你在调试action 1时, 数据已经被action 2改变
var a = {selected: true, content: 'hello'}; // action1 var a1 = Object.assign({}, a , { selected: true }) a !== a1
特别适合基于Pull流程(脏检查)的View层框架
var ReduxMixin = { events: { $config: function(){ store.subcribe( function(){ this.mapStateToData( store.getState(), this.data); this.$update()// 触发脏检查 }.bind(this) ) } }, mapStateToData: function(){ throw Error('You need implement mapStateToData') } } ReportApp.implement( ReduxApp );