├── config ├── dev.config.js ├── prod.config.js ├── webpack.dev.js ├── webpack.prod.js └── webpack.common.js ├── src ├── script │ ├── testEntryCheck.js │ ├── index.js │ ├── stylus.js │ ├── demoPage │ │ └── display.js │ ├── date-manager.js │ └── demo.js ├── static │ ├── img │ │ ├── bg-1.jpg │ │ ├── calc.png │ │ ├── logo.png │ │ ├── src.png │ │ ├── host-set.png │ │ ├── proxy-set.png │ │ ├── select-html.png │ │ ├── global-import.png │ │ └── import-select.png │ ├── iconfont │ │ ├── iconfont.eot │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ ├── iconfont.woff2 │ │ ├── iconfont.json │ │ ├── iconfont.css │ │ ├── iconfont.svg │ │ ├── iconfont.js │ │ ├── demo.css │ │ └── demo_index.html │ └── data │ │ └── data.json ├── style │ ├── stylus.styl │ ├── demo.sass │ └── index.sass ├── plugin │ ├── el-select │ │ ├── chevron-down.svg │ │ ├── select.sass │ │ └── index.js │ ├── arithmetic │ │ ├── stack.js │ │ └── index.js │ └── date-manager.js └── view │ ├── stylus.html │ ├── index.html │ └── demo.html ├── static ├── logo.png └── index-page.png ├── .babelrc ├── modules ├── create-define-plugin.js ├── style-file-loader-config.js └── html-webpack-config.js ├── README.md ├── server.js ├── package.json └── .gitignore /config/dev.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | API: './', 3 | }; 4 | -------------------------------------------------------------------------------- /config/prod.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | API: '../', 3 | }; 4 | -------------------------------------------------------------------------------- /src/script/testEntryCheck.js: -------------------------------------------------------------------------------- 1 | /* 该文件在这里只是用来测试入口文件与html的匹配情况,无其他作用 */ 2 | -------------------------------------------------------------------------------- /static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/static/logo.png -------------------------------------------------------------------------------- /static/index-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/static/index-page.png -------------------------------------------------------------------------------- /src/static/img/bg-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/bg-1.jpg -------------------------------------------------------------------------------- /src/static/img/calc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/calc.png -------------------------------------------------------------------------------- /src/static/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/logo.png -------------------------------------------------------------------------------- /src/static/img/src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/src.png -------------------------------------------------------------------------------- /src/style/stylus.styl: -------------------------------------------------------------------------------- 1 | #test 2 | height 100px 3 | width 100px 4 | background radial-gradient(#007aff 20%, #5856d6 80%) -------------------------------------------------------------------------------- /src/static/img/host-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/host-set.png -------------------------------------------------------------------------------- /src/static/img/proxy-set.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/proxy-set.png -------------------------------------------------------------------------------- /src/static/img/select-html.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/select-html.png -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/iconfont/iconfont.eot -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/static/img/global-import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/global-import.png -------------------------------------------------------------------------------- /src/static/img/import-select.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/img/import-select.png -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robustNan/jQuery-development-environment/HEAD/src/static/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/style/demo.sass: -------------------------------------------------------------------------------- 1 | @import '../static/iconfont/iconfont.css' 2 | 3 | body 4 | padding-bottom: 150px 5 | 6 | .pricing-card-title 7 | color: orange 8 | 9 | #css-bg 10 | background: url(../static/img/bg-1.jpg) no-repeat 11 | background-size: 100% -------------------------------------------------------------------------------- /src/script/index.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap'; 2 | 3 | import 'bootstrap/scss/bootstrap.scss'; 4 | import '../style/index.sass'; 5 | import displayState from './demoPage/display'; 6 | 7 | console.warn(`mode is: ${process.env.NODE_ENV}`); 8 | console.warn(displayState); //引入并打印是为了测试共同引用模块的打包 9 | -------------------------------------------------------------------------------- /src/plugin/el-select/chevron-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/env", 5 | { 6 | "targets": { 7 | "edge": "17", 8 | "firefox": "60", 9 | "chrome": "67", 10 | "safari": "11.1", 11 | "ie": "11" 12 | }, 13 | "corejs": "3", 14 | "useBuiltIns": "usage" 15 | } 16 | ] 17 | ] 18 | } -------------------------------------------------------------------------------- /src/style/index.sass: -------------------------------------------------------------------------------- 1 | $theme: #03a9f4 2 | 3 | body 4 | // background: tomato 5 | 6 | h1 7 | color: $theme 8 | margin-bottom: 50px 9 | margin-top: 150px 10 | text-align: center 11 | 12 | .container 13 | 14 | #des 15 | text-indent: 15px 16 | 17 | #link 18 | text-align: right 19 | 20 | .row:last-of-type 21 | margin-top: 50px -------------------------------------------------------------------------------- /src/script/stylus.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap'; 2 | import 'bootstrap/scss/bootstrap.scss'; 3 | 4 | // import '../plugin/date-picker'; 5 | 6 | import '../style/stylus.styl'; 7 | 8 | /* $(function () { 9 | $('#date').datePicker({ isEn: true }); 10 | $('#date-range').datePicker({ 11 | default: { 12 | start: '2020-09-07', 13 | end: '2020-09-07', 14 | }, 15 | range: true, 16 | }); 17 | }); */ 18 | -------------------------------------------------------------------------------- /config/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 3 | 4 | module.exports = { 5 | mode: 'development', 6 | devtool: 'cheap-module-eval-source-map', //inline-source-map 7 | plugins: [ 8 | new webpack.HotModuleReplacementPlugin(), 9 | new MiniCssExtractPlugin({ 10 | filename: 'css/[name].css', 11 | }), 12 | ], 13 | }; 14 | -------------------------------------------------------------------------------- /modules/create-define-plugin.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | 3 | /** 4 | * @author cooper 5 | * @description 根据dev.config.js或prod.config.js设定的值创建DefinePlugin,前端页面可全局调用这些值 6 | * @param {Object} | options 7 | * @returns {webpack.DefinePlugin} 8 | */ 9 | module.exports = (options) => { 10 | const obj = {}; 11 | for (const key in options) { 12 | const value = options[key]; 13 | obj[key] = JSON.stringify(value); 14 | } 15 | return new webpack.DefinePlugin(obj); 16 | }; 17 | -------------------------------------------------------------------------------- /src/plugin/arithmetic/stack.js: -------------------------------------------------------------------------------- 1 | export default class { 2 | constructor() { 3 | this.stack = []; 4 | } 5 | 6 | getLength() { 7 | return this.stack.length; 8 | } 9 | 10 | peek() { 11 | const len = this.getLength(); 12 | return len ? this.stack[len - 1] : undefined; 13 | } 14 | 15 | pop() { 16 | return this.stack.pop(); 17 | } 18 | 19 | push(num) { 20 | this.stack.push(num); 21 | return undefined; 22 | } 23 | 24 | reset() { 25 | this.stack = []; 26 | return undefined; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/view/stylus.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | date-picker 7 | 8 | 9 |
stylus
10 | 11 |
12 |
13 | 14 |
15 | 16 |
17 | 18 |
-
19 | 20 |
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![LOGO](https://github.com/robustNan/jQuery-development-environment/blob/master/static/logo.png) 2 | 3 | ![首页截图](https://github.com/robustNan/jQuery-development-environment/blob/master/static/index-page.png) 4 | 5 | # JQDE 6 | 7 | 基于 Webpack 搭建的 jQuery 项目开发环境(jQuery development environment),使 jQuery 项目能够以前后端分离模式进行开发,这是一种有效提高开发效率的先进模式。利用此环境前端开发人员无需搭建后台环境,只需要配置相应的代理地址即可实现前后端的数据流通。并且此环境配置了对 Sass 和 Stylus 两种 CSS 样式预编译语言的配置,可以直接使用这些语言高效快速的编写界面样式。 8 | 9 | 附加仿Element样式Select插件 10 | 11 | **安装依赖** 12 | 13 | `* 推荐使用cnpm安装,避免npm安装导致部分依赖安装失败` 14 | 15 | ```shell 16 | $ cnpm install 17 | $ cnpm i 18 | $ npm install 19 | $ npm i 20 | ``` 21 | 22 | **启动环境** 23 | 24 | ```shell 25 | $ npm start 26 | ``` 27 | 28 | **打包输出** 29 | 30 | ```shell 31 | $ npm run build 32 | ``` 33 | 34 | **node-sass升级** 35 | 36 | `* 已针对node14版本进行修改,如果使用的node版本不同,需要替换对应版本的node-sass` 37 | https://www.npmjs.com/package/node-sass 38 | -------------------------------------------------------------------------------- /src/script/demoPage/display.js: -------------------------------------------------------------------------------- 1 | export default function displayState(data) { 2 | const currentData = [ 3 | { 4 | /* 全球确诊 */ 5 | id: 'global', 6 | count: data.globalStatistics.confirmedCount, 7 | add: data.globalStatistics.confirmedIncr, 8 | }, 9 | { 10 | /* 国外确诊 */ 11 | id: 'foreign', 12 | count: data.foreignStatistics.confirmedCount, 13 | add: data.foreignStatistics.confirmedIncr, 14 | }, 15 | { 16 | /* 国内确诊 */ 17 | id: 'demostic', 18 | count: data.confirmedCount, 19 | add: data.confirmedIncr, 20 | }, 21 | ]; 22 | 23 | for (const iterator of currentData) { 24 | $(`#${iterator.id}`) 25 | .children('h1') 26 | .html(`${iterator.count} / 例`) 27 | .next() 28 | .children() 29 | .text(iterator.add > 0 ? `+${iterator.add}` : iterator.add); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/view/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | JQDE 7 | 8 | 9 |
10 |
11 | 12 |

Hello, JQDE!

13 |

14 | 基于Webpack搭建的用于jQuery多页面项目的开发环境,融入了jQuery,Lodash,Echarts和Bootstrap4库。借助Webpack,让jQuery项目开发前后端分离。 15 |

16 |
17 |

18 | 在使用本环境进行开发前请先对 19 | Webpack 20 | 有所了解 21 |

22 | Learn more 23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /modules/style-file-loader-config.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 2 | 3 | /** 4 | * @author cooper 5 | * @description 根据入参判定是否启用热重载 6 | * @param {Boolean} | isOn 7 | * @returns {Array} 8 | */ 9 | module.exports = (isOn) => { 10 | const baseLoader = [ 11 | { 12 | loader: MiniCssExtractPlugin.loader, 13 | options: { 14 | publicPath: '../', 15 | hmr: isOn, //热重载相关 16 | reloadAll: isOn, //热重载相关 17 | }, 18 | }, 19 | 'css-loader', 20 | ]; 21 | 22 | return [ 23 | { 24 | test: /\.styl$/, 25 | use: [...baseLoader, 'stylus-loader'], 26 | }, 27 | { 28 | test: /\.(sa|sc)ss$/, 29 | use: [ 30 | ...baseLoader, 31 | { 32 | loader: 'postcss-loader', // Run postcss actions 33 | options: { 34 | plugins: function () { 35 | // postcss plugins, can be exported to postcss.config.js 36 | return [require('autoprefixer')]; 37 | }, 38 | }, 39 | }, 40 | 'sass-loader', 41 | ], 42 | }, 43 | { 44 | test: /\.css$/, 45 | use: baseLoader, 46 | }, 47 | ]; 48 | }; 49 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | const path = require('path'); 3 | const webpackDevServer = require('webpack-dev-server'); 4 | const webpack = require('webpack'); 5 | 6 | const commonConfig = require('./config/webpack.common'); 7 | const devConfig = require('./config/webpack.dev'); 8 | const getStyleRules = require('./modules/style-file-loader-config'); 9 | 10 | const dotenv = require('dotenv'); 11 | dotenv.config('./env'); 12 | 13 | const NODE_ENV = process.env.NODE_ENV; 14 | const config = merge(commonConfig, devConfig, { 15 | module: { 16 | rules: getStyleRules(NODE_ENV === 'development'), 17 | }, 18 | }); 19 | 20 | const devServerOptions = { 21 | contentBase: path.join(__dirname, './dist'), 22 | host: process.env.HOST, 23 | hot: true, 24 | open: true, 25 | proxy: { 26 | '/txapi': { 27 | target: 'http://api.tianapi.com', 28 | changeOrigin: true, 29 | }, 30 | }, 31 | overlay: { 32 | errors: true, // 编译出现错误时,错误直接贴到页面上 33 | }, 34 | }; 35 | 36 | webpackDevServer.addDevServerEntrypoints(config, devServerOptions); 37 | const compiler = webpack(config); 38 | const server = new webpackDevServer(compiler, devServerOptions); 39 | 40 | server.listen(process.env.PORT, 'localhost', () => { 41 | console.log(`dev server listening on port ${process.env.PORT}`); 42 | }); 43 | -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "1689502", 3 | "name": "chanyedashuju", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "icon-", 6 | "description": "", 7 | "glyphs": [ 8 | { 9 | "icon_id": "5387588", 10 | "name": "箭头_向下", 11 | "font_class": "jiantou_xiangxia", 12 | "unicode": "eb0a", 13 | "unicode_decimal": 60170 14 | }, 15 | { 16 | "icon_id": "5387589", 17 | "name": "箭头_向上", 18 | "font_class": "jiantou_xiangshang", 19 | "unicode": "eb0b", 20 | "unicode_decimal": 60171 21 | }, 22 | { 23 | "icon_id": "11488026", 24 | "name": "double-arro- right", 25 | "font_class": "double-arro-right", 26 | "unicode": "e74c", 27 | "unicode_decimal": 59212 28 | }, 29 | { 30 | "icon_id": "1368661", 31 | "name": "3d", 32 | "font_class": "d", 33 | "unicode": "e625", 34 | "unicode_decimal": 58917 35 | }, 36 | { 37 | "icon_id": "7685206", 38 | "name": "power", 39 | "font_class": "power", 40 | "unicode": "e71d", 41 | "unicode_decimal": 59165 42 | }, 43 | { 44 | "icon_id": "11758144", 45 | "name": "柱状图", 46 | "font_class": "zhuzhuangtu", 47 | "unicode": "e748", 48 | "unicode_decimal": 59208 49 | } 50 | ] 51 | } 52 | -------------------------------------------------------------------------------- /config/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 2 | const WebpackProgressOraPlugin = require('webpack-progress-ora-plugin'); 3 | 4 | module.exports = { 5 | mode: 'production', 6 | devtool: 'source-map', //source-map 7 | optimization: { 8 | splitChunks: { 9 | chunks: 'all', 10 | minSize: 30000, //表示在压缩前的最小模块大小,默认值是30kb 11 | minChunks: 1, // 表示被引用次数,默认为1; 12 | maxAsyncRequests: 6, //所有异步请求不得超过6个 13 | maxInitialRequests: 4, //初始话并行请求不得超过4个 14 | automaticNameDelimiter: '~', //名称分隔符 15 | name: true, //打包后的名称,默认是chunk的名字通过分隔符(默认是~)分隔 16 | /* 设置缓存组用来抽取满足不同规则的chunk */ 17 | cacheGroups: { 18 | utilCommon: { 19 | // 抽离自定义工具库 20 | name: 'common', 21 | minSize: 0, // 将引用模块分离成新代码文件的最小体积 22 | minChunks: 2, // 表示将引用模块如不同文件引用了多少次,才能分离生成新chunk 23 | priority: -20, 24 | }, 25 | vendors: { 26 | // 抽离第三方插件 27 | test: /[\\/]node_modules[\\/]/, // 指定是node_modules下的第三方包 28 | name: 'vendors', 29 | priority: -10, // 抽取优先级 30 | }, 31 | }, 32 | }, 33 | }, 34 | plugins: [ 35 | new MiniCssExtractPlugin({ 36 | filename: 'css/[name]-[hash].css', 37 | }), 38 | new WebpackProgressOraPlugin({ 39 | stderr_check: true, 40 | interval: 300, 41 | }), 42 | ], 43 | }; 44 | -------------------------------------------------------------------------------- /modules/html-webpack-config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const glob = require('glob'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | 5 | /** 6 | * @cooper 7 | * @description 根据/src/script下的js文件名称动态生成入口配置对象 8 | * @returns {Object} 9 | */ 10 | function getEntry() { 11 | const entry = {}; 12 | const list = glob.sync('./src/script/*.js'); 13 | list.forEach(function (path) { 14 | const [flag, suffix] = ['script/', '.js']; 15 | const start = path.indexOf(flag) + flag.length; 16 | const end = path.length - suffix.length; 17 | const name = path.slice(start, end); 18 | if (fs.existsSync(`./src/view/${name}.html`)) entry[name] = path; //判定入口文件是否存在对应的html 19 | }); 20 | return entry; 21 | } 22 | 23 | /** 24 | * @cooper 25 | * @description 根据传入的入口文件名称返回HtmlWebpackPlugin所需配置对象 26 | * @param {String} | name 27 | * @returns {Object} 28 | */ 29 | function getHtmlConfig(name) { 30 | return { 31 | chunks: [name], 32 | template: `./src/view/${name}.html`, 33 | filename: `${name}.html`, 34 | favicon: './static/logo.png', //该配置回导致在html同级目录下多出一个logo.png文件 35 | hash: true, 36 | inject: 'body', 37 | }; 38 | } 39 | 40 | /** 41 | * @cooper 42 | * @description 根据getEntry返回的入口配置对象分别创建HtmlWebpackPlugin 43 | * @param {Object} | entries 44 | * @returns {Array} 45 | */ 46 | function createHtmlWebpackPlugin(entries) { 47 | const pluginArr = []; 48 | for (const key in entries) { 49 | if (entries.hasOwnProperty(key)) { 50 | const configOptions = getHtmlConfig(key); 51 | pluginArr.push(new HtmlWebpackPlugin(configOptions)); 52 | } 53 | } 54 | return pluginArr; 55 | } 56 | 57 | module.exports = { getEntry, createHtmlWebpackPlugin }; 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jqde", 3 | "version": "1.0.0", 4 | "description": "jQuery development environment", 5 | "scripts": { 6 | "build": "cross-env NODE_ENV=production node build.js", 7 | "start": "cross-env NODE_ENV=development node server.js" 8 | }, 9 | "keywords": [ 10 | "jquery" 11 | ], 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/robustNan/jQuery-development-environment" 15 | }, 16 | "homepage": "https://github.com/robustNan/jQuery-development-environment#readme", 17 | "author": "Cooper", 18 | "license": "ISC", 19 | "devDependencies": { 20 | "@babel/cli": "^7.8.4", 21 | "@babel/core": "^7.9.0", 22 | "@babel/preset-env": "^7.9.0", 23 | "autoprefixer": "^9.7.5", 24 | "babel-loader": "^8.1.0", 25 | "clean-webpack-plugin": "^3.0.0", 26 | "cross-env": "^7.0.2", 27 | "css-loader": "^3.4.2", 28 | "dotenv": "^8.2.0", 29 | "file-loader": "^6.0.0", 30 | "glob": "^7.1.6", 31 | "html-loader": "^1.0.0", 32 | "html-webpack-plugin": "^4.0.1", 33 | "mini-css-extract-plugin": "^0.9.0", 34 | "mkdirp": "^1.0.3", 35 | "node-sass": "^4.14.1", 36 | "postcss-loader": "^3.0.0", 37 | "sass-loader": "^8.0.2", 38 | "single-line-log": "^1.1.2", 39 | "stylus": "^0.54.7", 40 | "stylus-loader": "^3.0.2", 41 | "true-case-path": "^2.2.1", 42 | "webpack": "^4.42.1", 43 | "webpack-cli": "^3.3.11", 44 | "webpack-dev-server": "^3.11.2", 45 | "webpack-merge": "^4.2.2", 46 | "webpack-progress-ora-plugin": "^1.2.2" 47 | }, 48 | "dependencies": { 49 | "@babel/polyfill": "^7.8.7", 50 | "bootstrap": "^4.4.1", 51 | "core-js": "^3.6.4", 52 | "daterangepicker": "^3.1.0", 53 | "echarts": "^4.7.0", 54 | "jquery": "^3.6.0", 55 | "lodash": "^4.17.21", 56 | "moment": "^2.27.0", 57 | "popper.js": "^1.16.1" 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/plugin/date-manager.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * @author jiaojiannan 4 | * @description 获取十二个月分 5 | */ 6 | allMonths() { 7 | const months = []; 8 | for (let i = 1; i < 13; i++) months.push({ value: i, text: i + ' 月' }); 9 | return months; 10 | }, 11 | 12 | /** 13 | * @author jiaojiannan 14 | * @description 根据年份、月分获取当月天数的数据 15 | * @param {Number} year 16 | * @param {Number} month 1-12 17 | */ 18 | daysInMonth(year, month) { 19 | const [days, leng] = [[], this.getMonthLength(year, month)]; 20 | for (let i = 1; i <= leng; i++) days.push({ value: i, text: i + ' 日' }); 21 | return days; 22 | }, 23 | 24 | /** 25 | * @author jiaojiannan 26 | * @description 根据年份、月分获取当月总计天数 27 | * @param {Number} year 28 | * @param {Number} month 1-12 29 | */ 30 | getMonthLength(year, month) { 31 | const [datumYear, datumMonth] = [ 32 | 12 === month ? year + 1 : year, 33 | 12 === month ? 1 : month + 1, 34 | ]; //需要将月分向后推一个月 35 | const datum = new Date(datumYear + '-' + datumMonth); 36 | datum.setDate(0); //设置到指定月份最后一天 37 | return datum.getDate(); 38 | }, 39 | 40 | /** 41 | * @author jiaojiannan 42 | * @description 根据传入参数获取近几年,默认六年 43 | * @param {Number} range 44 | * @param {Number} maxYear 45 | */ 46 | nearlyYears(range = 6, maxYear) { 47 | const years = []; 48 | let max = maxYear ? maxYear : new Date().getFullYear(); 49 | for (let i = 0; i < range; i++) { 50 | const year = max - i; 51 | years.push({ value: year, text: year + ' 年' }); 52 | } 53 | return years; 54 | }, 55 | 56 | /** 57 | * @author jiaojiannan 58 | * @description 根据传入时间对象及分隔符输出日期字符串 59 | * @param {Date} date 60 | * @param {String} symbol 61 | */ 62 | formatterDate(date, symbol) { 63 | return ( 64 | date.getFullYear() + 65 | symbol + 66 | (date.getMonth() + 1) + 67 | symbol + 68 | date.getDate() 69 | ); 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /src/script/date-manager.js: -------------------------------------------------------------------------------- 1 | export default { 2 | /** 3 | * @author jiaojiannan 4 | * @description 获取十二个月分 5 | */ 6 | allMonths() { 7 | const months = []; 8 | for (let i = 1; i < 13; i++) months.push({ value: i, text: i + ' 月' }); 9 | return months; 10 | }, 11 | 12 | /** 13 | * @author jiaojiannan 14 | * @description 根据年份、月分获取当月天数的数据 15 | * @param {Number} year 16 | * @param {Number} month 1-12 17 | */ 18 | daysInMonth(year, month) { 19 | const [days, leng] = [[], this.getMonthLength(year, month)]; 20 | for (let i = 1; i <= leng; i++) days.push({ value: i, text: i + ' 日' }); 21 | return days; 22 | }, 23 | 24 | /** 25 | * @author jiaojiannan 26 | * @description 根据年份、月分获取当月总计天数 27 | * @param {Number} year 28 | * @param {Number} month 1-12 29 | */ 30 | getMonthLength(year, month) { 31 | const [datumYear, datumMonth] = [ 32 | 12 === month ? year + 1 : year, 33 | 12 === month ? 1 : month + 1, 34 | ]; //需要将月分向后推一个月 35 | const datum = new Date(datumYear + '-' + datumMonth); 36 | datum.setDate(0); //设置到指定月份最后一天 37 | return datum.getDate(); 38 | }, 39 | 40 | /** 41 | * @author jiaojiannan 42 | * @description 根据传入参数获取近几年,默认六年 43 | * @param {Number} range 44 | * @param {Number} maxYear 45 | */ 46 | nearlyYears(range = 6, maxYear) { 47 | const years = []; 48 | let max = maxYear ? maxYear : new Date().getFullYear(); 49 | for (let i = 0; i < range; i++) { 50 | const year = max - i; 51 | years.push({ value: year, text: year + ' 年' }); 52 | } 53 | return years; 54 | }, 55 | 56 | /** 57 | * @author jiaojiannan 58 | * @description 根据传入时间对象及分隔符输出日期字符串 59 | * @param {Date} date 60 | * @param {String} symbol 61 | */ 62 | formatterDate(date, symbol) { 63 | return ( 64 | date.getFullYear() + 65 | symbol + 66 | (date.getMonth() + 1) + 67 | symbol + 68 | date.getDate() 69 | ); 70 | }, 71 | }; 72 | -------------------------------------------------------------------------------- /config/webpack.common.js: -------------------------------------------------------------------------------- 1 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 2 | const path = require('path'); 3 | const webpack = require('webpack'); 4 | 5 | const getDefinePlugin = require('../modules/create-define-plugin'); 6 | const { 7 | getEntry, 8 | createHtmlWebpackPlugin, 9 | } = require('../modules/html-webpack-config'); 10 | const entries = getEntry(); //获取到所有入口文件 11 | 12 | /* 根据 process.env.NODE_ENV 生成对应 DefinePlugin */ 13 | const DefinePlugin = 14 | process.env.NODE_ENV === 'development' 15 | ? getDefinePlugin(require('./dev.config')) 16 | : getDefinePlugin(require('./prod.config')); 17 | 18 | module.exports = { 19 | entry: entries, 20 | output: { 21 | filename: 'js/[name]-[hash].js', 22 | path: path.resolve(__dirname, '../dist'), 23 | }, 24 | module: { 25 | rules: [ 26 | { 27 | test: /\.(woff|woff2|eot|ttf|otf)$/, 28 | use: { 29 | loader: 'file-loader', 30 | options: { 31 | name: '[name]-[hash].[ext]', 32 | outputPath: 'font', 33 | }, 34 | }, 35 | }, 36 | { 37 | test: /\.(png|svg|jpg|gif)$/, 38 | use: [ 39 | { 40 | loader: 'file-loader', 41 | options: { 42 | name: '[name]-[hash].[ext]', 43 | outputPath: 'img', 44 | }, 45 | }, 46 | ], 47 | }, 48 | { 49 | test: /\.js$/, 50 | exclude: /[\\/]node_modules[\\/]/, 51 | loader: 'babel-loader', 52 | }, 53 | { 54 | test: /\.html$/, 55 | use: [ 56 | { 57 | loader: 'html-loader', 58 | options: { 59 | attributes: true, 60 | }, 61 | }, 62 | ], 63 | }, 64 | ], 65 | }, 66 | plugins: [ 67 | new CleanWebpackPlugin(), 68 | /* 全局引入jquery、lodash、echarts */ 69 | new webpack.ProvidePlugin({ 70 | $: 'jquery', 71 | jQuery: 'jquery', 72 | jquery: 'jquery', 73 | _: 'lodash', 74 | echarts: 'echarts', 75 | moment: 'moment', 76 | Popper: ['popper.js', 'default'], 77 | }), 78 | DefinePlugin, 79 | ...createHtmlWebpackPlugin(entries), 80 | ], 81 | }; 82 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # Vscode config file 107 | .vscode 108 | /package-lock.json 109 | -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face {font-family: "iconfont"; 2 | src: url('iconfont.eot?t=1584330793137'); /* IE9 */ 3 | src: url('iconfont.eot?t=1584330793137#iefix') format('embedded-opentype'), /* IE6-IE8 */ 4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAQYAAsAAAAACNQAAAPLAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDVgqEDINIATYCJAMcCxAABCAFhG0HfRu1BxEVnFPJfiTGMSnrzPIqmmg3EzxfOfV97QqyChSYTwBslwCcAjApjadHujkA9l17P8I2oSLMofx25NEepnCUvjQd/fwx00XaBpbPvs0lKykScFZAA9pFNsgBlsiB+D3Asxr8T8DlEMCQixJI7bqNW+Oh0bcTQAb269MNL2FEV1QKHoJTcKhGFmPjWXOs+8Ai7/clSjnxwMJW6Ls2712nJ9V/Foz6KhKL0NHBIBrODvBHgQJKABpkcqFzLCpIlkBh1JdoGgPxeFjonwWDnEH9oHHUj8USOCPVvUK8UQwaG2fAfzwLxIHK4wFoi3qHIxRZCBqCnAg2BPURHAgaIyiIGgSBqH8EFgAuAImQng3cR2IFpVyCQlNOXJzjZNE6vVAaffEhttGh5m3CLcdoY7duGW7TfEyvnlXDoZBz2wndV87N0HX5bqzInozdVszL3GPVPlHJe7t369q9TDeL21X1sMas3A6RNRlfvGj9/Lm58mXo1avwqnUiyTszJGVtCnhk+xZ+iaHkvZlMLyt8f94+GaN9uy+dwXT0XTPWV6bYyc6hdtOmXUrVE+coNrxdwnYu9ZfBQ3uGlZkY6oMU3/mSGTMR7cOvlFoqpRtT7dL//Cl2zuv4tLPSxvu+00G+AJUpicDgJXn2G7VB7v0dcu/osqOD94m6sz1YZkwjf8v0piVCW03PhEGrVg9JWOLfOqEWEm69sG7R6Vv8RsYsi1RclmpWJK198mpdhtuJ6f7bN2T24mdfp8dzuPJh4puBPr6ydQq+NJg7Z27jOXPSzbmWdnZkdnwtSDWczWT0KSuqMtGaqoS1CmKXVURVh+RadVS1S2IH/IUAAhvq/3e7JFX+4/kagLcrshbFQGytprnwS6pQRZ9c1HBIaxLd5Gqls9WCAC6VYl/BAgwG+NTedHwcTp2xcTkIHhkjsHDJCQqPAlhNLAE2PhXAwaMaGIpT72if9AxHIToOKMYMACENh8AikUugSMMDrCZ+AJtM/AaHNKLAEJL0p/QpJDp7eGSsBFuo/8A2NCnTIge/8g11GCqOSzzGF7K3EcjiNJ15xQl5iD38t85FFCimEV7gajgMBI6pw0ZiI+JuSaKKPihuaJwdeGSsBFug/gNsQ5NyJssh8/NvqMNQcUVblfsL2dvlgYyYtAH2VTk1aruUp/hvnSOiAMU0Ai9gx8FIEuCKN+qwkRjTIe5uJDRONVXG06vH+7wAGPQ7uGKJEi22OOKKx11/W01Cofj15NoefUjpvcE73rcU6gGjipkittrIvF07+kE+/ptg8qsDEmYzAA==') format('woff2'), 5 | url('iconfont.woff?t=1584330793137') format('woff'), 6 | url('iconfont.ttf?t=1584330793137') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ 7 | url('iconfont.svg?t=1584330793137#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family: "iconfont" !important; 12 | font-size: 16px; 13 | font-style: normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-jiantou_xiangxia:before { 19 | content: "\eb0a"; 20 | } 21 | 22 | .icon-jiantou_xiangshang:before { 23 | content: "\eb0b"; 24 | } 25 | 26 | .icon-double-arro-right:before { 27 | content: "\e74c"; 28 | } 29 | 30 | .icon-d:before { 31 | content: "\e625"; 32 | } 33 | 34 | .icon-power:before { 35 | content: "\e71d"; 36 | } 37 | 38 | .icon-zhuzhuangtu:before { 39 | content: "\e748"; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/plugin/el-select/select.sass: -------------------------------------------------------------------------------- 1 | $bg-color: #fff //背景色 2 | $border-color: #dcdfe6 //边框颜色 3 | $font-color: #606266 //文字颜色 4 | $hover-color: #f5f7fa //下拉选项鼠标经过颜色 5 | $border-hover: #c0c4cc //Select框鼠标移入颜色 6 | $triangle-color: #c0c4cc //Select框箭头颜色 7 | 8 | .selector 9 | cursor: default 10 | display: inline-block 11 | position: relative 12 | // height: 32px 13 | width: 160px 14 | vertical-align: top 15 | 16 | .form-control[readonly] 17 | cursor: default 18 | font-size: 14px 19 | padding: 5px 31px 5px 10px 20 | background: $bg-color 21 | border: 1px solid $border-color 22 | border-radius: 2px 23 | color: $font-color 24 | 25 | &:hover 26 | border-color: $border-hover 27 | 28 | // &:focus 29 | // border-color: $border-focus 30 | 31 | /** i.glyphicon-triangle-bottom 32 | border: 5px solid $triangle-color 33 | border-top: 5px solid transparent 34 | border-left: 5px solid transparent 35 | display: block 36 | height: 10px 37 | width: 10px 38 | position: absolute 39 | right: 10px 40 | top: 50% 41 | transform: translateY(-50%) rotate(45deg) 42 | z-index: 100 **/ 43 | 44 | .glyphicon-triangle-bottom 45 | display: block 46 | position: absolute 47 | right: 10px 48 | top: 50% 49 | transform: translateY(-50%) rotate(0) 50 | z-index: 100 51 | 52 | ul.list-group 53 | border-radius: 5px 54 | display: none 55 | margin: 0 56 | max-height: 310px 57 | padding: 6px 0 58 | position: absolute 59 | top: 45px 60 | left: 0 61 | z-index: 999 62 | background: $bg-color 63 | border: 1px solid $border-color 64 | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1) 65 | color: $font-color 66 | 67 | li 68 | height: 30px 69 | line-height: 30px 70 | padding: 0 10px 71 | text-overflow: ellipsis 72 | overflow: hidden 73 | white-space: normal 74 | 75 | &:hover 76 | background-color: $hover-color 77 | 78 | div.select-arrow 79 | border: 6px solid $bg-color 80 | border-right: 6px solid transparent !important 81 | border-bottom: 6px solid transparent !important 82 | display: none 83 | height: 10px 84 | position: absolute 85 | left: 30% 86 | top: 40.5px 87 | transform: rotate(45deg) 88 | width: 10px 89 | z-index: 1000 90 | 91 | &::after 92 | border: 1px solid $border-color 93 | border-right: none !important 94 | border-bottom: none !important 95 | content: '' 96 | display: block 97 | height: 11px 98 | width: 11px 99 | transform: translate(-6px, -6px) 100 | -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/script/demo.js: -------------------------------------------------------------------------------- 1 | import 'bootstrap'; 2 | 3 | import 'bootstrap/scss/bootstrap.scss'; 4 | import '../style/demo.sass'; 5 | 6 | /* 引入日期范围选择器 */ 7 | import 'daterangepicker/daterangepicker.js'; 8 | import 'daterangepicker/daterangepicker.css'; 9 | 10 | import '../plugin/el-select'; //引入select插件 11 | import displayState from './demoPage/display'; 12 | 13 | /* import引入图片 */ 14 | import bg from '../static/img/bg-1.jpg'; 15 | 16 | import dateM from '../plugin/date-manager'; 17 | import Arithmetic from '../plugin/arithmetic'; 18 | 19 | /** 20 | * @description 日期范围选择插件配置 21 | * @type {Object} 22 | */ 23 | const locale = { 24 | format: 'YYYY/MM/DD', 25 | separator: ' - ', 26 | applyLabel: '确定', 27 | cancelLabel: '取消', 28 | fromLabel: 'From', 29 | toLabel: 'To', 30 | customRangeLabel: 'Custom', 31 | weekLabel: 'W', 32 | daysOfWeek: ['日', '一', '二', '三', '四', '五', '六'], 33 | monthNames: [ 34 | '一月', 35 | '二月', 36 | '三月', 37 | '四月', 38 | '五月', 39 | '六月', 40 | '七月', 41 | '八月', 42 | '九月', 43 | '十一月', 44 | '十二月', 45 | ], 46 | firstDay: 1, 47 | }; 48 | 49 | $(function () { 50 | console.warn('全局引入jQuery', $); 51 | console.warn('全局引入Lodash', _); 52 | console.warn('全局引入Echarts', echarts); 53 | 54 | console.warn(`current 'API' value: '${API}'`); 55 | 56 | const $btn = $('.btn'); 57 | $btn.on('click', function (e) { 58 | $btn 59 | .removeClass('btn-primary, btn-outline-primary') 60 | .addClass('btn-primary'); 61 | $(e.target).removeClass('btn-primary').addClass('btn-outline-primary'); 62 | }); 63 | 64 | if (process.env.NODE_ENV === 'development') { 65 | const key = 'a63b0782ec22dfd190771f7f57cf579d'; 66 | $.post('/txapi/ncov/index', { key }, function (response) { 67 | if (response.code === 200) { 68 | const desc = response.newslist[0].desc; 69 | displayState(desc); 70 | } 71 | }); 72 | } else { 73 | const data = require('../static/data/data.json'); 74 | displayState(data.newslist[0].desc); 75 | } 76 | 77 | document.querySelector('#script-import').src = bg; 78 | 79 | const years = $('#years').elSelect( 80 | [{ value: '2019', text: '2019年' }], //初始设置的数据 81 | (value, text) => { 82 | alert( 83 | `value: ${value}, text: ${text}\n提示:调用setValue方法也会设置value也会触发回调` 84 | ); 85 | } 86 | ); 87 | years.setData(dateM.nearlyYears()); //再次设置可选择数据 88 | // years.setValue('2015'); //设置指定值 89 | 90 | console.log($('#date-range').daterangepicker); 91 | 92 | $('#date').daterangepicker( 93 | { 94 | locale, 95 | // autoApply: true, 96 | drops: 'up', 97 | startDate: '2020/09/09', 98 | singleDatePicker: true, 99 | }, 100 | function (start, end, label) { 101 | console.log( 102 | '选择了一个新的日期: ' + 103 | start.format('YYYY-MM-DD') + 104 | ' to ' + 105 | end.format('YYYY-MM-DD') 106 | ); 107 | } 108 | ); 109 | 110 | $('#date-range').daterangepicker( 111 | { 112 | locale, 113 | // autoApply: true, 114 | drops: 'up', 115 | opens: 'left', 116 | startDate: '2020/09/03', 117 | endDate: '2020/09/09', 118 | }, 119 | function (start, end, label) { 120 | console.log( 121 | '选择了一个新的日期: ' + 122 | start.format('YYYY-MM-DD') + 123 | ' to ' + 124 | end.format('YYYY-MM-DD') 125 | ); 126 | } 127 | ); 128 | 129 | const arith = new Arithmetic(); //初始化计算对象 130 | $('#calc').on('click', () => { 131 | const expression = $('#calc-input').val(); 132 | const result = arith.calculate(expression); //传入表达式开始计算 133 | alert(result); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /src/static/iconfont/iconfont.js: -------------------------------------------------------------------------------- 1 | !function(c){var e,a='',t=(e=document.getElementsByTagName("script"))[e.length-1].getAttribute("data-injectcss");if(t&&!c.__iconfont__svg__cssinject__){c.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(e){console&&console.log(e)}}!function(e){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(e,0);else{var t=function(){document.removeEventListener("DOMContentLoaded",t,!1),e()};document.addEventListener("DOMContentLoaded",t,!1)}else document.attachEvent&&(o=e,i=c.document,l=!1,(a=function(){try{i.documentElement.doScroll("left")}catch(e){return void setTimeout(a,50)}n()})(),i.onreadystatechange=function(){"complete"==i.readyState&&(i.onreadystatechange=null,n())});function n(){l||(l=!0,o())}var o,i,l,a}(function(){var e,t,n,o,i,l;(e=document.createElement("div")).innerHTML=a,a=null,(t=e.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",n=t,(o=document.body).firstChild?(i=n,(l=o.firstChild).parentNode.insertBefore(i,l)):o.appendChild(n))})}(window); -------------------------------------------------------------------------------- /src/plugin/el-select/index.js: -------------------------------------------------------------------------------- 1 | import '../../lib/jquery.nicescroll'; 2 | import './select.sass'; 3 | 4 | const down = require('./chevron-down.svg'); 5 | console.log(down); 6 | $.fn.extend({ 7 | elSelect: function (data, callback) { 8 | const _this = this; 9 | const $input = _this.children('input'); 10 | /* webpack打包好的代码中回自动去掉 type="text" */ 11 | // const $input = _this.children('input[type="text"]'); 12 | const $glyphicon = $( 13 | ` 14 | 15 | ` 16 | // `` 17 | ); 18 | const $ul = $( 19 | '' 22 | ); 23 | const $arrow = $('
'); 24 | 25 | let _data = null; 26 | let _callback = callback; 27 | let displayFlag = false; 28 | 29 | _this.append($glyphicon).append($arrow).append($ul); 30 | 31 | $input 32 | .on('click', function () { 33 | if (displayFlag) setListVisible(false); 34 | else setListVisible(true); 35 | if (_this.get(0).offsetWidth != $ul[0].offsetWidth) { 36 | $ul.css({ width: _this.get(0).offsetWidth + 'px' }); 37 | } 38 | }) 39 | .prop('readonly', true) 40 | .attr('placeholder', '请选择'); 41 | 42 | $glyphicon.on('click', function () { 43 | if (displayFlag) setListVisible(false); 44 | else setListVisible(true); 45 | }); 46 | 47 | if (typeof data == 'object' && data instanceof Array) setData(data); 48 | 49 | $ul 50 | .on('click', function (e) { 51 | const $target = $(e.target); 52 | const value = $target.attr('data-value'); 53 | const text = $target.text(); 54 | $input.val(text).attr('title', text).data('value', value); 55 | if (typeof _callback == 'function') _callback(value, text); 56 | }) 57 | .niceScroll({ 58 | cursorcolor: '#c0c4cc', 59 | }); 60 | 61 | $(document).on('click', function (e) { 62 | if ( 63 | e.target !== _this.get(0) && 64 | e.target !== $input.get(0) && 65 | e.target !== $ul.get(0) && 66 | e.target !== $glyphicon.get(0) 67 | ) 68 | setListVisible(false); 69 | }); 70 | 71 | function setListVisible(visible) { 72 | if (visible) { 73 | $arrow.show(); 74 | $ul.show(); 75 | $glyphicon.css('transform', 'translateY(-50%) rotate(180deg)'); 76 | } else { 77 | $arrow.hide(); 78 | $ul.hide().getNiceScroll(0).doScrollLeft(0); 79 | $glyphicon.css('transform', 'translateY(-50%) rotate(0)'); 80 | } 81 | displayFlag = visible; 82 | } 83 | 84 | function setData(data) { 85 | _data = data; 86 | $ul.empty(); 87 | for (let i = 0, len = _data.length; i < len; i++) { 88 | $ul.append( 89 | '
  • ' + 94 | _data[i].text + 95 | '
  • ' 96 | ); 97 | } 98 | $ul.getNiceScroll().resize(); 99 | return _this; 100 | } 101 | 102 | _this.setData = setData; 103 | 104 | _this.setCallback = function (callback) { 105 | if (typeof callback == 'function') _callback = callback; 106 | }; 107 | 108 | _this.setValue = function (value) { 109 | if (typeof _data == 'object' && _data instanceof Array && _data.length) 110 | for (let i = 0, len = _data.length; i < len; i++) { 111 | if (value == _data[i].value) { 112 | $input 113 | .val(_data[i].text) 114 | .attr('title', _data[i].text) 115 | .data('value', value); 116 | if (typeof _callback == 'function') 117 | _callback(_data[i].value, _data[i].text); 118 | return _this; 119 | } 120 | } 121 | return _this; 122 | }; 123 | 124 | _this.value = function () { 125 | return $input.data('value'); 126 | }; 127 | 128 | return _this; 129 | }, 130 | }); 131 | -------------------------------------------------------------------------------- /src/static/data/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "code": 200, 3 | "msg": "success", 4 | "newslist": [ 5 | { 6 | "news": [ 7 | { 8 | "id": 12991, 9 | "pubDate": 1584938403000, 10 | "pubDateStr": "1小时前", 11 | "title": "哥伦比亚监狱暴动致23死90伤:囚犯不满卫生条件差发起抗议", 12 | "summary": "3月22日,哥伦比亚首都波哥大的一座监狱发生暴动,造成至少23人死亡,十多人受伤。据称囚犯因不满新冠疫情下的监狱卫生条件发起抗议,而司法部长称暴乱只是一场大规模的越狱意图。", 13 | "infoSource": "人民日报海外版", 14 | "sourceUrl": "http:\/\/m.weibo.cn\/3057540037\/4485619134236654", 15 | "provinceId": "1", 16 | "createTime": 1584939378000, 17 | "modifyTime": 1584939378000, 18 | "entryWay": 1, 19 | "adoptType": 1, 20 | "infoType": 1, 21 | "dataInfoState": 0, 22 | "dataInfoOperator": "", 23 | "dataInfoTime": 1584939378000 24 | }, 25 | { 26 | "id": 12985, 27 | "pubDate": 1584937444000, 28 | "pubDateStr": "1小时前", 29 | "title": "新西兰宣布将全面停工停课", 30 | "summary": "新西兰总理阿德恩23日表示,48小时后将把新冠肺炎疫情警报等级提高到最高级。届时,新西兰全国将全面停工停课,仅保留超市、医疗机构等必要机构运行。该警报等级将至少持续四周。\n", 31 | "infoSource": "央视新闻", 32 | "sourceUrl": "http:\/\/m.weibo.cn\/2656274875\/4485615112315259", 33 | "provinceId": "1", 34 | "createTime": 1584938417000, 35 | "modifyTime": 1584938417000, 36 | "entryWay": 1, 37 | "adoptType": 1, 38 | "infoType": 2, 39 | "dataInfoState": 0, 40 | "dataInfoOperator": "", 41 | "dataInfoTime": 1584938417000 42 | }, 43 | { 44 | "id": 12975, 45 | "pubDate": 1584934983000, 46 | "pubDateStr": "2小时前", 47 | "title": "天津新增4例境外输入病例", 48 | "summary": "3月22日18时至23日6时,天津无新增报告本地新冠肺炎确诊病例,新增报告4例境外输入确诊病例(中国籍3例、法国籍1例),累计报告境外输入确诊病例5例(中国籍4例、法国籍1例)。", 49 | "infoSource": "人民日报", 50 | "sourceUrl": "http:\/\/m.weibo.cn\/2803301701\/4485604790057843", 51 | "provinceId": "12", 52 | "provinceName": "天津市", 53 | "createTime": 1584935781000, 54 | "modifyTime": 1584935781000, 55 | "entryWay": 1, 56 | "adoptType": 1, 57 | "infoType": 2, 58 | "dataInfoState": 0, 59 | "dataInfoOperator": "", 60 | "dataInfoTime": 1584935781000 61 | }, 62 | { 63 | "id": 12968, 64 | "pubDate": 1584933008000, 65 | "pubDateStr": "2小时前", 66 | "title": "澳大利亚无法集结参加今夏奥运会", 67 | "summary": "据今日俄罗斯网站23日报道,澳大利亚奥委会(AOC)表示,鉴于国内外(疫情)不断变化的情势,澳大利亚团队“无法集结”参与今夏奥运会,会为2021年准备。\n", 68 | "infoSource": "人民日报海外版", 69 | "sourceUrl": "http:\/\/m.weibo.cn\/3057540037\/4485596506899811", 70 | "provinceId": "1", 71 | "createTime": 1584933978000, 72 | "modifyTime": 1584933978000, 73 | "entryWay": 1, 74 | "adoptType": 1, 75 | "infoType": 2, 76 | "dataInfoState": 0, 77 | "dataInfoOperator": "", 78 | "dataInfoTime": 1584933978000 79 | }, 80 | { 81 | "id": 12953, 82 | "pubDate": 1584930447000, 83 | "pubDateStr": "3小时前", 84 | "title": "上海应急响应级别调整为二级", 85 | "summary": "上海市自3月3日起已无新增本地确诊病例,上海市政府决定,自24日零时起,将上海市重大突发公共卫生事件应急响应级别由一级响应调整为二级响应。上海市将继续高度重视疫情防控工作,特别是以严防境外疫情输入为重点,做好口岸防控和社区防控。\n", 86 | "infoSource": "央视新闻", 87 | "sourceUrl": "http:\/\/m.weibo.cn\/2656274875\/4485585765178598", 88 | "provinceId": "31", 89 | "provinceName": "上海市", 90 | "createTime": 1584931217000, 91 | "modifyTime": 1584931217000, 92 | "entryWay": 1, 93 | "adoptType": 1, 94 | "infoType": 2, 95 | "dataInfoState": 0, 96 | "dataInfoOperator": "", 97 | "dataInfoTime": 1584931217000 98 | } 99 | ], 100 | "desc": { 101 | "id": 1, 102 | "createTime": 1579537899000, 103 | "modifyTime": 1584941547000, 104 | "summary": "", 105 | "deleted": false, 106 | "countRemark": "", 107 | "currentConfirmedCount": 5486, 108 | "confirmedCount": 81608, 109 | "suspectedCount": 354, 110 | "curedCount": 72846, 111 | "deadCount": 3276, 112 | "seriousCount": 1749, 113 | "suspectedIncr": 40, 114 | "currentConfirmedIncr": -363, 115 | "confirmedIncr": 110, 116 | "curedIncr": 464, 117 | "deadIncr": 9, 118 | "seriousIncr": -96, 119 | "remark1": "易感人群:人群普遍易感。老年人及有基础疾病者感染后病情较重,儿童及婴幼儿也有发病", 120 | "remark2": "潜伏期:一般为 3~7 天,最长不超过 14 天,潜伏期内可能存在传染性,其中无症状病例传染性非常罕见", 121 | "remark3": "宿主:野生动物,可能为中华菊头蝠", 122 | "remark4": "", 123 | "remark5": "", 124 | "note1": "病毒:SARS-CoV-2,其导致疾病命名 COVID-19", 125 | "note2": "传染源:新冠肺炎的患者。无症状感染者也可能成为传染源。", 126 | "note3": "传播途径:经呼吸道飞沫、接触传播是主要的传播途径。气溶胶传播和消化道等传播途径尚待明确。", 127 | "generalRemark": "1. 3 月 12 日国家卫健委确诊补订遗漏 12 例确诊病例(非 12 日新增),暂无具体省份信息。 2. 浙江省 12 例外省治愈暂无具体省份信息。", 128 | "abroadRemark": "", 129 | "foreignStatistics": { 130 | "currentConfirmedCount": 220144, 131 | "confirmedCount": 256234, 132 | "suspectedCount": 4, 133 | "curedCount": 24813, 134 | "deadCount": 11277, 135 | "suspectedIncr": 0, 136 | "currentConfirmedIncr": 2905, 137 | "confirmedIncr": 3140, 138 | "curedIncr": 208, 139 | "deadIncr": 27 140 | }, 141 | "globalStatistics": { 142 | "currentConfirmedCount": 225630, 143 | "confirmedCount": 337842, 144 | "curedCount": 97659, 145 | "deadCount": 14553, 146 | "currentConfirmedIncr": 2542, 147 | "confirmedIncr": 3250, 148 | "curedIncr": 672, 149 | "deadIncr": 36 150 | } 151 | } 152 | } 153 | ] 154 | } -------------------------------------------------------------------------------- /src/plugin/arithmetic/index.js: -------------------------------------------------------------------------------- 1 | import Stack from './stack'; 2 | 3 | export default class Arithmetic { 4 | constructor() { 5 | this.operand = new Stack(); 6 | this.operator = new Stack(); 7 | this.tempNum = ''; 8 | this.tempSym = ''; 9 | } 10 | /** 11 | * @description 递归表达式,优先计算括号中的内容并进行替换 12 | * @param {String} 13 | */ 14 | matchInBrackets(expression) { 15 | const regInBrackets = /\([\+|\-|\*|\/|\.|\d]+?\)/g; 16 | let expInBrackets = expression.match(regInBrackets); 17 | if (expInBrackets) { 18 | expInBrackets.forEach((element) => { 19 | const tempResualt = this.calculate(element.replace(/[\(|\)]/g, '')); 20 | expression = expression.replace(element, tempResualt); 21 | }); 22 | } 23 | expInBrackets = expression.match(regInBrackets); 24 | return expInBrackets ? this.matchInBrackets(expression) : expression; 25 | } 26 | /** 27 | * @description 初步处理计算表达式,将优先级高的乘除运算和括号内的运算先计算出结果 28 | * @param {String} 29 | */ 30 | calculate(expression) { 31 | // 先判断表达式中是否存在括号运算,如果有则递归计算出其中的值并替换表达式中的括号 32 | expression = this.matchInBrackets(expression); 33 | for (let i = expression.length - 1; 0 <= i; i--) { 34 | const numReg = /[\d|\.]/; 35 | let char = expression[i]; 36 | if (numReg.test(char)) { 37 | this.tempNum = char + this.tempNum; 38 | if (0 == i) { 39 | if (this.tempSym) { 40 | this.calculateMultiOrDivis(this.tempSym); 41 | this.tempSym = ''; 42 | } 43 | if (this.tempNum) this.operand.push(this.tempNum); 44 | break; 45 | } 46 | } else { 47 | if (0 == i) { 48 | if (this.tempSym) { 49 | this.calculateMultiOrDivis(this.tempSym); 50 | this.tempSym = ''; 51 | } 52 | if (this.tempNum) this.operand.push(this.tempNum); 53 | this.operator.push(char); 54 | break; 55 | } 56 | if (this.tempSym) { 57 | this.calculateMultiOrDivis(this.tempSym); 58 | this.tempSym = ''; 59 | } 60 | let peekSym = this.operator.peek(); 61 | const nextChar = expression[i - 1]; 62 | const isSymbol = /[\+|\-|\*|\/]/; 63 | if (peekSym) { 64 | if (this.tempNum) { 65 | if (isSymbol.test(nextChar) && '-' == char) { 66 | this.operand.push(char + this.tempNum); 67 | char = ''; 68 | } else { 69 | this.operand.push(this.tempNum); 70 | } 71 | this.tempNum = ''; 72 | } 73 | switch (Arithmetic.priorityCompare(peekSym, char)) { 74 | case 2: 75 | this.tempSym = this.operator.pop(); 76 | break; 77 | case 1: 78 | this.calculateMultiOrDivis(this.operator.pop()); 79 | break; 80 | default: 81 | break; 82 | } 83 | } else if (!peekSym && this.tempNum) { 84 | if (isSymbol.test(nextChar) && '-' == char) { 85 | this.operand.push(char + this.tempNum); 86 | char = ''; 87 | } else { 88 | this.operand.push(this.tempNum); 89 | } 90 | this.tempNum = ''; 91 | } 92 | if (char) this.operator.push(char); 93 | } 94 | } 95 | return this.calculateReversePoland(); 96 | } 97 | /** 98 | * @description 计算最终的逆波兰表达式 99 | */ 100 | calculateReversePoland() { 101 | let resualt = 0; 102 | while (0 < this.operand.getLength()) { 103 | if (this.operator.getLength() == this.operand.getLength()) { 104 | const symL = resualt; 105 | const symR = this.operand.pop(); 106 | const cacheSym = this.operator.pop(); 107 | resualt = 108 | '+' == cacheSym 109 | ? Arithmetic.addition(symL, symR) 110 | : Arithmetic.subtraction(symL, symR); 111 | } else { 112 | if (1 == this.operand.getLength()) { 113 | resualt = parseFloat(this.operand.pop()); 114 | break; 115 | } 116 | const symL = this.operand.pop(); 117 | const symR = this.operand.pop(); 118 | const cacheSym = this.operator.pop(); 119 | resualt = Arithmetic.selectCalculationRule(symL, symR, cacheSym); 120 | } 121 | this.operand.push(resualt); 122 | } 123 | this.operand.reset(); 124 | this.operator.reset(); 125 | this.tempNum = ''; 126 | this.tempSym = ''; 127 | return resualt; 128 | } 129 | /** 130 | * @description 只计算乘法或者除法 131 | * @param {String} sym 132 | */ 133 | calculateMultiOrDivis(sym) { 134 | const symL = this.operand.pop(); 135 | const symR = this.operand.pop(); 136 | this.operand.push(Arithmetic.selectCalculationRule(symL, symR, sym)); 137 | return undefined; 138 | } 139 | /** 140 | * @description 判断两个数字间的运算法则 141 | * @param {String || Number} symL 142 | * @param {String || Number} symR 143 | * @param {String} sym 144 | */ 145 | static selectCalculationRule(symL, symR, sym) { 146 | switch (sym) { 147 | case '*': 148 | return Arithmetic.multiplication(symL, symR); 149 | case '/': 150 | return Arithmetic.division(symL, symR); 151 | case '+': 152 | return Arithmetic.addition(symL, symR); 153 | default: 154 | return Arithmetic.subtraction(symL, symR); 155 | } 156 | } 157 | /** 158 | * @description 加法 159 | * @param {String || Number} 160 | */ 161 | static addition(...num) { 162 | const symL = parseFloat(num[0]); 163 | const symR = parseFloat(num[1]); 164 | return symL + symR; 165 | } 166 | /** 167 | * @description 除法 168 | * @param {String || Number} 169 | */ 170 | static division(...num) { 171 | const symL = parseFloat(num[0]); 172 | const symR = parseFloat(num[1]); 173 | return symL / symR; 174 | } 175 | /** 176 | * @description 乘法 177 | * @param {String || Number} 178 | */ 179 | static multiplication(...num) { 180 | const symL = parseFloat(num[0]); 181 | const symR = parseFloat(num[1]); 182 | return symL * symR; 183 | } 184 | /** 185 | * @description 减法 186 | * @param {String || Number} 187 | */ 188 | static subtraction(...num) { 189 | const symL = parseFloat(num[0]); 190 | const symR = parseFloat(num[1]); 191 | return symL - symR; 192 | } 193 | /** 194 | * @description 判断两个运算符的优先级 195 | * @param {String} 196 | */ 197 | static priorityCompare(symA, symB) { 198 | const high = /[\*\/]/; 199 | if (high.test(symA) && !high.test(symB)) { 200 | return 2; 201 | } else if (high.test(symA) && high.test(symB)) { 202 | return 1; 203 | } else { 204 | return 0; 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/view/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 上手使用 7 | 8 | 9 | 10 |
    11 |

    什么是JQDE?

    12 |

    13 | 是一套基于Webpack搭建的jQuery项目开发环境(jQuery development 14 | environment),使jQuery项目能够以前后端分离模式进行开发,这是一种有效提高开发效率的先进模式。利用此环境前端开发人员无需搭建后台环境,只需要配置相应的代理地址即可实现前后端的数据流通。并且此环境配置了对Sass和Stylus两种CSS样式预编译语言的配置,可以直接使用这些语言高效快速的编写界面样式。 17 |

    18 | 19 |

    开始使用

    20 |

    21 | 对于多页面的jQuery项目,每个页面需要一个入口文件,入口文件的名称需要与页面名称严格对应,并且分别放置在src目录下的script和view目录中,这两个目录名称及位置不允许被改变。例如当前页面为view中的demo.html,对应的脚本入口文件为script中的demo.js,这是该页面的主入口文件。这样Webpack会将两个文件建立联系,而样式文件及其他脚本或库的引入都可以在主入口文件中通过import或者require引入。 24 |

    25 |
    26 | 27 |
    28 | 29 |

    配置代理

    30 |
    31 | 32 | 33 | 34 |
    35 |
    36 |
    37 |
    38 |
    39 |

    全球累计确诊

    40 |
    41 |
    42 |

    43 | ---- / 例 44 |

    45 |

    较昨日新增 ----

    46 | 49 |
    50 |
    51 |
    52 |
    53 |

    国外累计确诊

    54 |
    55 |
    56 |

    57 | ---- / 例 58 |

    59 |

    较昨日新增 ----

    60 | 63 |
    64 |
    65 |
    66 |
    67 |

    国内累计确诊

    68 |
    69 |
    70 |

    71 | ---- / 例 72 |

    73 |

    较昨日新增 ----

    74 | 77 |
    78 |
    79 |
    80 | 81 |

    82 | 数据来源 83 | 天行数据 89 |

    90 |
    91 |
    92 | 93 |
    94 |

    95 | 上面的显示的信息是对于Webpack请求代理配置的自验和功能展示,千万不要以为是广告植入。这里去请求了一个第三方的接口地址,如果你目前是通过npm 96 | start启动的项目,那么这些数据是动态获取的,如果你是从dist中直接打开的本地页面,那么这些数据从有页面引入的json中获取。代理接口地址的修改在server.js中可以看到proxy属性,请根据自己项目情况自行设定。另外,开发环境端口后的配置也在此文件中。 99 |

    100 | 101 | 102 |

    域名及端口的设置

    103 |

    104 | 通过在server.js中引入dotenv,我们可以方便的在根目录下的.env文件中对域名和端口号进行设置。 105 |

    106 | 107 | 108 |

    全局变量的配置

    109 |

    110 | 通过Webpack的DefinePlugin,我们可以获取到指定变量在不同开发环境下的取值,这些配置在config目录下的dev.config.js和prod.config.js两个文件中。现在你可以打开控制台查看当前对API变量的取值情况。 112 |

    113 | 114 |

    全局引入jQuery、Lodash、Echarts

    115 |

    116 | 在配置webpack时已将jQuery、Lodash、Echarts这三个常用库全局引入,各个模块中可直接调用。就像本页面在demo.js中将他们直接打印出来,但没有在文件顶部引入,你可以去控制台查看打印结果。 117 |

    118 |
    119 | 123 |
    124 | 125 |

    图片的引入

    126 |
    127 |
    128 |
    129 |
    130 | 134 |
    img标签src引入
    135 |
    136 |
    137 |
    138 |
    139 |
    140 |
    141 | 142 |
    143 | script脚本import引入 144 |
    145 |
    146 |
    147 |
    148 |
    149 |
    150 |
    151 |
    152 | 157 |
    158 |
    159 | css样式background引入 160 |
    161 |
    162 |
    163 |
    164 |
    165 | 166 |

    字体图标的引入

    167 |

    168 | 只需在主入口文件或页面对应的css文件中引入相应的字体css文件即可,示例图标: 171 |

    172 |

    173 | 你还可以尝试Bootstrap Icons 179 |

    180 |

    181 | 同时了解下Bootstrap4 187 |

    188 | 189 |

    关于HTML文件没有热重载

    190 |

    191 | 由于为了满足img标签通过src属性链接图片而采用了html-loader,目前不能实现Html文件变更的响应。 192 |

    193 | 194 |

    模拟Element的Select选择器

    195 |

    196 | 197 |

    198 | 199 |
    200 |

    201 |

    202 | Select选择器基于jQuery和jQuery.niceScroll(存放在lib目录下)及Bootstrap编写,存放在plugin目录下,使用时先引入该插件后$('')选择元素调用.elSelect方法,接收数据数组和回调两个参数。提供setData、setValue、setCallback和value四个接口,分别用来初始化后更新数据、设值、添加或修改回调、取值。select.sass文件顶部定义有颜色变量可修改。 204 |

    205 |
    206 | 210 | 214 |
    215 | 216 |

    Arithmetic 类

    217 |

    218 | 一个用于前端解析计算公式并输出结果的小工具,原生JS实现不依赖任何第三方库,可以实现简单的四则运算。使用时只需new出实例对象,每次需要计算时调用calculate方法并传入计算式即可。 219 |

    220 |
    221 |
    222 | 223 |
    224 |
    225 | 226 |
    227 |
    228 |
    229 |
    230 | 234 |
    235 |
    236 |

    237 | 跳转 238 | GitHub仓 244 |

    245 | 246 |

    推荐的日期选择插件Date Range Picker

    247 |

    248 |

    249 |
    250 | 251 |
    252 |
    253 | 254 |
    255 |
    256 |

    257 |

    258 | Date Range Picker文档 264 |

    265 | 266 |
    267 | Back to index 270 |
    271 | 272 | 273 | -------------------------------------------------------------------------------- /src/static/iconfont/demo.css: -------------------------------------------------------------------------------- 1 | /* Logo 字体 */ 2 | @font-face { 3 | font-family: "iconfont logo"; 4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); 5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), 6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), 7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), 8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); 9 | } 10 | 11 | .logo { 12 | font-family: "iconfont logo"; 13 | font-size: 160px; 14 | font-style: normal; 15 | -webkit-font-smoothing: antialiased; 16 | -moz-osx-font-smoothing: grayscale; 17 | } 18 | 19 | /* tabs */ 20 | .nav-tabs { 21 | position: relative; 22 | } 23 | 24 | .nav-tabs .nav-more { 25 | position: absolute; 26 | right: 0; 27 | bottom: 0; 28 | height: 42px; 29 | line-height: 42px; 30 | color: #666; 31 | } 32 | 33 | #tabs { 34 | border-bottom: 1px solid #eee; 35 | } 36 | 37 | #tabs li { 38 | cursor: pointer; 39 | width: 100px; 40 | height: 40px; 41 | line-height: 40px; 42 | text-align: center; 43 | font-size: 16px; 44 | border-bottom: 2px solid transparent; 45 | position: relative; 46 | z-index: 1; 47 | margin-bottom: -1px; 48 | color: #666; 49 | } 50 | 51 | 52 | #tabs .active { 53 | border-bottom-color: #f00; 54 | color: #222; 55 | } 56 | 57 | .tab-container .content { 58 | display: none; 59 | } 60 | 61 | /* 页面布局 */ 62 | .main { 63 | padding: 30px 100px; 64 | width: 960px; 65 | margin: 0 auto; 66 | } 67 | 68 | .main .logo { 69 | color: #333; 70 | text-align: left; 71 | margin-bottom: 30px; 72 | line-height: 1; 73 | height: 110px; 74 | margin-top: -50px; 75 | overflow: hidden; 76 | *zoom: 1; 77 | } 78 | 79 | .main .logo a { 80 | font-size: 160px; 81 | color: #333; 82 | } 83 | 84 | .helps { 85 | margin-top: 40px; 86 | } 87 | 88 | .helps pre { 89 | padding: 20px; 90 | margin: 10px 0; 91 | border: solid 1px #e7e1cd; 92 | background-color: #fffdef; 93 | overflow: auto; 94 | } 95 | 96 | .icon_lists { 97 | width: 100% !important; 98 | overflow: hidden; 99 | *zoom: 1; 100 | } 101 | 102 | .icon_lists li { 103 | width: 100px; 104 | margin-bottom: 10px; 105 | margin-right: 20px; 106 | text-align: center; 107 | list-style: none !important; 108 | cursor: default; 109 | } 110 | 111 | .icon_lists li .code-name { 112 | line-height: 1.2; 113 | } 114 | 115 | .icon_lists .icon { 116 | display: block; 117 | height: 100px; 118 | line-height: 100px; 119 | font-size: 42px; 120 | margin: 10px auto; 121 | color: #333; 122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear; 123 | -moz-transition: font-size 0.25s linear, width 0.25s linear; 124 | transition: font-size 0.25s linear, width 0.25s linear; 125 | } 126 | 127 | .icon_lists .icon:hover { 128 | font-size: 100px; 129 | } 130 | 131 | .icon_lists .svg-icon { 132 | /* 通过设置 font-size 来改变图标大小 */ 133 | width: 1em; 134 | /* 图标和文字相邻时,垂直对齐 */ 135 | vertical-align: -0.15em; 136 | /* 通过设置 color 来改变 SVG 的颜色/fill */ 137 | fill: currentColor; 138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 139 | normalize.css 中也包含这行 */ 140 | overflow: hidden; 141 | } 142 | 143 | .icon_lists li .name, 144 | .icon_lists li .code-name { 145 | color: #666; 146 | } 147 | 148 | /* markdown 样式 */ 149 | .markdown { 150 | color: #666; 151 | font-size: 14px; 152 | line-height: 1.8; 153 | } 154 | 155 | .highlight { 156 | line-height: 1.5; 157 | } 158 | 159 | .markdown img { 160 | vertical-align: middle; 161 | max-width: 100%; 162 | } 163 | 164 | .markdown h1 { 165 | color: #404040; 166 | font-weight: 500; 167 | line-height: 40px; 168 | margin-bottom: 24px; 169 | } 170 | 171 | .markdown h2, 172 | .markdown h3, 173 | .markdown h4, 174 | .markdown h5, 175 | .markdown h6 { 176 | color: #404040; 177 | margin: 1.6em 0 0.6em 0; 178 | font-weight: 500; 179 | clear: both; 180 | } 181 | 182 | .markdown h1 { 183 | font-size: 28px; 184 | } 185 | 186 | .markdown h2 { 187 | font-size: 22px; 188 | } 189 | 190 | .markdown h3 { 191 | font-size: 16px; 192 | } 193 | 194 | .markdown h4 { 195 | font-size: 14px; 196 | } 197 | 198 | .markdown h5 { 199 | font-size: 12px; 200 | } 201 | 202 | .markdown h6 { 203 | font-size: 12px; 204 | } 205 | 206 | .markdown hr { 207 | height: 1px; 208 | border: 0; 209 | background: #e9e9e9; 210 | margin: 16px 0; 211 | clear: both; 212 | } 213 | 214 | .markdown p { 215 | margin: 1em 0; 216 | } 217 | 218 | .markdown>p, 219 | .markdown>blockquote, 220 | .markdown>.highlight, 221 | .markdown>ol, 222 | .markdown>ul { 223 | width: 80%; 224 | } 225 | 226 | .markdown ul>li { 227 | list-style: circle; 228 | } 229 | 230 | .markdown>ul li, 231 | .markdown blockquote ul>li { 232 | margin-left: 20px; 233 | padding-left: 4px; 234 | } 235 | 236 | .markdown>ul li p, 237 | .markdown>ol li p { 238 | margin: 0.6em 0; 239 | } 240 | 241 | .markdown ol>li { 242 | list-style: decimal; 243 | } 244 | 245 | .markdown>ol li, 246 | .markdown blockquote ol>li { 247 | margin-left: 20px; 248 | padding-left: 4px; 249 | } 250 | 251 | .markdown code { 252 | margin: 0 3px; 253 | padding: 0 5px; 254 | background: #eee; 255 | border-radius: 3px; 256 | } 257 | 258 | .markdown strong, 259 | .markdown b { 260 | font-weight: 600; 261 | } 262 | 263 | .markdown>table { 264 | border-collapse: collapse; 265 | border-spacing: 0px; 266 | empty-cells: show; 267 | border: 1px solid #e9e9e9; 268 | width: 95%; 269 | margin-bottom: 24px; 270 | } 271 | 272 | .markdown>table th { 273 | white-space: nowrap; 274 | color: #333; 275 | font-weight: 600; 276 | } 277 | 278 | .markdown>table th, 279 | .markdown>table td { 280 | border: 1px solid #e9e9e9; 281 | padding: 8px 16px; 282 | text-align: left; 283 | } 284 | 285 | .markdown>table th { 286 | background: #F7F7F7; 287 | } 288 | 289 | .markdown blockquote { 290 | font-size: 90%; 291 | color: #999; 292 | border-left: 4px solid #e9e9e9; 293 | padding-left: 0.8em; 294 | margin: 1em 0; 295 | } 296 | 297 | .markdown blockquote p { 298 | margin: 0; 299 | } 300 | 301 | .markdown .anchor { 302 | opacity: 0; 303 | transition: opacity 0.3s ease; 304 | margin-left: 8px; 305 | } 306 | 307 | .markdown .waiting { 308 | color: #ccc; 309 | } 310 | 311 | .markdown h1:hover .anchor, 312 | .markdown h2:hover .anchor, 313 | .markdown h3:hover .anchor, 314 | .markdown h4:hover .anchor, 315 | .markdown h5:hover .anchor, 316 | .markdown h6:hover .anchor { 317 | opacity: 1; 318 | display: inline-block; 319 | } 320 | 321 | .markdown>br, 322 | .markdown>p>br { 323 | clear: both; 324 | } 325 | 326 | 327 | .hljs { 328 | display: block; 329 | background: white; 330 | padding: 0.5em; 331 | color: #333333; 332 | overflow-x: auto; 333 | } 334 | 335 | .hljs-comment, 336 | .hljs-meta { 337 | color: #969896; 338 | } 339 | 340 | .hljs-string, 341 | .hljs-variable, 342 | .hljs-template-variable, 343 | .hljs-strong, 344 | .hljs-emphasis, 345 | .hljs-quote { 346 | color: #df5000; 347 | } 348 | 349 | .hljs-keyword, 350 | .hljs-selector-tag, 351 | .hljs-type { 352 | color: #a71d5d; 353 | } 354 | 355 | .hljs-literal, 356 | .hljs-symbol, 357 | .hljs-bullet, 358 | .hljs-attribute { 359 | color: #0086b3; 360 | } 361 | 362 | .hljs-section, 363 | .hljs-name { 364 | color: #63a35c; 365 | } 366 | 367 | .hljs-tag { 368 | color: #333333; 369 | } 370 | 371 | .hljs-title, 372 | .hljs-attr, 373 | .hljs-selector-id, 374 | .hljs-selector-class, 375 | .hljs-selector-attr, 376 | .hljs-selector-pseudo { 377 | color: #795da3; 378 | } 379 | 380 | .hljs-addition { 381 | color: #55a532; 382 | background-color: #eaffea; 383 | } 384 | 385 | .hljs-deletion { 386 | color: #bd2c00; 387 | background-color: #ffecec; 388 | } 389 | 390 | .hljs-link { 391 | text-decoration: underline; 392 | } 393 | 394 | /* 代码高亮 */ 395 | /* PrismJS 1.15.0 396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ 397 | /** 398 | * prism.js default theme for JavaScript, CSS and HTML 399 | * Based on dabblet (http://dabblet.com) 400 | * @author Lea Verou 401 | */ 402 | code[class*="language-"], 403 | pre[class*="language-"] { 404 | color: black; 405 | background: none; 406 | text-shadow: 0 1px white; 407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 408 | text-align: left; 409 | white-space: pre; 410 | word-spacing: normal; 411 | word-break: normal; 412 | word-wrap: normal; 413 | line-height: 1.5; 414 | 415 | -moz-tab-size: 4; 416 | -o-tab-size: 4; 417 | tab-size: 4; 418 | 419 | -webkit-hyphens: none; 420 | -moz-hyphens: none; 421 | -ms-hyphens: none; 422 | hyphens: none; 423 | } 424 | 425 | pre[class*="language-"]::-moz-selection, 426 | pre[class*="language-"] ::-moz-selection, 427 | code[class*="language-"]::-moz-selection, 428 | code[class*="language-"] ::-moz-selection { 429 | text-shadow: none; 430 | background: #b3d4fc; 431 | } 432 | 433 | pre[class*="language-"]::selection, 434 | pre[class*="language-"] ::selection, 435 | code[class*="language-"]::selection, 436 | code[class*="language-"] ::selection { 437 | text-shadow: none; 438 | background: #b3d4fc; 439 | } 440 | 441 | @media print { 442 | 443 | code[class*="language-"], 444 | pre[class*="language-"] { 445 | text-shadow: none; 446 | } 447 | } 448 | 449 | /* Code blocks */ 450 | pre[class*="language-"] { 451 | padding: 1em; 452 | margin: .5em 0; 453 | overflow: auto; 454 | } 455 | 456 | :not(pre)>code[class*="language-"], 457 | pre[class*="language-"] { 458 | background: #f5f2f0; 459 | } 460 | 461 | /* Inline code */ 462 | :not(pre)>code[class*="language-"] { 463 | padding: .1em; 464 | border-radius: .3em; 465 | white-space: normal; 466 | } 467 | 468 | .token.comment, 469 | .token.prolog, 470 | .token.doctype, 471 | .token.cdata { 472 | color: slategray; 473 | } 474 | 475 | .token.punctuation { 476 | color: #999; 477 | } 478 | 479 | .namespace { 480 | opacity: .7; 481 | } 482 | 483 | .token.property, 484 | .token.tag, 485 | .token.boolean, 486 | .token.number, 487 | .token.constant, 488 | .token.symbol, 489 | .token.deleted { 490 | color: #905; 491 | } 492 | 493 | .token.selector, 494 | .token.attr-name, 495 | .token.string, 496 | .token.char, 497 | .token.builtin, 498 | .token.inserted { 499 | color: #690; 500 | } 501 | 502 | .token.operator, 503 | .token.entity, 504 | .token.url, 505 | .language-css .token.string, 506 | .style .token.string { 507 | color: #9a6e3a; 508 | background: hsla(0, 0%, 100%, .5); 509 | } 510 | 511 | .token.atrule, 512 | .token.attr-value, 513 | .token.keyword { 514 | color: #07a; 515 | } 516 | 517 | .token.function, 518 | .token.class-name { 519 | color: #DD4A68; 520 | } 521 | 522 | .token.regex, 523 | .token.important, 524 | .token.variable { 525 | color: #e90; 526 | } 527 | 528 | .token.important, 529 | .token.bold { 530 | font-weight: bold; 531 | } 532 | 533 | .token.italic { 534 | font-style: italic; 535 | } 536 | 537 | .token.entity { 538 | cursor: help; 539 | } 540 | -------------------------------------------------------------------------------- /src/static/iconfont/demo_index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IconFont Demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
    18 |

    19 | 29 |
    30 |
    31 |
      32 | 33 |
    • 34 | 35 |
      箭头_向下
      36 |
      &#xeb0a;
      37 |
    • 38 | 39 |
    • 40 | 41 |
      箭头_向上
      42 |
      &#xeb0b;
      43 |
    • 44 | 45 |
    • 46 | 47 |
      double-arro- right
      48 |
      &#xe74c;
      49 |
    • 50 | 51 |
    • 52 | 53 |
      3d
      54 |
      &#xe625;
      55 |
    • 56 | 57 |
    • 58 | 59 |
      power
      60 |
      &#xe71d;
      61 |
    • 62 | 63 |
    • 64 | 65 |
      柱状图
      66 |
      &#xe748;
      67 |
    • 68 | 69 |
    70 |
    71 |

    Unicode 引用

    72 |
    73 | 74 |

    Unicode 是字体在网页端最原始的应用方式,特点是:

    75 |
      76 |
    • 兼容性最好,支持 IE6+,及所有现代浏览器。
    • 77 |
    • 支持按字体的方式去动态调整图标大小,颜色等等。
    • 78 |
    • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
    • 79 |
    80 |
    81 |

    注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式

    82 |
    83 |

    Unicode 使用步骤如下:

    84 |

    第一步:拷贝项目下面生成的 @font-face

    85 |
    @font-face {
     87 |   font-family: 'iconfont';
     88 |   src: url('iconfont.eot');
     89 |   src: url('iconfont.eot?#iefix') format('embedded-opentype'),
     90 |       url('iconfont.woff2') format('woff2'),
     91 |       url('iconfont.woff') format('woff'),
     92 |       url('iconfont.ttf') format('truetype'),
     93 |       url('iconfont.svg#iconfont') format('svg');
     94 | }
     95 | 
    96 |

    第二步:定义使用 iconfont 的样式

    97 |
    .iconfont {
     99 |   font-family: "iconfont" !important;
    100 |   font-size: 16px;
    101 |   font-style: normal;
    102 |   -webkit-font-smoothing: antialiased;
    103 |   -moz-osx-font-smoothing: grayscale;
    104 | }
    105 | 
    106 |

    第三步:挑选相应图标并获取字体编码,应用于页面

    107 |
    108 | <span class="iconfont">&#x33;</span>
    110 | 
    111 |
    112 |

    "iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

    113 |
    114 |
    115 |
    116 |
    117 |
      118 | 119 |
    • 120 | 121 |
      122 | 箭头_向下 123 |
      124 |
      .icon-jiantou_xiangxia 125 |
      126 |
    • 127 | 128 |
    • 129 | 130 |
      131 | 箭头_向上 132 |
      133 |
      .icon-jiantou_xiangshang 134 |
      135 |
    • 136 | 137 |
    • 138 | 139 |
      140 | double-arro- right 141 |
      142 |
      .icon-double-arro-right 143 |
      144 |
    • 145 | 146 |
    • 147 | 148 |
      149 | 3d 150 |
      151 |
      .icon-d 152 |
      153 |
    • 154 | 155 |
    • 156 | 157 |
      158 | power 159 |
      160 |
      .icon-power 161 |
      162 |
    • 163 | 164 |
    • 165 | 166 |
      167 | 柱状图 168 |
      169 |
      .icon-zhuzhuangtu 170 |
      171 |
    • 172 | 173 |
    174 |
    175 |

    font-class 引用

    176 |
    177 | 178 |

    font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

    179 |

    与 Unicode 使用方式相比,具有如下特点:

    180 |
      181 |
    • 兼容性良好,支持 IE8+,及所有现代浏览器。
    • 182 |
    • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
    • 183 |
    • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
    • 184 |
    • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
    • 185 |
    186 |

    使用步骤如下:

    187 |

    第一步:引入项目下面生成的 fontclass 代码:

    188 |
    <link rel="stylesheet" href="./iconfont.css">
    189 | 
    190 |

    第二步:挑选相应图标并获取类名,应用于页面:

    191 |
    <span class="iconfont icon-xxx"></span>
    192 | 
    193 |
    194 |

    " 195 | iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

    196 |
    197 |
    198 |
    199 |
    200 |
      201 | 202 |
    • 203 | 206 |
      箭头_向下
      207 |
      #icon-jiantou_xiangxia
      208 |
    • 209 | 210 |
    • 211 | 214 |
      箭头_向上
      215 |
      #icon-jiantou_xiangshang
      216 |
    • 217 | 218 |
    • 219 | 222 |
      double-arro- right
      223 |
      #icon-double-arro-right
      224 |
    • 225 | 226 |
    • 227 | 230 |
      3d
      231 |
      #icon-d
      232 |
    • 233 | 234 |
    • 235 | 238 |
      power
      239 |
      #icon-power
      240 |
    • 241 | 242 |
    • 243 | 246 |
      柱状图
      247 |
      #icon-zhuzhuangtu
      248 |
    • 249 | 250 |
    251 |
    252 |

    Symbol 引用

    253 |
    254 | 255 |

    这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 256 | 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

    257 |
      258 |
    • 支持多色图标了,不再受单色限制。
    • 259 |
    • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
    • 260 |
    • 兼容性较差,支持 IE9+,及现代浏览器。
    • 261 |
    • 浏览器渲染 SVG 的性能一般,还不如 png。
    • 262 |
    263 |

    使用步骤如下:

    264 |

    第一步:引入项目下面生成的 symbol 代码:

    265 |
    <script src="./iconfont.js"></script>
    266 | 
    267 |

    第二步:加入通用 CSS 代码(引入一次就行):

    268 |
    <style>
    269 | .icon {
    270 |   width: 1em;
    271 |   height: 1em;
    272 |   vertical-align: -0.15em;
    273 |   fill: currentColor;
    274 |   overflow: hidden;
    275 | }
    276 | </style>
    277 | 
    278 |

    第三步:挑选相应图标并获取类名,应用于页面:

    279 |
    <svg class="icon" aria-hidden="true">
    280 |   <use xlink:href="#icon-xxx"></use>
    281 | </svg>
    282 | 
    283 |
    284 |
    285 | 286 |
    287 |
    288 | 307 | 308 | 309 | --------------------------------------------------------------------------------