From 610a342a82af827ff85e2653eb8abcef4012478a Mon Sep 17 00:00:00 2001 From: youki Date: Tue, 22 Dec 2020 11:28:53 +0800 Subject: [PATCH] =?UTF-8?q?KERNEL-6234=20refactor:=20starter=E6=94=AF?= =?UTF-8?q?=E6=8C=81ts=E5=92=8Ces=E5=86=99=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 4 + .eslintrc | 173 +----------------------- .gitignore | 3 +- .npmrc | 1 + Gruntfile.js | 121 ----------------- README.md | 9 +- babel.config.js | 1 + package.json | 51 ++++--- src/core/javascript/decorator.js | 1 + src/core/typescript/decorator.ts | 3 + src/css/header/header.css | 16 --- src/css/index.css | 0 src/css/list/list.css | 14 -- src/css/main.css | 6 - src/css/nav/nav.css | 0 src/index.js | 14 +- src/index.less | 2 +- src/modules/header/header.js | 133 +++++++++--------- src/modules/list/list.js | 90 ------------- src/modules/list/list.ts | 101 ++++++++++++++ src/modules/main.js | 222 +++++++++++++++---------------- src/types/globals.d.ts | 10 ++ tsconfig.json | 7 + webpack/dirs.js | 9 ++ webpack/webpack.common.js | 63 +++++++++ webpack/webpack.dev.js | 53 ++++++++ webpack/webpack.prod.js | 60 +++++++++ 27 files changed, 544 insertions(+), 623 deletions(-) create mode 100644 .eslintignore create mode 100644 .npmrc delete mode 100644 Gruntfile.js create mode 100644 babel.config.js create mode 100644 src/core/javascript/decorator.js create mode 100644 src/core/typescript/decorator.ts delete mode 100644 src/css/header/header.css delete mode 100644 src/css/index.css delete mode 100644 src/css/list/list.css delete mode 100644 src/css/main.css delete mode 100644 src/css/nav/nav.css delete mode 100644 src/modules/list/list.js create mode 100644 src/modules/list/list.ts create mode 100644 src/types/globals.d.ts create mode 100644 tsconfig.json create mode 100644 webpack/dirs.js create mode 100644 webpack/webpack.common.js create mode 100644 webpack/webpack.dev.js create mode 100644 webpack/webpack.prod.js diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..e401845 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,4 @@ +types +node_modules/ +dist/ +assets/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index b85ad48..63e374d 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,171 +1,8 @@ { - "extends": "eslint:recommended", - "rules": { - // 声明 - "no-use-before-define": "error", - //禁止定义前使用 - - // 对象 - "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 + "extends": "plugin:@fui/typescript", + "parserOptions": { + "ecmaFeatures": { + "legacyDecorators": true + } } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1efa1e2..9719d54 100644 --- a/.gitignore +++ b/.gitignore @@ -48,4 +48,5 @@ crashlytics-build.properties /node_modules/ package-lock.json -yarn.lock \ No newline at end of file +yarn.lock +/dist \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..21e56c3 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +@fui:registry=https://npm.fineres.com/ \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 70aa6fa..0000000 --- a/Gruntfile.js +++ /dev/null @@ -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"]); -}; diff --git a/README.md b/README.md index 78002c7..dde098a 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,14 @@ ## 安装运行 `git clone --recursive https://git.fanruan.com/dailer/FineUI-Start.git` -`npm install` +## 安装依赖 +`yarn install` -`npm run grunt` +## 打开dev模式 +`yarn start` + +## 打包 +`yarn build` ## 示例效果 ![](./screenshorts/todolist.gif) \ No newline at end of file diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..6cf5fff --- /dev/null +++ b/babel.config.js @@ -0,0 +1 @@ +module.exports = require('@fui/babel-preset-fineui').configs.ie8; diff --git a/package.json b/package.json index a65ed87..ae7946f 100644 --- a/package.json +++ b/package.json @@ -7,27 +7,40 @@ "fineui": "^2.0.0" }, "devDependencies": { - "chai": "4.1.2", - "eslint": "4.12.0", - "eslint-plugin-prettier": "2.3.1", - "express": "4.15.2", - "grunt": "1.0.1", - "grunt-contrib-concat": "1.0.1", - "grunt-contrib-connect": "1.0.2", - "grunt-contrib-cssmin": "1.0.1", - "grunt-contrib-jshint": "1.0.0", - "grunt-contrib-less": "1.4.1", - "grunt-contrib-uglify": "1.0.1", - "grunt-contrib-watch": "1.0.0", - "lodash": "4.17.10", - "mocha": "4.0.1", - "open": "0.0.5", - "prettier": "1.8.2" + "@fui/babel-preset-fineui": "^1.0.0", + "@fui/typescript-configs": "^1.0.1", + "@fui/eslint-plugin": "^1.0.7", + "@types/jest": "24.0.11", + "typescript": "3.9.2", + "fork-ts-checker-webpack-plugin": "1.4.3", + "autoprefixer": "9.6.1", + "babel-loader": "8.0.6", + "cross-env": "6.0.0", + "css-loader": "3.0.0", + "html-webpack-plugin": "3.2.0", + "jest": "24.7.1", + "jest-css-modules-transform": "2.5.0", + "jest-environment-jsdom": "24.7.1", + "jest-snapshot": "23.6.0", + "less": "^3.11.3", + "less-loader": "5.0.0", + "mini-css-extract-plugin": "0.7.0", + "npm-run-all": "4.1.5", + "optimize-css-assets-webpack-plugin": "5.0.3", + "postcss-loader": "3.0.0", + "postcss-simple-vars": "5.0.2", + "source-map-loader": "0.2.4", + "style-loader": "0.23.1", + "uglifyjs-webpack-plugin": "2.2.0", + "webpack": "4.35.2", + "webpack-cli": "3.3.5", + "webpack-dev-server": "3.7.2", + "webpack-merge": "4.2.1" }, "scripts": { - "grunt": "grunt", - "uglify": "grunt min", - "eslint": "eslint src --fix" + "start": "webpack-dev-server -p --progress --host 127.0.0.1 --config=webpack/webpack.dev.js --mode development", + "build": "webpack -p --progress --config=webpack/webpack.prod.js --mode production", + "test": "jest" }, "author": "", "license": "MIT" diff --git a/src/core/javascript/decorator.js b/src/core/javascript/decorator.js new file mode 100644 index 0000000..e5f32dd --- /dev/null +++ b/src/core/javascript/decorator.js @@ -0,0 +1 @@ +export const { shortcut, Model, model, store } = BI.Decorators; diff --git a/src/core/typescript/decorator.ts b/src/core/typescript/decorator.ts new file mode 100644 index 0000000..ee94eb1 --- /dev/null +++ b/src/core/typescript/decorator.ts @@ -0,0 +1,3 @@ +export const { shortcut, Model, model, store } = BI.Decorators; + +export type Constructor = new(...args: any[]) => T; diff --git a/src/css/header/header.css b/src/css/header/header.css deleted file mode 100644 index 051de4b..0000000 --- a/src/css/header/header.css +++ /dev/null @@ -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; -} diff --git a/src/css/index.css b/src/css/index.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/css/list/list.css b/src/css/list/list.css deleted file mode 100644 index 7635093..0000000 --- a/src/css/list/list.css +++ /dev/null @@ -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; -} diff --git a/src/css/main.css b/src/css/main.css deleted file mode 100644 index 214161e..0000000 --- a/src/css/main.css +++ /dev/null @@ -1,6 +0,0 @@ -/** - 列表项的less,其中用到了部分FineUI提供的字号,颜色常量,还有border-radius,box-shadow方法等.请选择性使用.不强制要求 - */ -.my-todolist-background { - background-color: #f7f8fa; -} diff --git a/src/css/nav/nav.css b/src/css/nav/nav.css deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.js b/src/index.js index d906090..3a8714d 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,7 @@ -!(function () { - // 将todolist组件挂载到#wrapper上. - BI.createWidget({ - type: "my.todolist", - element: "#wrapper" - }); -})(); +import { ToDoList } from "./modules/main"; + +// 将todolist组件挂载到#wrapper上. +BI.createWidget({ + type: ToDoList.xtype, + element: "#wrapper" +}); diff --git a/src/index.less b/src/index.less index abfac0b..09f8de8 100644 --- a/src/index.less +++ b/src/index.less @@ -1,4 +1,4 @@ -@import "../fineui/src/less/index"; +@import "../node_modules/fineui/src/less/index"; @fontUrl: 'font/'; //字体存放路径 @imageUrl: 'images/1x/'; //图片的基本地址 diff --git a/src/modules/header/header.js b/src/modules/header/header.js index c7ce6e1..6f490ff 100644 --- a/src/modules/header/header.js +++ b/src/modules/header/header.js @@ -1,70 +1,71 @@ -!(function() { - /** - * 顶部组件,提供输入框添加todo项目 - * 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中 - */ - var ToDoListHeader = BI.inherit(BI.Widget, { +import { shortcut } from "../../core/javascript/decorator"; +import "./header.less"; - props: { - // 指定组件的className - baseCls: "my-todolist-header" - }, +/** + * 顶部组件,提供输入框添加todo项目 + * 布局: bi.horizontal_auto 实现水平居中. bi.left_right_vertical_adapt 实现标题是输入框的靠左靠右垂直居中 + */ +@shortcut() +export class ToDoListHeader extends BI.Widget { + static xtype = "my.todolist.header"; - render: function() { - var self = this, o = this.options; - return { - type: "bi.horizontal_auto", // 水平居中布局 - items: [ - { - 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(""); - } - } - ] - } - } - ] - } - } - } - ] - }; - } - }); + static EVENT_ADD = "EVENT_ADD"; + + props = { + // 指定组件的className + baseCls: "my-todolist-header", + } - ToDoListHeader.EVENT_ADD = "EVENT_ADD"; + render() { + const { height } = this.options; - BI.shortcut("my.todolist.header", ToDoListHeader); -})(); \ No newline at end of file + 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(""); + }, + }, + ], + }, + }, + ], + }, + }, + }], + }; + } +} diff --git a/src/modules/list/list.js b/src/modules/list/list.js deleted file mode 100644 index d4e0d3a..0000000 --- a/src/modules/list/list.js +++ /dev/null @@ -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); -})(); \ No newline at end of file diff --git a/src/modules/list/list.ts b/src/modules/list/list.ts new file mode 100644 index 0000000..7a9b1f2 --- /dev/null +++ b/src/modules/list/list.ts @@ -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, +} diff --git a/src/modules/main.js b/src/modules/main.js index 9152cee..e624d9a 100644 --- a/src/modules/main.js +++ b/src/modules/main.js @@ -1,121 +1,119 @@ -!(function() { - /** - * todolist 组件 - */ - var ToDoList = BI.inherit(BI.Widget, { +import { shortcut } from "../core/javascript/decorator"; +import { ToDoListHeader } from "./header/header"; +import { List } from "./list/list"; +import "./main.less"; - props: { - baseCls: "fine-to-do-list" - }, +/** + * todolist 组件 + */ +@shortcut() +export class ToDoList extends BI.Widget { + static xtype = "my.todolist"; - // 生命周期函数,在组件创建前 - beforeCreate: function() { - // 初始化存储数据 - this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : []; - }, + props = { + baseCls: "fine-to-do-list", + } - render: function() { - var self = this, o = this.options; - return { - type: "bi.vtape", // vtape布局,顶部高度固定,下部分列表占满高度 - items: [ - { - el: { - type: "my.todolist.header", // 顶部组件 - listeners: [ - { // 监听组件的EVENT_ADD事件,新建todo项 - eventName: "EVENT_ADD", - action: function(v) { - self.addToDo(v); - } - } - ], - height: 40 - }, - height: 40 - }, { - type: "bi.horizontal_auto", // 水平居中布局 - cls: "my-todolist-background", // 添加className - items: [ - { - el: { - type: "my.todolist.list", // need todo项列表 - ref: function(_ref) { - self.todolist = _ref; - }, - items: this._getNeedTodoList(), - text: "正在进行", - listeners: [ - { // 监听EVENT_CHANGE事件,完成某一项todo - eventName: "EVENT_CHANGE", - action: function(v) { - self.finishTodo(v); - } - } - ], - width: 600 - } - }, { - el: { - type: "my.todolist.list", // 已经完成的todo项列表 - text: "已经完成", - items: this._getAlreadyDoneList(), - ref: function(_ref) { - self.donelist = _ref; + // 生命周期函数,在组件创建前 + beforeCreate() { + // 初始化存储数据 + this.list = localStorage.getItem("fine-todolist") ? JSON.parse(localStorage.getItem("fine-todolist")) : []; + } + + render() { + return { + type: BI.VTapeLayout.xtype, // vtape布局,顶部高度固定,下部分列表占满高度 + items: [ + { + el: { + type: ToDoListHeader.xtype, // 顶部组件 + listeners: [ + { // 监听组件的EVENT_ADD事件,新建todo项 + eventName: "EVENT_ADD", + action: v => { + this.addToDo(v); + }, + }, + ], + height: 40, + }, + height: 40, + }, { + type: BI.HorizontalAutoLayout.xtype, // 水平居中布局 + cls: "my-todolist-background", // 添加className + items: [ + { + el: { + type: List.xtype, // need todo项列表 + ref: _ref => { + this.todolist = _ref; + }, + items: this._getNeedTodoList(), + text: "正在进行", + listeners: [ + { // 监听EVENT_CHANGE事件,完成某一项todo + eventName: "EVENT_CHANGE", + action: v => { + this.finishTodo(v); + }, }, - width: 600 - } - } - ] - } - ] - }; - }, + ], + width: 600, + }, + }, { + el: { + type: List.xtype, // 已经完成的todo项列表 + text: "已经完成", + items: this._getAlreadyDoneList(), + ref: _ref => { + this.donelist = _ref; + }, + width: 600, + }, + }, + ], + }], + }; + } - _updateLocalStorage: function() { - localStorage.setItem("fine-todolist", JSON.stringify(this.list)); - }, + _updateLocalStorage() { + localStorage.setItem("fine-todolist", JSON.stringify(this.list)); + } - _getNeedTodoList: function() { - return BI.filter(this.list, function(index, item) { - return !item.done; - }); - }, + _getNeedTodoList() { + return BI.filter(this.list, (index, item) => !item.done); + } - _getAlreadyDoneList: function() { - return BI.filter(this.list, function(index, item) { - return item.done; - }); - }, + _getAlreadyDoneList() { + return BI.filter(this.list, (index, item) => item.done); + } - /** - * 添加todo项 - * @param text todo项的内容 - */ - addToDo: function(text) { - this.list.push({ - value: BI.UUID(), - text: text, - done: false - }); - this.todolist.populate(this._getNeedTodoList()); - this._updateLocalStorage(); - }, + /** + * 添加todo项 + * @param text todo项的内容 + */ + addToDo(text) { + this.list.push({ + value: BI.UUID(), + text, + done: false, + }); + this.todolist.populate(this._getNeedTodoList()); + this._updateLocalStorage(); + } - /** - * 完成某一项todo - * @param v todo项的value - */ - finishTodo: function(v) { - BI.some(this.list, function(index, item) { - if (item.value === v) { - item.done = true; - } - }); - this.todolist.populate(this._getNeedTodoList()); - this.donelist.populate(this._getAlreadyDoneList()); - this._updateLocalStorage(); - } - }); - BI.shortcut("my.todolist", ToDoList); -})(); + /** + * 完成某一项todo + * @param v todo项的value + */ + finishTodo(v) { + BI.some(this.list, (index, item) => { + if (item.value === v) { + item.done = true; + } + }); + this.todolist.populate(this._getNeedTodoList()); + this.donelist.populate(this._getAlreadyDoneList()); + this._updateLocalStorage(); + } +} diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts new file mode 100644 index 0000000..6a28a08 --- /dev/null +++ b/src/types/globals.d.ts @@ -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; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9459ffe --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "@fui/typescript-configs/application.json", + "compilerOptions": { + "strict": false, + "allowJs": true, + }, +} diff --git a/webpack/dirs.js b/webpack/dirs.js new file mode 100644 index 0000000..09fc4e7 --- /dev/null +++ b/webpack/dirs.js @@ -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"), +}; diff --git a/webpack/webpack.common.js b/webpack/webpack.common.js new file mode 100644 index 0000000..fa765f5 --- /dev/null +++ b/webpack/webpack.common.js @@ -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, + }, + }, + ], + }, + ], + }, +}; diff --git a/webpack/webpack.dev.js b/webpack/webpack.dev.js new file mode 100644 index 0000000..190be31 --- /dev/null +++ b/webpack/webpack.dev.js @@ -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, + }), + ], +}); diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js new file mode 100644 index 0000000..29b363d --- /dev/null +++ b/webpack/webpack.prod.js @@ -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, + }), + ], +});