forked from fanruan/fineui-start
richie
4 years ago
27 changed files with 544 additions and 623 deletions
@ -1,171 +1,8 @@ |
|||||||
{ |
{ |
||||||
"extends": "eslint:recommended", |
"extends": "plugin:@fui/typescript", |
||||||
"rules": { |
"parserOptions": { |
||||||
// 声明 |
"ecmaFeatures": { |
||||||
"no-use-before-define": "error", |
"legacyDecorators": true |
||||||
//禁止定义前使用 |
} |
||||||
|
|
||||||
// 对象 |
|
||||||
"no-dupe-keys": "error", |
|
||||||
// 禁止在对象字面量中出现重复的键 |
|
||||||
"quote-props": [ |
|
||||||
"error", |
|
||||||
"as-needed" |
|
||||||
], |
|
||||||
// 对象属性只在需要的时候加引号 |
|
||||||
|
|
||||||
// 字符串 |
|
||||||
"quotes": [ |
|
||||||
"error", |
|
||||||
"double", |
|
||||||
{ |
|
||||||
"allowTemplateLiterals": true |
|
||||||
} |
|
||||||
], |
|
||||||
// 字符串开头和结束使用双引号 |
|
||||||
"no-useless-concat": "error", |
|
||||||
// 禁止没有必要的字符拼接 |
|
||||||
"no-useless-escape": "error", |
|
||||||
// 禁用不必要的转义 |
|
||||||
|
|
||||||
// 函数 |
|
||||||
"no-dupe-args": "error", |
|
||||||
// 禁止在 function 定义中出现重复的参数 |
|
||||||
"space-before-function-paren": "error", |
|
||||||
// 函数括号前必须要有空格 |
|
||||||
|
|
||||||
// 变量 |
|
||||||
"no-undef": "error", |
|
||||||
// 禁止使用未声明的变量 |
|
||||||
|
|
||||||
// 比较运算符 & 相等运算符 |
|
||||||
"eqeqeq": "error", |
|
||||||
// 使用 === 和 !== 代替 == 和 != |
|
||||||
"no-unneeded-ternary": "error", |
|
||||||
//禁止可以在有更简单的可替代的表达式时使用三元操作符 |
|
||||||
|
|
||||||
// 条件 |
|
||||||
"default-case": "error", |
|
||||||
// 要求 Switch 语句中有 Default 分支 |
|
||||||
"no-else-return": "error", |
|
||||||
// 如果 if 块中包含了一个 return 语句,else 块就成了多余的了。可以将其内容移至块外 |
|
||||||
|
|
||||||
// 代码块 |
|
||||||
"brace-style": [ |
|
||||||
"error", |
|
||||||
"1tbs", |
|
||||||
{ |
|
||||||
"allowSingleLine": true |
|
||||||
} |
|
||||||
], |
|
||||||
// 代码块左括号紧跟上一行结束 |
|
||||||
"curly": [ |
|
||||||
"error", |
|
||||||
"multi-line" |
|
||||||
], |
|
||||||
// if、else if、else、for、while强制使用大括号,但允许在单行中省略大括号 |
|
||||||
|
|
||||||
// 注释 |
|
||||||
"spaced-comment": "error", |
|
||||||
// 注释前有空格 |
|
||||||
|
|
||||||
// 空白 |
|
||||||
"indent": [ |
|
||||||
"error", |
|
||||||
4, |
|
||||||
{ |
|
||||||
"SwitchCase": 1 |
|
||||||
} |
|
||||||
], |
|
||||||
// 缩进控制4空格 |
|
||||||
"no-mixed-spaces-and-tabs": "error", |
|
||||||
// 禁止使用 空格 和 tab 混合缩进 |
|
||||||
"space-before-blocks": [ |
|
||||||
"error", |
|
||||||
"always" |
|
||||||
], |
|
||||||
// 语句块之前的需要有空格 |
|
||||||
"space-infix-ops": [ |
|
||||||
"error", |
|
||||||
{ |
|
||||||
"int32Hint": false |
|
||||||
} |
|
||||||
], |
|
||||||
// 要求中缀操作符周围有空格,设置 int32Hint 选项为 true (默认 false) 允许 a|0 不带空格 |
|
||||||
"no-trailing-spaces": [ |
|
||||||
"error", |
|
||||||
{ |
|
||||||
"skipBlankLines": true |
|
||||||
} |
|
||||||
], |
|
||||||
// 禁用行尾空格 |
|
||||||
"key-spacing": [ |
|
||||||
"error", |
|
||||||
{ |
|
||||||
"afterColon": true |
|
||||||
} |
|
||||||
], |
|
||||||
// 要求在对象字面量的冒号和值之间存在至少有一个空格 |
|
||||||
|
|
||||||
|
|
||||||
// 逗号 |
|
||||||
"comma-style": "error", |
|
||||||
// 逗号必须放在行末 |
|
||||||
"comma-dangle": [ |
|
||||||
"error", |
|
||||||
"never" |
|
||||||
], |
|
||||||
// 多行对象字面量中要求不要拖尾逗号 |
|
||||||
"comma-spacing": [ |
|
||||||
"error", |
|
||||||
{ |
|
||||||
"before": false, |
|
||||||
"after": true |
|
||||||
} |
|
||||||
], |
|
||||||
//在变量声明、数组字面量、对象字面量、函数参数 和 序列中禁止在逗号前使用空格,要求在逗号后使用一个或多个空格 |
|
||||||
|
|
||||||
|
|
||||||
// 分号 |
|
||||||
"semi": "error", |
|
||||||
//不得省略语句结束的分号 |
|
||||||
"semi-spacing": [ |
|
||||||
"error", |
|
||||||
{ |
|
||||||
"before": false, |
|
||||||
"after": true |
|
||||||
} |
|
||||||
], |
|
||||||
//禁止分号周围的空格 |
|
||||||
"no-extra-semi": "error", |
|
||||||
// 禁用不必要的分号 |
|
||||||
|
|
||||||
|
|
||||||
// 类型转换 |
|
||||||
"no-extra-boolean-cast": "error", |
|
||||||
// 禁止不必要的布尔类型转换 |
|
||||||
|
|
||||||
|
|
||||||
// 其他最佳实践或规范 |
|
||||||
"no-unexpected-multiline": "error", |
|
||||||
// 禁止使用令人困惑的多行表达式 |
|
||||||
"no-unreachable": "error", |
|
||||||
// 禁止在 return、throw、continue 和 break 语句后出现不可达代码 |
|
||||||
"valid-typeof": "error", |
|
||||||
// 强制 typeof 表达式与有效的字符串进行比较 |
|
||||||
"no-new-wrappers": "error" |
|
||||||
// 禁止通过 new 操作符使用 String、Number 和 Boolean |
|
||||||
}, |
|
||||||
"globals": { |
|
||||||
"window": true, |
|
||||||
"BI": true, |
|
||||||
"BICst": true, |
|
||||||
"Data": true, |
|
||||||
"Fix": true, |
|
||||||
"module": true, |
|
||||||
"describe": true, |
|
||||||
"it": true, |
|
||||||
"expect": true, |
|
||||||
"Dec": true |
|
||||||
} |
} |
||||||
} |
} |
@ -1,121 +0,0 @@ |
|||||||
module.exports = function (grunt) { |
|
||||||
// Project configuration.
|
|
||||||
grunt.initConfig({ |
|
||||||
pkg: grunt.file.readJSON("package.json"), |
|
||||||
concat: { |
|
||||||
options: { |
|
||||||
separator: "" |
|
||||||
}, |
|
||||||
bundleJs: { |
|
||||||
src: [ |
|
||||||
"src/modules/**/*.js", |
|
||||||
"src/index.js" |
|
||||||
], |
|
||||||
dest: "dist/bundle.js" |
|
||||||
}, |
|
||||||
bundleCss: { |
|
||||||
src: ["src/css/**/*.css"], |
|
||||||
dest: "dist/bundle.css" |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
less: { |
|
||||||
main: { |
|
||||||
expand: true, |
|
||||||
cwd: "src/modules", |
|
||||||
src: ["**/*.less"], |
|
||||||
dest: "src/css/", |
|
||||||
ext: ".css" |
|
||||||
}, |
|
||||||
dev: { |
|
||||||
options: { |
|
||||||
compress: true, |
|
||||||
yuicompress: false |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
uglify: { |
|
||||||
options: { |
|
||||||
banner: |
|
||||||
"/*! <%= pkg.name %> <%= grunt.template.today(\"dd-mm-yyyy\") %> */\n" |
|
||||||
}, |
|
||||||
dist: { |
|
||||||
files: { |
|
||||||
"dist/bundle.min.js": ["<%= concat.bundleJs.dest %>"] |
|
||||||
} |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
cssmin: { |
|
||||||
bundleCss: { |
|
||||||
src: "<%= concat.bundleCss.dest %>", |
|
||||||
|
|
||||||
dest: "dist/bundle.min.css" |
|
||||||
} |
|
||||||
}, |
|
||||||
|
|
||||||
jshint: { |
|
||||||
files: ["src/**/*.js"], |
|
||||||
options: { |
|
||||||
globals: { |
|
||||||
$: true, |
|
||||||
jQuery: true, |
|
||||||
console: true, |
|
||||||
module: true, |
|
||||||
document: true |
|
||||||
}, |
|
||||||
browser: true, |
|
||||||
expr: true |
|
||||||
} |
|
||||||
}, |
|
||||||
watch: { |
|
||||||
scripts: { |
|
||||||
files: ["src/**/*.js", "src/**/*.less"], |
|
||||||
tasks: ["less", "concat"], |
|
||||||
options: { |
|
||||||
spanw: true, |
|
||||||
interrupt: true |
|
||||||
} |
|
||||||
}, |
|
||||||
livereload: { |
|
||||||
options: { |
|
||||||
livereload: "<%= connect.options.livereload %>" |
|
||||||
}, |
|
||||||
files: ["src/**/*.js", "src/**/*.less"] |
|
||||||
} |
|
||||||
}, |
|
||||||
connect: { |
|
||||||
options: { |
|
||||||
port: 9000, |
|
||||||
open: true, |
|
||||||
livereload: 35799, |
|
||||||
// Change this to '0.0.0.0' to access the server from outside
|
|
||||||
hostname: "localhost" |
|
||||||
}, |
|
||||||
server: { |
|
||||||
options: { |
|
||||||
port: 9009, |
|
||||||
base: "./" |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
grunt.loadNpmTasks("grunt-contrib-uglify"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-jshint"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-less"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-watch"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-concat"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-cssmin"); |
|
||||||
grunt.loadNpmTasks("grunt-contrib-connect"); |
|
||||||
|
|
||||||
grunt.registerTask("default", [ |
|
||||||
"jshint", |
|
||||||
"less", |
|
||||||
"concat", |
|
||||||
"connect", |
|
||||||
"watch" |
|
||||||
]); |
|
||||||
grunt.registerTask("min", ["less", "concat", "uglify", "cssmin"]); |
|
||||||
}; |
|
@ -0,0 +1 @@ |
|||||||
|
module.exports = require('@fui/babel-preset-fineui').configs.ie8; |
@ -0,0 +1 @@ |
|||||||
|
export const { shortcut, Model, model, store } = BI.Decorators; |
@ -0,0 +1,3 @@ |
|||||||
|
export const { shortcut, Model, model, store } = BI.Decorators; |
||||||
|
|
||||||
|
export type Constructor<T> = new(...args: any[]) => T; |
@ -1,16 +0,0 @@ |
|||||||
/** |
|
||||||
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求 |
|
||||||
*/ |
|
||||||
.my-todolist-header { |
|
||||||
background-color: #3d4d66; |
|
||||||
} |
|
||||||
.my-todolist-header .my-todolist-title { |
|
||||||
font-size: 22px; |
|
||||||
color: #FFF; |
|
||||||
} |
|
||||||
.my-todolist-header .my-todolist-header-editor { |
|
||||||
background-color: #FFF; |
|
||||||
-webkit-border-radius: 5px; |
|
||||||
-moz-border-radius: 5px; |
|
||||||
border-radius: 5px; |
|
||||||
} |
|
@ -1,14 +0,0 @@ |
|||||||
/** |
|
||||||
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius方法等.请选择性使用.不强制要求 |
|
||||||
*/ |
|
||||||
.my-todolist-list .my-todolist-list-text { |
|
||||||
font-size: 16px; |
|
||||||
font-weight: bold; |
|
||||||
} |
|
||||||
.my-todolist-list .my-todolist-list-count-container { |
|
||||||
-webkit-border-radius: 10px; |
|
||||||
-moz-border-radius: 10px; |
|
||||||
border-radius: 10px; |
|
||||||
background-color: #3d4d66; |
|
||||||
color: #ffffff; |
|
||||||
} |
|
@ -1,6 +0,0 @@ |
|||||||
/** |
|
||||||
列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求 |
|
||||||
*/ |
|
||||||
.my-todolist-background { |
|
||||||
background-color: #f7f8fa; |
|
||||||
} |
|
@ -1,7 +1,7 @@ |
|||||||
!(function () { |
import { ToDoList } from "./modules/main"; |
||||||
// 将todolist组件挂载到#wrapper上.
|
|
||||||
BI.createWidget({ |
// 将todolist组件挂载到#wrapper上.
|
||||||
type: "my.todolist", |
BI.createWidget({ |
||||||
element: "#wrapper" |
type: ToDoList.xtype, |
||||||
}); |
element: "#wrapper" |
||||||
})(); |
}); |
||||||
|
@ -1,4 +1,4 @@ |
|||||||
@import "../fineui/src/less/index"; |
@import "../node_modules/fineui/src/less/index"; |
||||||
|
|
||||||
@fontUrl: 'font/'; //字体存放路径 |
@fontUrl: 'font/'; //字体存放路径 |
||||||
@imageUrl: 'images/1x/'; //图片的基本地址 |
@imageUrl: 'images/1x/'; //图片的基本地址 |
||||||
|
@ -1,70 +1,71 @@ |
|||||||
!(function() { |
import { shortcut } from "../../core/javascript/decorator"; |
||||||
/** |
import "./header.less"; |
||||||
* 顶部组件,提供输入框添加todo项目 |
|
||||||
* 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中 |
|
||||||
*/ |
|
||||||
var ToDoListHeader = BI.inherit(BI.Widget, { |
|
||||||
|
|
||||||
props: { |
/** |
||||||
// 指定组件的className
|
* 顶部组件,提供输入框添加todo项目 |
||||||
baseCls: "my-todolist-header" |
* 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中 |
||||||
}, |
*/ |
||||||
|
@shortcut() |
||||||
|
export class ToDoListHeader extends BI.Widget { |
||||||
|
static xtype = "my.todolist.header"; |
||||||
|
|
||||||
render: function() { |
static EVENT_ADD = "EVENT_ADD"; |
||||||
var self = this, o = this.options; |
|
||||||
return { |
props = { |
||||||
type: "bi.horizontal_auto", // 水平居中布局
|
// 指定组件的className
|
||||||
items: [ |
baseCls: "my-todolist-header", |
||||||
{ |
} |
||||||
el: { |
|
||||||
type: "bi.left_right_vertical_adapt", // 左右垂直居中布局
|
|
||||||
width: 600, |
|
||||||
height: o.height, |
|
||||||
items: { |
|
||||||
left: [ |
|
||||||
{ |
|
||||||
el: { |
|
||||||
type: "bi.label", |
|
||||||
cls: "my-todolist-title", |
|
||||||
text: "FineUI ToDoList", |
|
||||||
height: o.height |
|
||||||
} |
|
||||||
} |
|
||||||
], |
|
||||||
right: [ |
|
||||||
{ |
|
||||||
el: { |
|
||||||
type: "bi.editor", |
|
||||||
ref: function(_ref) { |
|
||||||
self.editor = _ref; |
|
||||||
}, |
|
||||||
allowBlank: true, |
|
||||||
cls: "my-todolist-header-editor", |
|
||||||
watermark: "添加ToDo", |
|
||||||
width: 300, |
|
||||||
height: 24, |
|
||||||
listeners: [ |
|
||||||
{ // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置空
|
|
||||||
eventName: "EVENT_ENTER", |
|
||||||
action: function() { |
|
||||||
// 注意:在这里this指向的是bi.editor的实例.通过bi.editor的getValue()方法获取输入框输入值.
|
|
||||||
self.fireEvent(ToDoListHeader.EVENT_ADD, this.getValue()); |
|
||||||
self.editor.setValue(""); |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
}; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
ToDoListHeader.EVENT_ADD = "EVENT_ADD"; |
render() { |
||||||
|
const { height } = this.options; |
||||||
|
|
||||||
BI.shortcut("my.todolist.header", ToDoListHeader); |
return { |
||||||
})(); |
// 水平居中布局
|
||||||
|
type: BI.HorizontalAutoLayout.xtype, |
||||||
|
items: [{ |
||||||
|
el: { |
||||||
|
// 左右垂直居中布局
|
||||||
|
type: BI.LeftRightVerticalAdaptLayout.xtype, |
||||||
|
width: 600, |
||||||
|
height: 40, |
||||||
|
items: { |
||||||
|
left: [ |
||||||
|
{ |
||||||
|
el: { |
||||||
|
type: BI.Label.xtype, |
||||||
|
cls: "my-todolist-title", |
||||||
|
text: "FineUI ToDoList", |
||||||
|
height, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
right: [ |
||||||
|
{ |
||||||
|
el: { |
||||||
|
type: BI.Editor.xtype, |
||||||
|
ref: _ref => { |
||||||
|
this.editor = _ref; |
||||||
|
}, |
||||||
|
allowBlank: true, |
||||||
|
cls: "my-todolist-header-editor", |
||||||
|
watermark: "添加ToDo", |
||||||
|
width: 300, |
||||||
|
height: 24, |
||||||
|
listeners: [ |
||||||
|
{ // 监听bi.editor 组件的"EVENT_ENTER"事件(即敲回车),触发事件ToDoListHeader.EVENT_ADD事件并将输入框值置
|
||||||
|
eventName: "EVENT_ENTER", |
||||||
|
action: () => { |
||||||
|
this.fireEvent(ToDoListHeader.EVENT_ADD, this.editor.getValue()); |
||||||
|
this.editor.setValue(""); |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
}, |
||||||
|
}], |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
@ -1,90 +0,0 @@ |
|||||||
!(function() { |
|
||||||
/** |
|
||||||
* todo项列表 |
|
||||||
* |
|
||||||
*/ |
|
||||||
var List = BI.inherit(BI.Widget, { |
|
||||||
|
|
||||||
props: { |
|
||||||
// 指定组件的className
|
|
||||||
baseCls: "my-todolist-list", |
|
||||||
text: "正在进行" |
|
||||||
}, |
|
||||||
|
|
||||||
render: function() { |
|
||||||
var self = this, o = this.options; |
|
||||||
return { |
|
||||||
type: "bi.vertical", |
|
||||||
items: [ |
|
||||||
{ |
|
||||||
el: { |
|
||||||
type: "bi.vertical_adapt", |
|
||||||
height: 40, |
|
||||||
items: [ |
|
||||||
{ |
|
||||||
type: "bi.label", |
|
||||||
cls: "my-todolist-list-text", |
|
||||||
textAlign: "left", |
|
||||||
text: o.text, |
|
||||||
width: 580 |
|
||||||
}, { |
|
||||||
type: "bi.center_adapt", |
|
||||||
cls: "my-todolist-list-count-container", |
|
||||||
width: 20, |
|
||||||
height: 20, |
|
||||||
items: [ |
|
||||||
{ |
|
||||||
el: { |
|
||||||
type: "bi.label", |
|
||||||
ref: function(_ref) { |
|
||||||
self.count = _ref; |
|
||||||
}, |
|
||||||
text: "0" |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
] |
|
||||||
} |
|
||||||
}, { // 用bi.vertical布局作为列表项的容器.
|
|
||||||
type: "bi.vertical", |
|
||||||
vgap: 10, |
|
||||||
ref: function(_ref) { |
|
||||||
self.list = _ref; |
|
||||||
}, |
|
||||||
items: this._createItems(o.items) |
|
||||||
} |
|
||||||
] |
|
||||||
}; |
|
||||||
}, |
|
||||||
|
|
||||||
_createItems: function(items) { |
|
||||||
var self = this; |
|
||||||
return BI.map(items, function(index, item) { |
|
||||||
return BI.extend(item, { |
|
||||||
type: "bi.multi_select_item", // 节点采用复选节点展示
|
|
||||||
selected: item.done, // 已完成的todo项置为选中状态
|
|
||||||
disabled: item.done, // 已完成的todo项置为灰化状态
|
|
||||||
listeners: [ |
|
||||||
{ // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事件
|
|
||||||
eventName: "EVENT_CHANGE", |
|
||||||
action: function(v) { |
|
||||||
self.fireEvent("EVENT_CHANGE", v); |
|
||||||
} |
|
||||||
} |
|
||||||
] |
|
||||||
}); |
|
||||||
}); |
|
||||||
}, |
|
||||||
|
|
||||||
_setCount: function(count) { |
|
||||||
this.count.setText(count); |
|
||||||
}, |
|
||||||
|
|
||||||
populate: function(items) { |
|
||||||
this.list.populate(this._createItems(items)); |
|
||||||
this._setCount(items.length); |
|
||||||
} |
|
||||||
}); |
|
||||||
BI.shortcut("my.todolist.list", List); |
|
||||||
})(); |
|
@ -0,0 +1,101 @@ |
|||||||
|
import { Label, VerticalLayout } from 'fineui'; |
||||||
|
import { shortcut } from "../../core/typescript/decorator"; |
||||||
|
import "./list.less"; |
||||||
|
|
||||||
|
/** |
||||||
|
* todo项列表 |
||||||
|
*/ |
||||||
|
@shortcut() |
||||||
|
export class List extends BI.Widget { |
||||||
|
public static xtype = "my.todolist.list"; |
||||||
|
|
||||||
|
private count: Label; |
||||||
|
private list: VerticalLayout; |
||||||
|
|
||||||
|
public props = { |
||||||
|
// 指定组件的className
|
||||||
|
baseCls: "my-todolist-list", |
||||||
|
text: "正在进行", |
||||||
|
items: [], |
||||||
|
} |
||||||
|
|
||||||
|
public render() { |
||||||
|
const { text, items } = this.options; |
||||||
|
|
||||||
|
return { |
||||||
|
type: BI.VerticalLayout.xtype, |
||||||
|
items: [ |
||||||
|
{ |
||||||
|
el: { |
||||||
|
type: BI.VerticalAdaptLayout.xtype, |
||||||
|
height: 40, |
||||||
|
items: [ |
||||||
|
{ |
||||||
|
type: BI.Label.xtype, |
||||||
|
cls: "my-todolist-list-text", |
||||||
|
textAlign: "left", |
||||||
|
text, |
||||||
|
width: 580, |
||||||
|
}, { |
||||||
|
type: BI.CenterAdaptLayout.xtype, |
||||||
|
cls: "my-todolist-list-count-container", |
||||||
|
width: 20, |
||||||
|
height: 20, |
||||||
|
items: [ |
||||||
|
{ |
||||||
|
el: { |
||||||
|
type: BI.Label.xtype, |
||||||
|
ref: (_ref: Label) => { |
||||||
|
this.count = _ref; |
||||||
|
}, |
||||||
|
text: 0, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
}, { |
||||||
|
// 用bi.vertical布局作为列表项的容器.
|
||||||
|
type: BI.VerticalLayout.xtype, |
||||||
|
vgap: 10, |
||||||
|
ref: (_ref: VerticalLayout) => { |
||||||
|
this.list = _ref; |
||||||
|
}, |
||||||
|
items: this.createItems(items), |
||||||
|
}, |
||||||
|
], |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
private createItems(items: Item[]) { |
||||||
|
return items.map(item => { |
||||||
|
return BI.extend(item, { |
||||||
|
type: BI.MultiSelectItem.xtype, // 节点采用复选节点展示
|
||||||
|
selected: item.done, // 已完成的todo项置为选中状态
|
||||||
|
disabled: item.done, // 已完成的todo项置为灰化状态
|
||||||
|
listeners: [ |
||||||
|
{ // 为每个todo项添加"EVENT_CHANGE"事件监听,触发组件自身"EVENT_CHANGE"事
|
||||||
|
eventName: "EVENT_CHANGE", |
||||||
|
action: (v: any) => { |
||||||
|
this.fireEvent("EVENT_CHANGE", v); |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}); |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
private setCount(count: number) { |
||||||
|
this.count.setText(`${count}`); |
||||||
|
} |
||||||
|
|
||||||
|
public populate(items: []) { |
||||||
|
this.list.populate(this.createItems(items)); |
||||||
|
this.setCount(items.length); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
interface Item { |
||||||
|
done: boolean, |
||||||
|
} |
@ -1,121 +1,119 @@ |
|||||||
!(function() { |
import { shortcut } from "../core/javascript/decorator"; |
||||||
/** |
import { ToDoListHeader } from "./header/header"; |
||||||
* todolist 组件 |
import { List } from "./list/list"; |
||||||
*/ |
import "./main.less"; |
||||||
var ToDoList = BI.inherit(BI.Widget, { |
|
||||||
|
|
||||||
props: { |
/** |
||||||
baseCls: "fine-to-do-list" |
* todolist 组件 |
||||||
}, |
*/ |
||||||
|
@shortcut() |
||||||
|
export class ToDoList extends BI.Widget { |
||||||
|
static xtype = "my.todolist"; |
||||||
|
|
||||||
// 生命周期函数,在组件创建前
|
props = { |
||||||
beforeCreate: function() { |
baseCls: "fine-to-do-list", |
||||||
// 初始化存储数据
|
} |
||||||
this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : []; |
|
||||||
}, |
|
||||||
|
|
||||||
render: function() { |
// 生命周期函数,在组件创建前
|
||||||
var self = this, o = this.options; |
beforeCreate() { |
||||||
return { |
// 初始化存储数据
|
||||||
type: "bi.vtape", // vtape布局,顶部高度固定,下部分列表占满高度
|
this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : []; |
||||||
items: [ |
} |
||||||
{ |
|
||||||
el: { |
render() { |
||||||
type: "my.todolist.header", // 顶部组件
|
return { |
||||||
listeners: [ |
type: BI.VTapeLayout.xtype, // vtape布局,顶部高度固定,下部分列表占满高度
|
||||||
{ // 监听组件的EVENT_ADD事件,新建todo项
|
items: [ |
||||||
eventName: "EVENT_ADD", |
{ |
||||||
action: function(v) { |
el: { |
||||||
self.addToDo(v); |
type: ToDoListHeader.xtype, // 顶部组件
|
||||||
} |
listeners: [ |
||||||
} |
{ // 监听组件的EVENT_ADD事件,新建todo项
|
||||||
], |
eventName: "EVENT_ADD", |
||||||
height: 40 |
action: v => { |
||||||
}, |
this.addToDo(v); |
||||||
height: 40 |
}, |
||||||
}, { |
}, |
||||||
type: "bi.horizontal_auto", // 水平居中布局
|
], |
||||||
cls: "my-todolist-background", // 添加className
|
height: 40, |
||||||
items: [ |
}, |
||||||
{ |
height: 40, |
||||||
el: { |
}, { |
||||||
type: "my.todolist.list", // need todo项列表
|
type: BI.HorizontalAutoLayout.xtype, // 水平居中布局
|
||||||
ref: function(_ref) { |
cls: "my-todolist-background", // 添加className
|
||||||
self.todolist = _ref; |
items: [ |
||||||
}, |
{ |
||||||
items: this._getNeedTodoList(), |
el: { |
||||||
text: "正在进行", |
type: List.xtype, // need todo项列表
|
||||||
listeners: [ |
ref: _ref => { |
||||||
{ // 监听EVENT_CHANGE事件,完成某一项todo
|
this.todolist = _ref; |
||||||
eventName: "EVENT_CHANGE", |
}, |
||||||
action: function(v) { |
items: this._getNeedTodoList(), |
||||||
self.finishTodo(v); |
text: "正在进行", |
||||||
} |
listeners: [ |
||||||
} |
{ // 监听EVENT_CHANGE事件,完成某一项todo
|
||||||
], |
eventName: "EVENT_CHANGE", |
||||||
width: 600 |
action: v => { |
||||||
} |
this.finishTodo(v); |
||||||
}, { |
}, |
||||||
el: { |
|
||||||
type: "my.todolist.list", // 已经完成的todo项列表
|
|
||||||
text: "已经完成", |
|
||||||
items: this._getAlreadyDoneList(), |
|
||||||
ref: function(_ref) { |
|
||||||
self.donelist = _ref; |
|
||||||
}, |
}, |
||||||
width: 600 |
], |
||||||
} |
width: 600, |
||||||
} |
}, |
||||||
] |
}, { |
||||||
} |
el: { |
||||||
] |
type: List.xtype, // 已经完成的todo项列表
|
||||||
}; |
text: "已经完成", |
||||||
}, |
items: this._getAlreadyDoneList(), |
||||||
|
ref: _ref => { |
||||||
|
this.donelist = _ref; |
||||||
|
}, |
||||||
|
width: 600, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}], |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
_updateLocalStorage: function() { |
_updateLocalStorage() { |
||||||
localStorage.setItem("fine-todolist", JSON.stringify(this.list)); |
localStorage.setItem("fine-todolist", JSON.stringify(this.list)); |
||||||
}, |
} |
||||||
|
|
||||||
_getNeedTodoList: function() { |
_getNeedTodoList() { |
||||||
return BI.filter(this.list, function(index, item) { |
return BI.filter(this.list, (index, item) => !item.done); |
||||||
return !item.done; |
} |
||||||
}); |
|
||||||
}, |
|
||||||
|
|
||||||
_getAlreadyDoneList: function() { |
_getAlreadyDoneList() { |
||||||
return BI.filter(this.list, function(index, item) { |
return BI.filter(this.list, (index, item) => item.done); |
||||||
return item.done; |
} |
||||||
}); |
|
||||||
}, |
|
||||||
|
|
||||||
/** |
/** |
||||||
* 添加todo项 |
* 添加todo项 |
||||||
* @param text todo项的内容 |
* @param text todo项的内容 |
||||||
*/ |
*/ |
||||||
addToDo: function(text) { |
addToDo(text) { |
||||||
this.list.push({ |
this.list.push({ |
||||||
value: BI.UUID(), |
value: BI.UUID(), |
||||||
text: text, |
text, |
||||||
done: false |
done: false, |
||||||
}); |
}); |
||||||
this.todolist.populate(this._getNeedTodoList()); |
this.todolist.populate(this._getNeedTodoList()); |
||||||
this._updateLocalStorage(); |
this._updateLocalStorage(); |
||||||
}, |
} |
||||||
|
|
||||||
/** |
/** |
||||||
* 完成某一项todo |
* 完成某一项todo |
||||||
* @param v todo项的value |
* @param v todo项的value |
||||||
*/ |
*/ |
||||||
finishTodo: function(v) { |
finishTodo(v) { |
||||||
BI.some(this.list, function(index, item) { |
BI.some(this.list, (index, item) => { |
||||||
if (item.value === v) { |
if (item.value === v) { |
||||||
item.done = true; |
item.done = true; |
||||||
} |
} |
||||||
}); |
}); |
||||||
this.todolist.populate(this._getNeedTodoList()); |
this.todolist.populate(this._getNeedTodoList()); |
||||||
this.donelist.populate(this._getAlreadyDoneList()); |
this.donelist.populate(this._getAlreadyDoneList()); |
||||||
this._updateLocalStorage(); |
this._updateLocalStorage(); |
||||||
} |
} |
||||||
}); |
} |
||||||
BI.shortcut("my.todolist", ToDoList); |
|
||||||
})(); |
|
||||||
|
@ -0,0 +1,10 @@ |
|||||||
|
interface Obj { |
||||||
|
[key: string]: any; |
||||||
|
} |
||||||
|
|
||||||
|
declare let BI: Obj & import('fineui').BI; |
||||||
|
declare const Fix: Obj; |
||||||
|
|
||||||
|
declare interface String { |
||||||
|
replaceAll(regx: string | RegExp, callback: (str: string) => void): string; |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"extends": "@fui/typescript-configs/application.json", |
||||||
|
"compilerOptions": { |
||||||
|
"strict": false, |
||||||
|
"allowJs": true, |
||||||
|
}, |
||||||
|
} |
@ -0,0 +1,9 @@ |
|||||||
|
const path = require("path"); |
||||||
|
module.exports = { |
||||||
|
DEST: path.resolve(__dirname, "../dist"), |
||||||
|
NODE_MODULES: path.resolve(__dirname, "../node_modules"), |
||||||
|
PRIVATE: path.resolve(__dirname, "../private"), |
||||||
|
BABEL_CONFIG: path.resolve(__dirname, "../babel.config.js"), |
||||||
|
IE8_BABEL_CONFIG: path.resolve(__dirname, "../babel.config.ie8.js"), |
||||||
|
SRC: path.resolve(__dirname, "../src"), |
||||||
|
}; |
@ -0,0 +1,63 @@ |
|||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
||||||
|
const autoprefixer = require("autoprefixer"); |
||||||
|
|
||||||
|
const dirs = require("./dirs"); |
||||||
|
|
||||||
|
module.exports = { |
||||||
|
entry: { |
||||||
|
bundle: [ |
||||||
|
"./src/index.js", |
||||||
|
], |
||||||
|
}, |
||||||
|
resolve: { |
||||||
|
mainFields: ["module", "main"], |
||||||
|
extensions: [".js", ".ts"], |
||||||
|
}, |
||||||
|
stats: { |
||||||
|
children: false, |
||||||
|
modules: false, |
||||||
|
}, |
||||||
|
module: { |
||||||
|
rules: [ |
||||||
|
{ |
||||||
|
test: /\.(js|ts)$/, |
||||||
|
include: [dirs.NODE_MODULES, dirs.SRC], |
||||||
|
use: [{ |
||||||
|
loader: "babel-loader", |
||||||
|
options: { |
||||||
|
configFile: dirs.BABEL_CONFIG, |
||||||
|
}, |
||||||
|
}, { |
||||||
|
loader: "source-map-loader", |
||||||
|
options: { |
||||||
|
enforce: "pre", |
||||||
|
}, |
||||||
|
}], |
||||||
|
}, |
||||||
|
{ |
||||||
|
test: /\.(css|less)$/, |
||||||
|
use: [ |
||||||
|
MiniCssExtractPlugin.loader, |
||||||
|
{ |
||||||
|
loader: "css-loader", |
||||||
|
options: { |
||||||
|
url: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
loader: "postcss-loader", |
||||||
|
options: { |
||||||
|
plugins: [autoprefixer], |
||||||
|
}, |
||||||
|
}, |
||||||
|
{ |
||||||
|
loader: "less-loader", |
||||||
|
options: { |
||||||
|
relativeUrls: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
], |
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,53 @@ |
|||||||
|
const merge = require("webpack-merge"); |
||||||
|
const path = require("path"); |
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin"); |
||||||
|
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); |
||||||
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); |
||||||
|
|
||||||
|
const dirs = require("./dirs"); |
||||||
|
|
||||||
|
const common = require("./webpack.common.js"); |
||||||
|
|
||||||
|
module.exports = merge(common, { |
||||||
|
devtool: "eval-source-map", |
||||||
|
entry: { |
||||||
|
}, |
||||||
|
output: { |
||||||
|
path: dirs.DEST, |
||||||
|
filename: "[name].[contenthash].js", |
||||||
|
}, |
||||||
|
devServer: { |
||||||
|
open: true, |
||||||
|
contentBase: path.join(__dirname, ".."), |
||||||
|
port: 9002, |
||||||
|
liveReload: true, |
||||||
|
}, |
||||||
|
plugins: [ |
||||||
|
new ForkTsCheckerWebpackPlugin({ |
||||||
|
}), |
||||||
|
new MiniCssExtractPlugin({ |
||||||
|
path: dirs.DEST, |
||||||
|
filename: "[contenthash].css", |
||||||
|
}), |
||||||
|
new HtmlWebpackPlugin({ |
||||||
|
template: path.resolve(__dirname, "../index.html"), |
||||||
|
chunks: ["bundle"], |
||||||
|
chunksSortMode: "manual", |
||||||
|
nodeModules: path.resolve(__dirname, "../node_modules"), |
||||||
|
}), |
||||||
|
new OptimizeCssAssetsPlugin({ |
||||||
|
assetNameRegExp: /\.css$/g, |
||||||
|
cssProcessor: require("cssnano"), |
||||||
|
cssProcessorPluginOptions: { |
||||||
|
preset: ["default", { |
||||||
|
discardComments: { |
||||||
|
removeAll: true, |
||||||
|
}, |
||||||
|
normalizeUnicode: false, |
||||||
|
}], |
||||||
|
}, |
||||||
|
canPrint: true, |
||||||
|
}), |
||||||
|
], |
||||||
|
}); |
@ -0,0 +1,60 @@ |
|||||||
|
const webpack = require("webpack"); |
||||||
|
const merge = require("webpack-merge"); |
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
||||||
|
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin"); |
||||||
|
const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); |
||||||
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); |
||||||
|
|
||||||
|
const dirs = require("./dirs"); |
||||||
|
|
||||||
|
const common = require("./webpack.common.js"); |
||||||
|
|
||||||
|
module.exports = merge.smart(common, { |
||||||
|
mode: "production", |
||||||
|
optimization: { |
||||||
|
minimizer: [ |
||||||
|
new UglifyJsPlugin({ |
||||||
|
parallel: true, |
||||||
|
sourceMap: true, |
||||||
|
uglifyOptions: { |
||||||
|
ie8: true, |
||||||
|
output: { |
||||||
|
comments: false, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}), |
||||||
|
], |
||||||
|
}, |
||||||
|
|
||||||
|
devtool: "hidden-source-map", |
||||||
|
|
||||||
|
output: { |
||||||
|
path: dirs.DEST, |
||||||
|
filename: "bundle.js", |
||||||
|
}, |
||||||
|
|
||||||
|
plugins: [ |
||||||
|
new ForkTsCheckerWebpackPlugin({ |
||||||
|
}), |
||||||
|
new MiniCssExtractPlugin({ |
||||||
|
path: dirs.DEST, |
||||||
|
filename: "bundle.css", |
||||||
|
}), |
||||||
|
new webpack.BannerPlugin({ |
||||||
|
banner: `time: ${new Date().toLocaleString()}`, |
||||||
|
}), |
||||||
|
new OptimizeCssAssetsPlugin({ |
||||||
|
assetNameRegExp: /\.css$/g, |
||||||
|
cssProcessor: require("cssnano"), |
||||||
|
cssProcessorPluginOptions: { |
||||||
|
preset: ["default", { |
||||||
|
discardComments: { |
||||||
|
removeAll: true, |
||||||
|
}, |
||||||
|
normalizeUnicode: false, |
||||||
|
}], |
||||||
|
}, |
||||||
|
canPrint: true, |
||||||
|
}), |
||||||
|
], |
||||||
|
}); |
Loading…
Reference in new issue