Authored by 陈轩

Merge remote-tracking branch 'origin/develop' into develop

... ... @@ -5,7 +5,6 @@
*/
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
/**
... ...
... ... @@ -27,6 +27,7 @@ iconfont 新建项目,使用 class 控制图标样式,不要用 unicode<br>
<h2>button</h2>
三种尺寸,圆角直角,实心空心<br>
设计图尺寸太多,不统一,用的时候自己改一下大小<br>
<button class="button">空心</button>
<button class="button button-solid">实心</button>
... ... @@ -114,16 +115,26 @@ iconfont 新建项目,使用 class 控制图标样式,不要用 unicode<br>
<h2>loading</h2>
可以控制显示,隐藏
<p>
<a href="javascript:void(0);" id="loading">显示</a>
</p>
<h2>modal</h2>
支持 一个按钮,两个按钮,多个按钮
每个按钮支持自定义事件
<p>
<a href="javascript:void(0);" id="modal-overlay">显示覆盖层</a>
<a href="javascript:void(0);" id="modal-alert">Alert</a>
<a href="javascript:void(0);" id="modal-confirm">Confirm</a>
<a href="javascript:void(0);" id="modal-custom">自定义</a>
</p>
<h2>Vue 示例(大展示,使用新路由)</h2>
<div id="app">
<app></app>
<app></app>
</div>
<h2>Handlebars 示例</h2>
... ...
/**
* 主页
* @author: Bi Kai<kai.bi@yoho.cn>
* @date: 2016/05/09
*/
'use strict';
const _ = require('lodash');
const helpers = global.yoho.helpers;
/**
* 频道选择页
*/
const component = {
index: (req, res, next) => {
res.render('index', {
module: 'example',
page: 'home'
});
}
};
module.exports = component;
... ...
/**
* sub app home
* @author: shenzm<zhimin.shen@yoho.cn>
* @date: 2016/07/18
*/
var express = require('express'),
path = require('path'),
hbs = require('express-handlebars');
var app = express();
// set view engin
var doraemon = path.join(__dirname, '../../doraemon/views'); //parent view root
app.on('mount', function(parent) {
delete parent.locals.settings; // 不继承父 App 的设置
Object.assign(app.locals, parent.locals);
});
app.set('views', path.join(__dirname, 'views/action'));
app.engine('.hbs', hbs({
extname: '.hbs',
defaultLayout: 'layout',
layoutsDir: doraemon,
partialsDir: [path.join(__dirname, 'views/partial'), `${doraemon}/partial`],
helpers: global.yoho.helpers
}));
// router
app.use(require('./router'));
module.exports = app;
... ...
/**
* router of sub app home
* @author: shenzm<zhimin.shen@yoho.cn>
* @date: 2016/07/18
*/
'use strict';
const router = require('express').Router();
const cRoot = './controllers';
// Your controller here
module.exports = router;
\ No newline at end of file
... ...
<h1>test</h1>
\ No newline at end of file
... ...
<div class="modal" style="background: blue; border-radius: 5px; border: 1px solid #FFFFFF;">
<h2 style="color: yellow">{{title}}</h2>
<p style="color: yellow">{{text}}</p>
<div class="button-group">
{{#each buttons}}
<a href="javascript:void(0);" class="modal-button">{{text}}</a>
{{/each}}
</div>
</div>
... ...
<div class="loading">
<div></div>
<div></div>
<div></div>
</div>
... ...
/**
* 加载组件
*
* @author: Aiden Xu <aiden.xu@yoho.cn>
* @date: 2016/07/18
*/
'use strict';
const Overlay = require('./overlay');
const template = require('./loading.hbs');
if (!Overlay) {
throw new Error('Required dependency "Overlay" not found!');
}
class Loading {
constructor(opts) {
this.defaults = {};
this.settings = Object.assign({}, this.defaults, opts);
this.elem = $(template());
this.elem.appendTo('body');
}
/**
* 显示
*/
show() {
this.overlay = $.overlay({
animation: 'fade',
clickToClose: false
});
this.overlay.show();
}
/**
* 关闭
*/
hide() {
this.overlay.hide();
this.elem.remove();
}
}
((function($) {
$.loading = opts => {
return new Loading(opts);
};
})(jQuery));
module.exports = Loading;
... ...
<div class="modal">
<h2>{{title}}</h2>
<p>{{text}}</p>
<hr>
<div class="button-group">
{{#each buttons}}
<a href="javascript:void(0);" class="modal-button">{{text}}</a>
{{/each}}
</div>
</div>
... ...
/**
* Modal 模态组件
*
* @author: Aiden Xu<aiden.xu@yoho.cn>
* @date: 2016/07/18
*/
'use strict';
const template = require('./modal.hbs');
class Modal {
/**
* Modal
*
* @param opts
*/
constructor(opts) {
// 默认参数
this.defaults = {
isModal: true,
template: template,
title: '',
text: '',
buttons: [
{
text: '好',
handler: () => {
this.hide();
}
}
]
};
// 初始化参数
this.settings = Object.assign({}, this.defaults, opts);
const tpl = this.settings.template({
title: this.settings.title,
text: this.settings.text,
buttons: this.settings.buttons
});
// 生成模版
this.elem = $(tpl);
const buttons = this.elem.find('.button-group').children();
const self = this;
this.elem.appendTo('body');
// 事件绑定
buttons.each(function(index) {
$(this).click(self.settings.buttons[index].handler.bind(self));
});
}
show() {
// 显示覆盖层
this.overlay = $.overlay({
clickToClose: false
});
this.overlay.show();
// 居中显示
this.elem.css({
left: ($(window).width() - this.elem.outerWidth()) / 2,
top: ($(window).height() - this.elem.outerHeight()) / 2 + $(window).scrollTop()
}).show().addClass('animation-target');
}
hide() {
this.overlay.hide();
this.elem.hide().remove();
}
}
(function($) {
$.modal = function(opts) {
return new Modal(opts);
};
$.extend($.modal, {
alert: (text, title)=> {
const modal = $.modal({
text: text,
title: title
});
modal.show();
},
confirm: (text, title, callback)=> {
const modal = $.modal({
text: text,
title: title,
buttons: [
{
text: '取消',
handler: function() {
this.hide();
}
},
{
text: '好',
handler: callback || $.noop
}
]
});
modal.show();
}
});
}(jQuery));
module.exports = Modal;
... ...
/**
* Modal 覆盖层组件
*
* @author: Aiden Xu<aiden.xu@yoho.cn>
* @date: 2016/07/18
*/
'use strict';
const ANIMATIONS = {
none: {
in: 'overlay-in',
out: 'overlay-out'
},
fade: {
in: 'overlay-fade-in',
out: 'overlay-fade-out'
}
};
class Overlay {
constructor(opts) {
this.isVisible = false;
// 默认参数
this.defaults = {
className: 'overlay',
clickToClose: true, // 点击关闭
onClose: $.noop, // 关闭回调函数
animation: 'fade', // 动画效果
disableScrolling: true
};
// 初始化参数
this.settings = Object.assign({}, this.defaults, opts);
this.settings.animationClasses = {
in: ANIMATIONS[this.settings.animation].in,
out: ANIMATIONS[this.settings.animation].out
};
this.elem = $('<div/>', {
class: this.settings.className
});
this.elem.appendTo('body');
// 点击关闭
this.elem.click(()=> {
if (this.settings.clickToClose) {
this.hide();
}
});
if (this.settings.disableScrolling) {
// 覆盖层出现时阻止滚动
$(window).on('touchmove', (e)=> {
if (this.isVisible) {
e.preventDefault();
}
});
}
}
_clearStylesClasses() {
this.elem
.removeClass(this.settings.animationClasses.in)
.removeClass(this.settings.animationClasses.out);
}
/**
* 显示覆盖层
*/
show() {
this._clearStylesClasses();
this.elem.css({
visibility: 'visible'
}).show().addClass(this.settings.animationClasses.in);
this.isVisible = true;
$('body').css({
overflow: 'hidden'
});
}
/**
* 关闭覆盖层
*/
hide() {
this._clearStylesClasses();
const listener = () => {
// 一次性监听,动画完成事件触发后删除监听器
this.elem[0].removeEventListener('webkitTransitionEnd', listener);
this.elem.css({
visibility: 'hidden'
});
this._clearStylesClasses();
this.isVisible = false;
this.elem.remove();
};
this.elem[0].addEventListener('webkitTransitionEnd', listener);
this.elem.addClass(this.settings.animationClasses.out);
if (this.settings.disableScrolling) {
$('body').css({
overflow: 'auto'
});
}
}
}
((function($) {
$.overlay = opts => {
return new Overlay(opts);
};
})(jQuery));
module.exports = Overlay;
... ...
... ... @@ -47,4 +47,60 @@ tipBtn.addEventListener('click', function(){
})
var overlay = require('../common/overlay');
var modal = require('../common/modal');
var customModal = require('../../hbs/example/custom-modal.hbs');
var loading = require('../common/loading');
$('#modal-overlay').click(()=> {
var overlay = $.overlay();
overlay.show();
});
$('#modal-alert').click(()=> {
$.modal.alert('自毁系统已经开启,请马上撤离!', '警告');
});
$('#modal-confirm').click(()=> {
$.modal.confirm('是否开启自毁系统?', '', function() {
this.hide();
alert('BOOM!');
});
});
// 自定义模态
$('#modal-custom').click(()=> {
const modal = $.modal({
title: '自定义模态对话框',
text: '你可以自定义哦!',
template: customModal,
buttons: [
{
text: '香蕉',
handler: function() {
this.hide();
alert('香蕉');
}
},
{
text: '苹果',
handler: function() {
this.hide();
alert('苹果');
}
}
]
});
modal.show();
});
$('#loading').click(()=> {
const loading = $.loading();
loading.show();
setTimeout(()=> {
loading.hide();
}, 3000)
});
/* eslint-enable */
... ...
... ... @@ -14,13 +14,42 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-bag:before { content: "\e601"; }
.icon-check:before { content: "\e603"; }
.icon-close:before { content: "\e605"; }
.icon-left:before { content: "\e606"; }
.icon-right:before { content: "\e607"; }
.icon-search:before { content: "\e608"; }
.icon-down:before { content: "\e602"; }
.icon-up:before { content: "\e617"; }
.icon-love:before { content: "\e60d"; }
.icon-delete:before { content: "\e600"; }
.icon-bag:before {
content: "\e601";
}
.icon-check:before {
content: "\e603";
}
.icon-close:before {
content: "\e605";
}
.icon-left:before {
content: "\e606";
}
.icon-right:before {
content: "\e607";
}
.icon-search:before {
content: "\e608";
}
.icon-down:before {
content: "\e602";
}
.icon-up:before {
content: "\e617";
}
.icon-love:before {
content: "\e60d";
}
.icon-delete:before {
content: "\e600";
}
... ...
... ... @@ -8,3 +8,5 @@
@import "swiper";
@import "badge";
@import "form";
@import "modal";
@import "loading";
... ...
@keyframes loading-scale {
0% {
transform: scale(1);
opacity: 1;
}
45% {
transform: scale(0.1);
opacity: 0.7;
}
80% {
transform: scale(1);
opacity: 1;
}
}
.loading {
position: fixed;
top: 50%;
left: 50%;
margin-top: -20px;
margin-left: -60px;
width: 128px;
height: 40px;
z-index: 1001;
> div {
$init: 0.12;
@for $i from 1 to 3 {
&:nth-child($i) {
animation: loading-scale 0.75s $(init)s infinite cubic-bezier(0.2, 0.68, 0.18, 1.08);
}
$init: calc(($i + 1) * 0.12);
}
display: inline-block;
margin: 4px;
width: 30px;
height: 30px;
border-radius: 100%;
background: #fff;
}
}
... ...
@import "overlay";
.modal {
position: absolute;
margin: 0 auto;
background: #fcfcfc;
width: 512px;
z-index: 1001;
h2 {
font-size: 32px;
text-align: center;
margin-top: 50px;
margin-bottom: 0;
}
p {
font-size: 21px;
text-align: center;
margin-top: 20px;
margin-bottom: 48px;
}
hr {
border: none;
border-top: 1px solid #e0e0e0;
margin: 0;
}
.button-group {
display: flex;
flex-direction: row;
justify-content: space-around;
align-items: stretch;
height: 88px;
a.modal-button {
flex: 1;
align-self: center;
text-align: center;
color: $blue;
font-size: 30px;
}
:not(:first-child) {
border-left: 1px solid #e0e0e0;
}
}
}
.animation-target {
-webkit-animation: animation 1000ms linear both;
animation: animation 1000ms linear both;
}
/* Generated with Bounce.js. Edit at http://goo.gl/W7f9he */
@keyframes animation {
0% {
transform: matrix3d(0.5, 0, 0, 0, 0, 0.5, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
4.3% {
transform: matrix3d(0.757, 0, 0, 0, 0, 0.757, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
8.61% {
transform: matrix3d(0.939, 0, 0, 0, 0, 0.939, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
12.91% {
transform: matrix3d(1.026, 0, 0, 0, 0, 1.026, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
17.22% {
transform: matrix3d(1.047, 0, 0, 0, 0, 1.047, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
28.33% {
transform: matrix3d(1.01, 0, 0, 0, 0, 1.01, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
39.44% {
transform: matrix3d(0.997, 0, 0, 0, 0, 0.997, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
61.66% {
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
83.98% {
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
100% {
transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
}
... ...
.overlay {
position: fixed;
background: #000;
opacity: 0;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1000;
}
.overlay-fade-in {
opacity: 0.5;
transition: opacity 0.1s linear;
}
.overlay-fade-out {
opacity: 0;
transition: opacity 0.1s linear;
}
.overlay-in {
opacity: 0.5;
transition: opacity 0.1s linear;
}
.overlay-out {
opacity: 0;
transition: opacity 0.1s linear;
}
... ...