├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .postcssrc.js ├── README.md ├── build ├── autodeploy.js ├── build-all.js ├── build.js ├── check-versions.js ├── module-conf.js ├── utils.js ├── vue-loader.conf.js ├── webpack.base.conf.js ├── webpack.dev.conf.js ├── webpack.prod.conf.js └── webpack.test.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── document ├── component.txt ├── main.txt ├── router │ ├── index.js │ └── router.txt ├── vue-multipage-platform-project.docx └── vuex │ ├── Vuexstore.vue │ ├── store.js │ └── vueX.txt ├── moduletemplate ├── App.vue ├── index.html └── main.js ├── package-lock.json ├── package.json ├── projectConfig └── index.js ├── src ├── api │ ├── http.js │ └── url.js ├── assets │ └── css │ │ └── style.css ├── common │ ├── css │ │ ├── common.css │ │ └── font │ │ │ ├── reducto_condensed_ssi_condensed-webfont.eot │ │ │ ├── reducto_condensed_ssi_condensed-webfont.svg │ │ │ ├── reducto_condensed_ssi_condensed-webfont.ttf │ │ │ ├── reducto_condensed_ssi_condensed-webfont.woff │ │ │ └── reducto_condensed_ssi_condensed-webfont.woff2 │ ├── img │ │ └── rwtx.png │ ├── js │ │ ├── store.js │ │ ├── util.js │ │ └── viewport │ │ │ └── viewport1366.js │ └── video │ │ └── test.mp4 ├── components │ ├── HelloWorld.vue │ └── Pagenation.vue ├── framePage │ ├── App.vue │ ├── components │ │ ├── account.vue │ │ ├── index.vue │ │ ├── login.vue │ │ └── theme.vue │ ├── index.html │ ├── index.js │ └── router │ │ └── index.js ├── modules │ ├── bbsmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── blogmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── clubmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── coursemodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── homemodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── musicmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── productmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── socialmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── storemodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ ├── supportmodule │ │ ├── App.vue │ │ ├── components │ │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ │ └── index.js │ └── textmodule │ │ ├── App.vue │ │ ├── components │ │ └── index.vue │ │ ├── index.html │ │ ├── index.js │ │ └── router │ │ └── index.js ├── util │ ├── mixins │ │ ├── clickOutside.js │ │ ├── emitter.js │ │ └── locale.js │ ├── secret.js │ ├── tools.js │ └── utils │ │ ├── secret.js │ │ ├── tools.js │ │ ├── util.js │ │ └── valid.js └── vuex │ ├── readme.txt │ └── store.js ├── static └── webfavicon │ └── favicon.ico └── test ├── e2e ├── custom-assertions │ └── elementCount.js ├── nightwatch.conf.js ├── runner.js └── specs │ └── test.js └── unit ├── .eslintrc ├── index.js ├── karma.conf.js └── specs └── HelloWorld.spec.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": false, 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"], 12 | "env": { 13 | "test": { 14 | "presets": ["env", "stage-2"], 15 | "plugins": ["transform-vue-jsx", "istanbul"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /dist 3 | selenium-debug.log 4 | chromedriver.log 5 | geckodriver.log 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-multipage-platform-project(vue-cli-ww) 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 安装依赖 9 | cnpm i 10 | 11 | # serve with hot reload at localhost:8080 运行,开发模式暂不可指定运行模块,可配置rojectConfig/index来指定 12 | npm run dev //开发模式启动 13 | 14 | # build for production with minification //项目构建 15 | npm run build // 打包全部模块到一个资源包下面,每个模块的入口是module.html文件,静态资源都在static目录中,这种方式可以复用重复的资源 16 | npm run build moduleName1,moduleName2,... // 打包指定模块到一个资源包下面,每个模块的入口是module.html文件,静态资源都在static目录中,这种方式可以复用重复的资源 17 | 18 | npm run build moduleName1,moduleName2,... total// total代表整体打包(静态资源在同一个目录下,可以复用重复的文件),separate代表分开打包(静态资源按模块名称分别独立打包,不能复用重复的文件)separate模式下一次只能打某一个包,例如npm run build a separate 19 | 20 | npm run build-all // 打包所有模块,然后每个模块彼此独立,有几个模块,就产生几个静态资源包,这种方式不会复用重复的资源 21 | 22 | npm run build-all moduleName1,moduleName2,...// 打包制定模块,参数逗号隔开,然后每个模块彼此独立,有几个模块,就产生几个静态资源包,这种方式不会复用重复的资源 23 | 24 | # build for production and view the bundle analyzer report //构建并查看包分析报告 25 | npm run build --report 26 | 27 | # run unit tests 28 | npm run unit 29 | 30 | # run e2e tests 31 | npm run e2e 32 | 33 | # run all tests 34 | npm test 35 | ``` 36 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 37 | 38 | projectConfig/index为项目配置,若要更改默认的src下modules子文件夹名称或src下framePage文件夹名称,必须配置此js文件 39 | 当isbuildassignmodules为真时,项目打包或启动只会构建此配置buildmodules指定的包,命令行所传参数无效,当前状态下只可使用npm run build或npm run build-all 打包或npm run dev启动项目,系统默认启动打开页面为没有框架页为buildmodules[0]或有框架页则为框架页面 40 | 41 | npm run build //总体打包时访问参数传递为framePage.html?manulist=a,b&type=totle 两个参数 42 | npm run build-all //访问参数参数为framePage.html?manulist=a,b 单个参数 43 | 44 | 每次build时候会自动删除dist/static以及dist/*.html 打包构建前若不想保留以前的独立打包文件时请手动删除dist文件夹 -------------------------------------------------------------------------------- /build/autodeploy.js: -------------------------------------------------------------------------------- 1 | //局部模式 2 | var shell = require('shelljs'); 3 | //全局模式下,就不需要用shell开头了。 4 | //require('shelljs/global'); 5 | 6 | // if (shell.exec('npm run build').code !== 0) {//执行npm run build 命令 7 | // shell.echo('Error: Git commit failed'); 8 | // shell.exit(1); 9 | // } 10 | 11 | // //由于我的用另外一个仓库存放dist目录,所以这里要将文件增量复制到目标目录。并切换到对应目录。 12 | // shell.cp ('-r', './dist/*', '../../Rychou'); 13 | // shell.cd('../../Rychou'); 14 | 15 | // shell.exec('git add .'); 16 | // shell.exec("git commit -m 'autocommit'") 17 | // shell.exec('git push') 18 | 19 | // //引入shelljs 20 | // var shell = require('shelljs') 21 | 22 | // //检查控制台是否以运行`git `开头的命令 23 | // if (!shell.which('git')) { 24 | // //在控制台输出内容 25 | // shell.echo('Sorry, this script requires git'); 26 | // shell.exit(1); 27 | // } 28 | 29 | // shell.rm('-rf','out/Release');//强制递归删除`out/Release目录` 30 | // shell.cp('-R','stuff/','out/Release');//将`stuff/`中所有内容拷贝至`out/Release`目录 31 | 32 | // shell.cd('lib');//进入`lib`目录 33 | // //找出所有的扩展名为js的文件,并遍历进行操作 34 | // shell.ls('*.js').forEach(function (file) { 35 | // /* 这是第一个难点:sed流编辑器,建议专题学习,-i表示直接作用源文件 */ 36 | // //将build_version字段替换为'v0.1.2' 37 | // shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file); 38 | // //将包含`REMOVE_THIS_LINE`字符串的行删除 39 | // shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file); 40 | // //将包含`REPLACE_LINE_WITH_MACRO`字符串的行替换为`macro.js`中的内容 41 | // shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file); 42 | // }); 43 | 44 | // //返回上一级目录 45 | // shell.cd('..'); 46 | 47 | // //run external tool synchronously 48 | // //即同步运行外部工具 49 | // if (shell.exec('git commit -am "Auto-commit"').code !== 0){ 50 | // shell.echo('Error: Git commit failed'); 51 | // shell.exit(1); 52 | // } 53 | 54 | 55 | 56 | 57 | 58 | // 官方示例中涉及的命令解释: 59 | // shell.which(command) 60 | // 在环境变量PATH中寻找指定命令的地址,判断该命令是否可执行,返回该命令的绝对地址。 61 | 62 | // echo 63 | // 在控制台输出指定内容 64 | 65 | // exit(code) 66 | // 以退出码为code退出当前进程 67 | 68 | // rm 69 | // 删除一个目录中一个或多个文件或目录,一旦删除,无法恢复。 常用参数: 70 | // -f:强制删除文件; 71 | // -i:删除之前先询问用户; 72 | // -r:递归处理目录; 73 | // -v:显示处理过程; 74 | 75 | // cp([options,] source_array, dest) 76 | // 用来将一个或多个源文件或目录复制到指定的文件或目录。 常用参数: 77 | // -f:强制删除文件; 78 | // -i:删除之前先询问用户; 79 | // -r:递归处理目录; 80 | 81 | // cd 82 | // 切换工作目录至指定的相对路径或绝对路径。cd..为返回上一级,cd-回到前一目录。 83 | 84 | // ls 85 | // 用来显示目标列表。 常用参数: 86 | // -a:显示所有文件; 87 | // -C:多列显示查询结果; 88 | // -l:单列长格式显示查询结果(与-C相反); 89 | // -R:递归处理目录; 90 | 91 | // sed([options,] search_regex, replacement, file_array 92 | // 将file_array中符合search_regex的内容替换为replacement,支持正则的捕获组自引用。一次处理一行内容,处理完成后把缓冲区内容送往屏幕,然后处理下一行,循环直至结束。功能丰富且用法较复杂,建议自行百度进行专题学习。 93 | // -i:直接作用源文件 94 | 95 | // cat 96 | // 将一个或多个文件内容读入,指定一个文件时读入该文件,指定多个文件时将内容连接在一起读入。 97 | 98 | // exec(command,[, options][, callback]) 99 | // 执行所传入的命令 100 | 101 | // async:是否异步执行,默认false,传入callback时自动开启 102 | // slient:不输出信息到console,默认false 103 | // encoding:默认utf8 104 | 105 | // 四.文档中其他API概览 106 | // chmo 107 | // 设置文件调用权限 108 | // 基本语法 :chmod [-cfvR] [—help] [—version] mode file… 109 | // -c:若文件权限确实被更改,才显示更改动作 110 | // -f: 权限无法被更改时不显示错误信息 111 | // -v: 显示权限变更的详细资料 112 | // -R: 递归,对其目录下所有文件和子文件执行相同操作 113 | // mode字段格式 : [ugoa…][[+-=][rwxX]…][,…] 114 | // u表示该文件拥有者,g表示同一群体者,o表示其他,a表示所有 115 | // +表示增加权限,-表示取消权限,=表示唯一设定权限 116 | // r表示可读,w表示可写,x表示可执行,X表示当该文件是个子目录? 117 | 118 | // find(path[,path…]) 119 | // 寻找路径 120 | 121 | // grep([options,] regex_filter,file) 122 | // 从指定文件中抓取符合正则的行 123 | 124 | // -v:翻转正则匹配 125 | // -l:仅打印符合条件的文件名 126 | 127 | // head([{'-n':,}] file) 128 | // 显示指定文件中的前N行 129 | // -n:显示前<num>行 130 | 131 | // mv 132 | // 移动文件 133 | 134 | // pwd 135 | // 返回当前目录 136 | 137 | // rm 138 | // 见上文 139 | 140 | // set 141 | // 设置全局变量的值 142 | 143 | // sort 144 | // 将文件的内容逐行排序 145 | 146 | // -r:反转结果 147 | // -n:依据数值对比 148 | 149 | // tail 150 | // 读取指定文件的末尾n行,对比head命令进行理解 151 | 152 | // test() 153 | // 评估一个表达式是否为真(以下仅为最常见的参数用例) 154 | 155 | // -d,path:如果path是一个路径则返回true 156 | // -e,path:如果path存在则返回true 157 | 158 | // ShellString() 159 | // 构造器,将一个字符串转化为Shell字符串,转化后的字符串支持链式调用特殊的shell命令 160 | 161 | // ShellString.Prototype.to() 162 | // 将shellString输出至指定文件,相当于脚本语言中的> 163 | 164 | // ShellString.Prototype.toEnd() 165 | // 将shellString追加至指定文件,相当于脚本语言中的>> 166 | 167 | // touch([options,]file) 168 | // 生成文件 169 | // -m:仅修改编辑时间 170 | // -c:不创建任何文件 171 | // -d DATE:指定时间 172 | // -r FILE:用FILE的时间替代新文件时间 173 | // env['VAR_NAME'] 174 | 175 | // 指向process.env 176 | // Pipes链式调用支持 177 | // sed,grep,cat,exec,to,toEnd均支持链式调用。 -------------------------------------------------------------------------------- /build/build-all.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const execFileSync = require('child_process').execFileSync; //node子进程调用 3 | var moduleList = require('./module-conf').moduleList || [] //获取 buildlist 4 | const buildFile = path.join(__dirname, 'build.js') //获取build/build.js 5 | // process.argv.forEach((val, index) => { 6 | // console.log(`${index}: ${val}`); 7 | // }); 8 | //process.env.NODE_ENV = process.argv[2] //获取build-all 模块参数 9 | //process.env.NODE_TYPE = process.argv[1].split("/")[process.argv[1].split("/").length-1].split(".")[0] //获取打包类型 build-all 10 | 11 | for (const module of moduleList) { 12 | console.log('正在编译:', module) 13 | // 异步执行构建文件,并传入两个参数,module:当前打包模块,separate:当前打包模式(分开打包) 14 | //执行脚本 node build/build.js modulename(module:当前打包模块) separate 相当于 npm run build modulename(module:当前打包模块) separate 15 | execFileSync('node', [buildFile, module, 'separate'], {}) 16 | } 17 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | const chalk = require('chalk') 4 | 5 | process.env.NODE_ENV = 'production' 6 | // MODULE_ENV用来记录当前打包的模块名称 7 | 8 | const { framePage, isbuildassignmodules, buildmodules, modulesconfig } = require('../projectConfig') 9 | process.env.MODULE_ENV = process.argv[2]&&process.argv[2].replace(',', ',') 10 | 11 | // MODE_ENV用来记录当前打包的模式,total代表整体打包(静态资源在同一个目录下,可以复用重复的文件),separate代表分开打包(静态资源按模块名称分别独立打包,不能复用重复的文件) 12 | process.env.MODE_ENV = process.argv[3] 13 | 14 | process.env.NODE_TYPE = process.argv[1].split("/")[process.argv[1].split("/").length - 1].split(".")[0] 15 | if (process.env.NODE_TYPE == "build" && process.env.MODULE_ENV.split(",").length > 1 && process.env.MODE_ENV==="separate") { 16 | console.log(chalk.red('参数错误,允许的参数只能为一个,'), chalk.yellow(`非法参数:`),chalk.red(`${process.env.MODULE_ENV}`)) 17 | 18 | return 19 | } 20 | // 如果有传参时,对传入的参数进行检测,如果参数非法,那么停止打包操作 21 | const checkModule = require('./module-conf').checkModule 22 | if (process.env.MODULE_ENV !== 'undefined' && !checkModule()) { 23 | return 24 | } else if (process.env.NODE_TYPE == "build" && !checkModule()) { 25 | process.env.MODULE_ENV = isbuildassignmodules ? buildmodules.join() : process.argv[2] 26 | } else { 27 | process.env.MODULE_ENV = process.argv[2] 28 | } 29 | 30 | 31 | 32 | const path = require('path') 33 | const ora = require('ora') 34 | const rm = require('rimraf') 35 | const webpack = require('webpack') 36 | const config = require('../config') 37 | const webpackConfig = require('./webpack.prod.conf') 38 | 39 | const spinner = ora('building for production...') 40 | spinner.start() 41 | 42 | rm(path.resolve(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 43 | if (err) throw err 44 | webpack(webpackConfig, (err, stats) => { 45 | spinner.stop() 46 | if (err) throw err 47 | process.stdout.write(stats.toString({ 48 | colors: true, 49 | modules: false, 50 | children: false, // If you are using ts-loader, setting this to true will make TypeScript errors show up during build. 51 | chunks: false, 52 | chunkModules: false 53 | }) + '\n\n') 54 | 55 | if (stats.hasErrors()) { 56 | console.log(chalk.red(' Build failed with errors.\n')) 57 | process.exit(1) 58 | } 59 | 60 | console.log(chalk.cyan(' Build complete.\n')) 61 | console.log(chalk.yellow( 62 | ' Tip: built files are meant to be served over an HTTP server.\n' + 63 | ' Opening index.html over file:// won\'t work.\n' 64 | )) 65 | }) 66 | }) 67 | -------------------------------------------------------------------------------- /build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | 4 | //npm install --save semver 5 | const semver = require('semver') //检测版本 6 | // semver.valid('1.2.3') // '1.2.3' 7 | // semver.valid('a.b.c') // null 8 | // semver.clean(' =v1.2.3 ') // '1.2.3' 9 | // semver.satisfies('1.2.3', '1.x || >=2.5.0 || 5.0.0 - 7.2.3') // true 10 | // semver.gt('1.2.3', '9.8.7') // false 11 | // semver.lt('1.2.3', '9.8.7') // true 12 | // semver.valid(semver.coerce('v2')) // '2.0.0' 13 | // semver.valid(semver.coerce('42.6.7.9.3-alpha')) // '42.6.7' 14 | 15 | 16 | 17 | const shell = require('shelljs') //可在cmd窗口执行一些脚本,详情参考 autodeploy.js 18 | 19 | 20 | const packageConfig = require('../package.json') 21 | 22 | 23 | function exec (cmd) { 24 | return require('child_process').execSync(cmd).toString().trim() 25 | } 26 | 27 | const versionRequirements = [ 28 | { 29 | name: 'node', 30 | currentVersion: semver.clean(process.version), 31 | versionRequirement: packageConfig.engines.node 32 | } 33 | ] 34 | 35 | if (shell.which('npm')) { 36 | versionRequirements.push({ 37 | name: 'npm', 38 | currentVersion: exec('npm --version'), 39 | versionRequirement: packageConfig.engines.npm 40 | }) 41 | } 42 | 43 | module.exports = function () { 44 | const warnings = [] 45 | 46 | for (let i = 0; i < versionRequirements.length; i++) { 47 | const mod = versionRequirements[i] 48 | 49 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 50 | warnings.push(mod.name + ': ' + 51 | chalk.red(mod.currentVersion) + ' should be ' + 52 | chalk.green(mod.versionRequirement) 53 | ) 54 | } 55 | } 56 | 57 | if (warnings.length) { 58 | console.log('') 59 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 60 | console.log() 61 | 62 | for (let i = 0; i < warnings.length; i++) { 63 | const warning = warnings[i] 64 | console.log(' ' + warning) 65 | } 66 | 67 | console.log() 68 | process.exit(1) 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /build/module-conf.js: -------------------------------------------------------------------------------- 1 | 2 | var chalk = require('chalk') //打印不同颜色,用法console.log(chalk.red(*****)) 3 | var glob = require('glob') //匹配所有通配符路径的文件以及文件夹,用法glob.sync('./src/modules/*') 4 | const framePage = require('../projectConfig').framePage //用户配置的框架页面文件夹 5 | 6 | var moduleList = [] // 获取所有的moduleList 固有的(项目中的所有模块)->命令行中的模块名称(输入的模块名)->用户配置指定的模块名(isbuildassignmodules为真是有效),后者替换前者 7 | 8 | 9 | // 获取框架模块 10 | var moduleSrcIframe = glob.sync('./src/'+(framePage||'framePage')+'/index.html') 11 | //console.log(chalk.red(moduleSrcIframe[0])) 12 | if(moduleSrcIframe!=0&&moduleList.indexOf(framePage||'framePage')==-1){ 13 | //moduleSrcIframe=moduleSrcIframe[0].split('/')[2].split('.')[0]; 14 | moduleSrcIframe=framePage||'framePage' 15 | console.log(chalk.blue("enabled(建立了)framePage(框架页):")+chalk.red(moduleSrcIframe)) 16 | moduleList.push(moduleSrcIframe) 17 | } 18 | else{ 19 | moduleSrcIframe=false; 20 | console.log(chalk.red("disabled(未建立)framePage(框架页)")) 21 | } 22 | // 获取moduls页面 23 | var moduleSrcArray = glob.sync('./src/modules/*') 24 | for(var x in moduleSrcArray){ 25 | moduleList.push(moduleSrcArray[x].split('/')[3]) 26 | } 27 | 28 | 29 | // 获取命令行中的模块名称 30 | if (process.argv[2]&&process.argv[2]!="--inline") { 31 | moduleList = process.argv[2].replace(',',',').split(",") 32 | } 33 | 34 | 35 | 36 | // 获取用户配置指定的模块名(isbuildassignmodules为真是有效) 37 | const { isbuildassignmodules, buildmodules, modulesconfig } = require('../projectConfig') 38 | moduleList = isbuildassignmodules ? buildmodules : moduleList 39 | 40 | 41 | 42 | // 检测输入的参数是否在允许的list中 43 | var checkModule = function () { 44 | var module = process.env.MODULE_ENV 45 | // 检查moduleList是否有重复 46 | var hash = {} 47 | var repeatList = [] 48 | for(var l = 0;l < moduleList.length; l++){ 49 | if(hash[moduleList[l]]){ 50 | repeatList.push(moduleList[l]) 51 | } 52 | hash[moduleList[l]] = true 53 | } 54 | // if(repeatList.length > 0){ 55 | // console.log(chalk.red('moduleList 有重复:')) 56 | // console.log(chalk.red(repeatList.toString())) 57 | // return false 58 | // } 59 | let result = true 60 | let illegalParam = '' 61 | for (let moduleToBuild of module.split(',')) { 62 | if (moduleList.indexOf(moduleToBuild) === -1) { 63 | result = false 64 | illegalParam = moduleToBuild 65 | break 66 | } 67 | } 68 | if(result === false&&module!=='undefined'){ 69 | console.log(module) 70 | console.log(chalk.red('参数错误,允许的参数为:'),chalk.green(moduleList.toString())) 71 | console.log(chalk.yellow(`非法参数:${illegalParam}`)) 72 | } 73 | return result 74 | } 75 | 76 | // 获取当前要打包的模块列表 77 | function getModuleToBuild () { 78 | let moduleToBuild = moduleList 79 | // if (process.env.NODE_ENV === 'production') { 80 | // /* 部署态,构建要打包的模块列表,如果指定了要打包的模块,那么按照指定的模块配置入口 81 | // * 这里有个特性,即使参数未传,那么获取到的undefined也是字符串类型的,不是undefined类型 82 | // * */ 83 | // if (process.env.MODULE_ENV !== 'undefined') { 84 | // moduleToBuild = process.env.MODULE_ENV.split(',') 85 | // } else { 86 | // // 如果未指定要打包的模块,那么打包所有模块 87 | // moduleToBuild = moduleList 88 | // } 89 | // } else { 90 | // // 开发态,获取所有的模块列表 91 | // moduleToBuild = moduleList 92 | // } 93 | return moduleToBuild 94 | } 95 | 96 | //command规范导出语法,可以写成obj 97 | exports.moduleList = moduleList 98 | exports.checkModule = checkModule 99 | exports.getModuleToBuild = getModuleToBuild 100 | exports.moduleIframe = moduleSrcIframe 101 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | const packageConfig = require('../package.json') 6 | 7 | exports.assetsPath = function(_path) { 8 | const assetsSubDirectory = process.env.NODE_ENV === 'production' ? 9 | config.build.assetsSubDirectory : 10 | config.dev.assetsSubDirectory 11 | 12 | return path.posix.join(assetsSubDirectory, _path) 13 | } 14 | 15 | exports.cssLoaders = function(options) { 16 | options = options || {} 17 | 18 | const cssLoader = { 19 | loader: 'css-loader', 20 | options: { 21 | sourceMap: options.sourceMap 22 | } 23 | } 24 | 25 | const postcssLoader = { 26 | loader: 'postcss-loader', 27 | options: { 28 | sourceMap: options.sourceMap 29 | } 30 | } 31 | 32 | // generate loader string to be used with extract text plugin 33 | function generateLoaders(loader, loaderOptions) { 34 | const loaders = options.usePostCSS ? [cssLoader, postcssLoader] : [cssLoader] 35 | 36 | if (loader) { 37 | loaders.push({ 38 | loader: loader + '-loader', 39 | options: Object.assign({}, loaderOptions, { 40 | sourceMap: options.sourceMap 41 | }) 42 | }) 43 | } 44 | 45 | // Extract CSS when that option is specified 46 | // (which is the case during production build) 47 | if (options.extract) { 48 | return ExtractTextPlugin.extract({ 49 | use: loaders, 50 | fallback: 'vue-style-loader', 51 | publicPath: '../../' //解决css背景图路径错位问题 52 | }) 53 | } else { 54 | return ['vue-style-loader'].concat(loaders) 55 | } 56 | } 57 | 58 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 59 | return { 60 | css: generateLoaders(), 61 | postcss: generateLoaders(), 62 | less: generateLoaders('less'), 63 | sass: generateLoaders('sass', { indentedSyntax: true }), 64 | scss: generateLoaders('sass'), 65 | stylus: generateLoaders('stylus'), 66 | styl: generateLoaders('stylus') 67 | } 68 | } 69 | 70 | // Generate loaders for standalone style files (outside of .vue) 71 | exports.styleLoaders = function(options) { 72 | const output = [] 73 | const loaders = exports.cssLoaders(options) 74 | 75 | for (const extension in loaders) { 76 | const loader = loaders[extension] 77 | output.push({ 78 | test: new RegExp('\\.' + extension + '$'), 79 | use: loader 80 | }) 81 | } 82 | 83 | return output 84 | } 85 | 86 | exports.createNotifierCallback = () => { 87 | const notifier = require('node-notifier') 88 | 89 | return (severity, errors) => { 90 | if (severity !== 'error') return 91 | 92 | const error = errors[0] 93 | const filename = error.file && error.file.split('!').pop() 94 | 95 | notifier.notify({ 96 | title: packageConfig.name, 97 | message: severity + ': ' + error.name, 98 | subtitle: filename || '', 99 | icon: path.join(__dirname, 'logo.png') 100 | }) 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | const sourceMapEnabled = isProduction 6 | ? config.build.productionSourceMap 7 | : config.dev.cssSourceMap 8 | 9 | module.exports = { 10 | loaders: utils.cssLoaders({ 11 | sourceMap: sourceMapEnabled, 12 | extract: isProduction 13 | }), 14 | cssSourceMap: sourceMapEnabled, 15 | cacheBusting: config.dev.cacheBusting, 16 | transformToRequire: { 17 | video: ['src', 'poster'], 18 | source: 'src', 19 | img: 'src', 20 | image: 'xlink:href' 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | const moduleIframe = require('./module-conf').moduleIframe 7 | 8 | function resolve(dir) { 9 | return path.join(__dirname, '..', dir) 10 | } 11 | 12 | const createLintingRule = () => ({ 13 | test: /\.(js|vue)$/, 14 | loader: 'eslint-loader', 15 | enforce: 'pre', 16 | include: [resolve('src'), resolve('test')], 17 | options: { 18 | formatter: require('eslint-friendly-formatter'), 19 | emitWarning: !config.dev.showEslintErrorsInOverlay 20 | } 21 | }) 22 | 23 | module.exports = { 24 | context: path.resolve(__dirname, '../'), 25 | // entry: { 26 | // app: './src/main.js' 27 | // }, 28 | entry() { 29 | // 初始化入口配置 30 | const entry = {} 31 | // 所有模块的列表 32 | const moduleToBuild = require('./module-conf').getModuleToBuild() || [] 33 | // 根据传入的待打包目录名称,构建多入口配置 34 | for (let module of moduleToBuild) { 35 | entry[module] = `./src/modules/${module}/index.js` 36 | if (moduleIframe == module) { 37 | entry[module] = `./src/${module}/index.js` 38 | } 39 | } 40 | return entry 41 | }, 42 | output: { 43 | path: config.build.assetsRoot, 44 | filename: '[name].js', 45 | publicPath: process.env.NODE_ENV === 'production' ? 46 | config.build.assetsPublicPath : 47 | config.dev.assetsPublicPath 48 | }, 49 | resolve: { 50 | extensions: ['.js', '.vue', '.json'], 51 | alias: { 52 | '@': resolve('src'), 53 | '#': path.resolve(__dirname, '../static'), 54 | '*': path.resolve(__dirname, '../src/components'), 55 | '&': path.resolve(__dirname, '../src/assets'), 56 | } 57 | }, 58 | module: { 59 | rules: [ 60 | ...(config.dev.useEslint ? [createLintingRule()] : []), 61 | { 62 | test: /\.vue$/, 63 | loader: 'vue-loader', 64 | options: vueLoaderConfig 65 | }, 66 | { 67 | test: /\.js$/, 68 | loader: 'babel-loader', 69 | include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')] 70 | }, 71 | { 72 | test: /\.sass$/, 73 | loaders: ["style", "css", "sass"] //使用 lass=scss 74 | }, 75 | { 76 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 77 | loader: 'url-loader', 78 | options: { 79 | limit: 10000, 80 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 81 | } 82 | }, 83 | { 84 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 85 | loader: 'url-loader', 86 | options: { 87 | limit: 1, 88 | name: utils.assetsPath('media/[name].[ext]') 89 | } 90 | }, 91 | { 92 | test: /\.(doc|pdf|xls|xlsx|ppt|txt)(\?.*)?$/, 93 | loader: 'url-loader', 94 | options: { 95 | limit: 10000, 96 | name: utils.assetsPath('documents/[name].[ext]') 97 | } 98 | }, 99 | { 100 | test: /\.(zip|rar|7z)(\?.*)?$/, 101 | loader: 'url-loader', 102 | options: { 103 | limit: 1, 104 | name: utils.assetsPath('rar/[name].[ext]') 105 | } 106 | }, 107 | { 108 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 109 | loader: 'url-loader', 110 | options: { 111 | limit: 1, 112 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 113 | } 114 | }, 115 | 116 | ] 117 | }, 118 | node: { 119 | // prevent webpack from injecting useless setImmediate polyfill because Vue 120 | // source contains it (although only uses it if it's native). 121 | setImmediate: false, 122 | // prevent webpack from injecting mocks to Node native modules 123 | // that does not make sense for the client 124 | dgram: 'empty', 125 | fs: 'empty', 126 | net: 'empty', 127 | tls: 'empty', 128 | child_process: 'empty' 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const path = require('path') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 11 | const portfinder = require('portfinder') 12 | 13 | const HOST = process.env.HOST 14 | const PORT = process.env.PORT && Number(process.env.PORT) 15 | var moduleList = require('./module-conf').moduleList || [] 16 | 17 | const moduleIframe = require('./module-conf').moduleIframe 18 | const { framePage, isbuildassignmodules, buildmodules, modulesconfig } = require('../projectConfig') 19 | // process.env.MODULE_ENV = process.argv[2] 20 | 21 | //console.log(process.argv[6]) 22 | // process.env.MODULE_ENV?moduleList=process.argv[2].split(","):moduleList=moduleList 23 | // 组装多个(有几个module就有几个htmlWebpackPlugin)htmlWebpackPlugin,然后追加到配置中 24 | var htmlWebpackPlugins = [] 25 | 26 | 27 | for (let module of moduleList) { 28 | if (moduleIframe == module) { 29 | htmlWebpackPlugins.push(new HtmlWebpackPlugin({ 30 | filename: `${moduleIframe}/index.html`, 31 | template: `./src/${moduleIframe}/index.html`, 32 | inject: true, 33 | chunks: [moduleIframe] 34 | })) 35 | } else { 36 | htmlWebpackPlugins.push(new HtmlWebpackPlugin({ 37 | filename: `${module}/index.html`, 38 | template: `./src/modules/${module}/index.html`, 39 | inject: true, 40 | chunks: [module] 41 | })) 42 | } 43 | } 44 | 45 | const devWebpackConfig = merge(baseWebpackConfig, { 46 | module: { 47 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true }) 48 | }, 49 | // cheap-module-eval-source-map is faster for development 50 | devtool: config.dev.devtool, 51 | 52 | // these devServer options should be customized in /config/index.js 53 | devServer: { 54 | clientLogLevel: 'warning', 55 | proxy: config.dev.proxy, 56 | historyApiFallback: { 57 | rewrites: [ 58 | { from: /^\/$/, to: '/views/landing.html' }, 59 | { from: /^\/subpage/, to: '/views/subpage.html' }, 60 | { from: /./, to: '/views/404.html' }, 61 | { from: /.*/, to: path.posix.join(config.dev.assetsPublicPath, 'index.html') }, 62 | ], 63 | }, 64 | hot: true, 65 | contentBase: false, // since we use CopyWebpackPlugin. 66 | compress: true, 67 | host: HOST || config.dev.host, 68 | port: PORT || config.dev.port, 69 | open: config.dev.autoOpenBrowser, 70 | overlay: config.dev.errorOverlay ? { warnings: false, errors: true } : false, 71 | publicPath: config.dev.assetsPublicPath, 72 | 73 | quiet: true, // necessary for FriendlyErrorsPlugin 74 | watchOptions: { 75 | poll: config.dev.poll, 76 | }, 77 | before(app) { 78 | 79 | // // 访问根路径时重定向到moduleList 80 | // app.get('/moduleList', (req, res, next) => { 81 | // res.send(html) 82 | // }) 83 | let moduleListapp = JSON.parse(JSON.stringify(moduleList)) 84 | //console.log(moduleList) 85 | if (moduleListapp.indexOf(moduleIframe) >= 0) { 86 | //路由重定向为框架页 87 | app.get('/', (req, res, next) => { 88 | //res.redirect('/moduleListapp') 89 | if (moduleListapp.indexOf(moduleIframe) >= 0) { 90 | moduleListapp.splice(moduleListapp.indexOf(moduleIframe), 1) 91 | } 92 | res.redirect(`/${moduleIframe}/index.html` + "?menulist=" + moduleListapp.join()) 93 | }) 94 | } else { 95 | app.get('/', (req, res, next) => { 96 | //res.redirect('/moduleListapp') 97 | res.redirect(`/${moduleListapp[0]}/index.html`) 98 | }) 99 | } 100 | } 101 | }, 102 | plugins: [ 103 | new webpack.DefinePlugin({ 104 | 'process.env': require('../config/dev.env') 105 | }), 106 | new webpack.HotModuleReplacementPlugin(), 107 | new webpack.NamedModulesPlugin(), // HMR shows correct file names in console on update. 108 | new webpack.NoEmitOnErrorsPlugin(), 109 | // copy custom static assets 110 | new CopyWebpackPlugin([{ 111 | from: path.resolve(__dirname, '../static'), 112 | to: config.dev.assetsSubDirectory, 113 | ignore: ['.*'] 114 | }]), 115 | // https://github.com/ampedandwired/html-webpack-plugin 116 | // new HtmlWebpackPlugin({ 117 | // filename: 'a/index.html', 118 | // template: './src/modules/a/index.html', 119 | // inject: true, 120 | // chunks: ['a'] 121 | // }), 122 | ].concat(htmlWebpackPlugins) 123 | }) 124 | 125 | module.exports = new Promise((resolve, reject) => { 126 | portfinder.basePort = process.env.PORT || config.dev.port 127 | portfinder.getPort((err, port) => { 128 | if (err) { 129 | reject(err) 130 | } else { 131 | // publish the new Port, necessary for e2e tests 132 | process.env.PORT = port 133 | // add port to devServer config 134 | devWebpackConfig.devServer.port = port 135 | 136 | // Add FriendlyErrorsPlugin 137 | devWebpackConfig.plugins.push(new FriendlyErrorsPlugin({ 138 | compilationSuccessInfo: { 139 | messages: [`Your application is running here: http://${devWebpackConfig.devServer.host}:${port}`], 140 | }, 141 | onErrors: config.dev.notifyOnErrors ? 142 | utils.createNotifierCallback() : undefined 143 | })) 144 | 145 | resolve(devWebpackConfig) 146 | } 147 | }) 148 | }) 149 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const webpack = require('webpack') 5 | const config = require('../config') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | const CopyWebpackPlugin = require('copy-webpack-plugin') 9 | const HtmlWebpackPlugin = require('html-webpack-plugin') 10 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 11 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') 12 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin') 13 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 14 | 15 | var glob = require('glob') 16 | var chalk = require('chalk') 17 | var globdist = glob.sync('./dist/*') 18 | 19 | const env = process.env.NODE_ENV === 'testing' ? 20 | require('../config/test.env') : 21 | require('../config/prod.env') 22 | // 获取所有模块列表 23 | const moduleToBuild = require('./module-conf').getModuleToBuild() || [] 24 | 25 | //是否有框架页 26 | const moduleIframe = require('./module-conf').moduleIframe 27 | 28 | const buildType = process.argv[1].split("/")[process.argv[1].split("/").length - 1].split(".")[0] 29 | 30 | // 组装多个(有几个module就有几个htmlWebpackPlugin)htmlWebpackPlugin,然后追加到配置中 31 | const htmlWebpackPlugins = [] 32 | 33 | 34 | // 判断一下是否为分开打包模式 35 | if (process.env.MODE_ENV === 'separate') { 36 | process.env.MODULE_ENVS = process.env.MODULE_ENV 37 | // 分开打包时是通过重复运行指定模块打包命令实现的,所以每次都是单个html文件,只要配置一个htmlPlugin 38 | 39 | htmlWebpackPlugins.push(new HtmlWebpackPlugin({ 40 | filename: process.env.NODE_ENV === 'testing' ? 41 | 'index.html' : config.build.index, 42 | // template: 'index.html', 43 | template: config.build.htmlTemplate, 44 | inject: true, 45 | minify: { 46 | removeComments: true, 47 | collapseWhitespace: true, 48 | removeAttributeQuotes: true 49 | // more options: 50 | // https://github.com/kangax/html-minifier#options-quick-reference 51 | }, 52 | chunks: ['manifest','vendor', process.env.MODULE_ENVS], 53 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 54 | chunksSortMode: 'dependency' 55 | })) 56 | 57 | 58 | } else { 59 | console.log(chalk.red("打包某一个或整体打包,名为分别为:" + moduleToBuild.join(","))) 60 | // 一起打包时是通过多入口实现的,所以要配置多个htmlPlugin 61 | //console.log(chalk.red(moduleToBuild)) 62 | for (let module of moduleToBuild) { 63 | if (module == moduleIframe) { 64 | htmlWebpackPlugins.push(new HtmlWebpackPlugin({ 65 | filename: `${module}.html`, 66 | template: `./src/${module}/index.html`, 67 | inject: true, 68 | // 这里要指定把哪些chunks追加到html中,默认会把所有入口的chunks追加到html中,这样是不行的 69 | chunks: ['vendor', 'manifest', module], 70 | // filename: process.env.NODE_ENV === 'testing' 71 | // ? 'index.html' 72 | // : config.build.index, 73 | // template: 'index.html', 74 | minify: { 75 | removeComments: true, 76 | collapseWhitespace: true, 77 | removeAttributeQuotes: true 78 | // more options: 79 | // https://github.com/kangax/html-minifier#options-quick-reference 80 | }, 81 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 82 | chunksSortMode: 'dependency' 83 | })) 84 | } else { 85 | htmlWebpackPlugins.push(new HtmlWebpackPlugin({ 86 | filename: `${module}.html`, 87 | template: `./src/modules/${module}/index.html`, 88 | inject: true, 89 | // 这里要指定把哪些chunks追加到html中,默认会把所有入口的chunks追加到html中,这样是不行的 90 | chunks: ['vendor', 'manifest', module], 91 | // filename: process.env.NODE_ENV === 'testing' 92 | // ? 'index.html' 93 | // : config.build.index, 94 | // template: 'index.html', 95 | minify: { 96 | removeComments: true, 97 | collapseWhitespace: true, 98 | removeAttributeQuotes: true 99 | // more options: 100 | // https://github.com/kangax/html-minifier#options-quick-reference 101 | }, 102 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 103 | chunksSortMode: 'dependency' 104 | })) 105 | } 106 | } 107 | } 108 | 109 | var getcleanOnceBeforeBuildPatterns = function() { 110 | //let cleanArr=[path.join(__dirname, '../dist/*'), path.join(__dirname, '../dist/*.html'), '!static-files*'] 111 | let cleanArr = [path.resolve(__dirname, '../dist/static'), path.resolve(__dirname, '../dist/*.html')] 112 | // globdist.forEach((v, i) => { 113 | // console.log("ddddddd", globdist[i].split("/")[2].split(".")[0]) 114 | for (let module of moduleToBuild) { 115 | // if (globdist[i].split("/")[2].split(".")[0] != val) { 116 | //cleanArr.push('!' + module) 117 | //cleanArr.push("!"+path.resolve(__dirname, '../module/*')) 118 | // } 119 | }; 120 | // }); 121 | return cleanArr; 122 | } 123 | 124 | // 获取当前打包的目录名称 125 | const webpackConfig = merge(baseWebpackConfig, { 126 | module: { 127 | rules: utils.styleLoaders({ 128 | sourceMap: config.build.productionSourceMap, 129 | extract: true, 130 | usePostCSS: true 131 | }) 132 | }, 133 | devtool: config.build.productionSourceMap ? config.build.devtool : false, 134 | output: { 135 | path: config.build.assetsRoot, 136 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 137 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 138 | }, 139 | // before(app) { 140 | // // app.get('/moduleList', (req, res, next) => { 141 | // // res.send(html) 142 | // // }) 143 | // if (moduleToBuild.indexOf(moduleIframe)>=0) { 144 | // //路由重定向为框架页 145 | // app.get('/', (req, res, next) => { 146 | // //res.redirect('/moduleList') 147 | // res.redirect(`/${moduleIframe}/index.html` + "?manulist=" + moduleList.slice(1)) 148 | // }) 149 | // } 150 | // else{ 151 | // app.get('/', (req, res, next) => { 152 | // //res.redirect('/moduleList') 153 | // res.redirect(`/${moduleToBuild[0]}/index.html`) 154 | // }) 155 | // } 156 | // }, 157 | plugins: [ 158 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 159 | 160 | new webpack.DefinePlugin({ 161 | 'process.env': env 162 | }), 163 | new UglifyJsPlugin({ 164 | uglifyOptions: { 165 | compress: { 166 | warnings: false 167 | } 168 | }, 169 | sourceMap: config.build.productionSourceMap, 170 | parallel: true 171 | }), 172 | // extract css into its own file 173 | new ExtractTextPlugin({ 174 | filename: utils.assetsPath('css/[name].[contenthash].css'), 175 | // Setting the following option to `false` will not extract CSS from codesplit chunks. 176 | // Their CSS will instead be inserted dynamically with style-loader when the codesplit chunk has been loaded by webpack. 177 | // It's currently set to `true` because we are seeing that sourcemaps are included in the codesplit bundle as well when it's `false`, 178 | // increasing file size: https://github.com/vuejs-templates/webpack/issues/1110 179 | allChunks: true, 180 | }), 181 | // Compress extracted CSS. We are using this plugin so that possible 182 | // duplicated CSS from different components can be deduped. 183 | new OptimizeCSSPlugin({ 184 | cssProcessorOptions: config.build.productionSourceMap ? { safe: true, map: { inline: false } } : { safe: true } 185 | }), 186 | // generate dist index.html with correct asset hash for caching. 187 | // you can customize output by editing /index.html 188 | // see https://github.com/ampedandwired/html-webpack-plugin 189 | /* 190 | new HtmlWebpackPlugin({ 191 | filename: process.env.NODE_ENV === 'testing' 192 | ? 'index.html' 193 | : config.build.index, 194 | // template: 'index.html', 195 | template: config.build.htmlTemplate, 196 | inject: true, 197 | minify: { 198 | removeComments: true, 199 | collapseWhitespace: true, 200 | removeAttributeQuotes: true 201 | // more options: 202 | // https://github.com/kangax/html-minifier#options-quick-reference 203 | }, 204 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 205 | chunksSortMode: 'dependency' 206 | }), 207 | */ 208 | // keep module.id stable when vendor modules does not change 209 | new webpack.HashedModuleIdsPlugin(), 210 | // enable scope hoisting 211 | new webpack.optimize.ModuleConcatenationPlugin(), 212 | // split vendor js into its own file 213 | new webpack.optimize.CommonsChunkPlugin({ 214 | name: 'vendor', 215 | minChunks(module) { 216 | // any required modules inside node_modules are extracted to vendor 217 | return ( 218 | module.resource && 219 | /\.js$/.test(module.resource) && 220 | module.resource.indexOf( 221 | path.join(__dirname, '../node_modules') 222 | ) === 0 223 | ) 224 | } 225 | }), 226 | // extract webpack runtime and module manifest to its own file in order to 227 | // prevent vendor hash from being updated whenever app bundle is updated 228 | new webpack.optimize.CommonsChunkPlugin({ 229 | name: 'manifest', 230 | minChunks: Infinity 231 | }), 232 | // This instance extracts shared chunks from code splitted chunks and bundles them 233 | // in a separate chunk, similar to the vendor chunk 234 | // see: https://webpack.js.org/plugins/commons-chunk-plugin/#extra-async-commons-chunk 235 | new webpack.optimize.CommonsChunkPlugin({ 236 | name: 'app', 237 | async: 'vendor-async', 238 | children: true, 239 | minChunks: 3 240 | }), 241 | 242 | // copy custom static assets 243 | new CopyWebpackPlugin([{ 244 | from: path.resolve(__dirname, '../static'), 245 | to: config.build.assetsSubDirectory, 246 | ignore: ['.*'] 247 | }]), 248 | new CleanWebpackPlugin({ 249 | // Simulate the removal of files 250 | // default: false 251 | dry: false, 252 | // Write Logs to Console 253 | // (Always enabled when dry is true) 254 | // default: false 255 | verbose: false, 256 | // Automatically remove all unused webpack assets on rebuild 257 | // default: true 258 | cleanStaleWebpackAssets: true, //配置false,默认是:true,这个是在重建时自动删除所有未使用的webpack资产 259 | protectWebpackAssets: true, //配置false,默认是:true,不允许删除当前的webpack资产 260 | // **WARNING** 261 | // Use !negative patterns to exclude files 262 | //在Webpack编译之前删除一次文件,不包括重建中,配置是个数组,默认:['**/*'],如果是个空数组,则表示禁用 263 | cleanOnceBeforeBuildPatterns: getcleanOnceBeforeBuildPatterns(), 264 | 265 | //在每个与此模式匹配的构建(包括监视模式)后删除文件,用于不是由Webpack直接创建的文件,默认是个空数组禁用 266 | cleanAfterEveryBuildPatterns: ['static*.*', '!static1.js'], 267 | // Allow clean patterns outside of process.cwd() 268 | // requires dry option to be explicitly set 269 | // default: false 270 | dangerouslyAllowCleanPatternsOutsideProject: false, 271 | } 272 | 273 | ) 274 | ].concat(htmlWebpackPlugins) 275 | }) 276 | 277 | if (config.build.productionGzip) { 278 | const CompressionWebpackPlugin = require('compression-webpack-plugin') 279 | 280 | webpackConfig.plugins.push( 281 | new CompressionWebpackPlugin({ 282 | filename: '[path].gz[query]', 283 | algorithm: 'gzip', 284 | test: new RegExp( 285 | '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' 286 | ), 287 | threshold: 10240, 288 | minRatio: 0.8 289 | }) 290 | ) 291 | } 292 | 293 | if (config.build.bundleAnalyzerReport) { 294 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin 295 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()) 296 | } 297 | 298 | module.exports = webpackConfig 299 | -------------------------------------------------------------------------------- /build/webpack.test.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // This is the webpack config used for unit tests. 3 | 4 | const utils = require('./utils') 5 | const webpack = require('webpack') 6 | const merge = require('webpack-merge') 7 | const baseWebpackConfig = require('./webpack.base.conf') 8 | 9 | const webpackConfig = merge(baseWebpackConfig, { 10 | // use inline sourcemap for karma-sourcemap-loader 11 | module: { 12 | rules: utils.styleLoaders() 13 | }, 14 | devtool: '#inline-source-map', 15 | resolveLoader: { 16 | alias: { 17 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option 18 | // see discussion at https://github.com/vuejs/vue-loader/issues/724 19 | 'scss-loader': 'sass-loader' 20 | } 21 | }, 22 | plugins: [ 23 | new webpack.DefinePlugin({ 24 | 'process.env': require('../config/test.env') 25 | }) 26 | ] 27 | }) 28 | 29 | // no need for app entry during tests 30 | delete webpackConfig.entry 31 | 32 | module.exports = webpackConfig 33 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | // Template version: 1.3.1 3 | // see http://vuejs-templates.github.io/webpack for documentation. 4 | 5 | const path = require('path') 6 | 7 | //buiid类型 8 | const MODULE = process.env.MODULE_ENV || 'undefined' 9 | // 入口模板路径 10 | 11 | //定义build模版 12 | var htmlTemplate = `./src/modules/${MODULE}/index.html` 13 | 14 | //是否有框架页面 15 | const moduleIframe = require('../build/module-conf').moduleIframe 16 | const { framePage, isbuildassignmodules, buildmodules, modulesconfig, proxy,productionSourceMap,autoOpenBrowser, useEslint,showEslintErrorsInOverlay,productionGzip } = require('../projectConfig') 17 | //获取框架页模版 18 | if (MODULE == moduleIframe) { htmlTemplate = `./src/${MODULE}/index.html` } 19 | 20 | 21 | //开发模式配置 22 | module.exports = { 23 | dev: { 24 | // Paths 25 | assetsSubDirectory: 'static', 26 | assetsPublicPath: '/', 27 | proxy: proxy||{//配置代理 28 | '/api': { 29 | target: 'http://www.abc.com', //目标接口域名 30 | changeOrigin: true, //是否跨域 31 | pathRewrite: { 32 | '^/api': '/api' //重写接口 33 | } 34 | } 35 | }, 36 | // Various Dev Server settings 37 | host: 'localhost', // can be overwritten by process.env.HOST 38 | port: 8086, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined 39 | 40 | errorOverlay: true, 41 | notifyOnErrors: true, 42 | poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions- 43 | 44 | // Use Eslint Loader? 45 | // If true, your code will be linted during bundling and 46 | // linting errors and warnings will be shown in the console. 47 | autoOpenBrowser: autoOpenBrowser || true, 48 | useEslint: useEslint || false, 49 | // If true, eslint errors and warnings will also be shown in the error overlay 50 | // in the browser. 51 | showEslintErrorsInOverlay: showEslintErrorsInOverlay||false, 52 | 53 | /** 54 | * Source Maps 55 | */ 56 | 57 | // https://webpack.js.org/configuration/devtool/#development 58 | devtool: 'cheap-module-eval-source-map', 59 | 60 | // If you have problems debugging vue-files in devtools, 61 | // set this to false - it *may* help 62 | // https://vue-loader.vuejs.org/en/options.html#cachebusting 63 | cacheBusting: true, 64 | 65 | cssSourceMap: true 66 | }, 67 | 68 | build: { 69 | // Template for index.html 70 | index: path.resolve(__dirname, '../dist', MODULE, 'index.html'), 71 | // 加入html入口 72 | htmlTemplate: htmlTemplate, 73 | // Paths 74 | // assetsRoot: path.resolve(__dirname, '../dist', MODULE), 75 | // 这里判断一下打包的模式,如果是分开打包,要把成果物放到以模块命名的文件夹中 76 | assetsRoot: process.env.MODE_ENV === 'separate' ? path.resolve(__dirname, '../dist', MODULE) : path.resolve(__dirname, '../dist'), 77 | assetsSubDirectory: 'static', 78 | // 这里的路径改成相对路径,原来是assetsPublicPath: '/', 79 | // assetsPublicPath: '/', 80 | assetsPublicPath: './', 81 | 82 | /** 83 | * Source Maps 84 | */ 85 | 86 | productionSourceMap: productionSourceMap||false, 87 | // https://webpack.js.org/configuration/devtool/#production 88 | devtool: '#source-map', 89 | // Gzip off by default as many popular static hosts such as 90 | // Surge or Netlify already gzip all static assets for you. 91 | // Before setting to `true`, make sure to: 92 | // npm install --save-dev compression-webpack-plugin 93 | productionGzip: productionGzip||false, 94 | productionGzipExtensions: ['js', 'css'], 95 | 96 | // Run the build command with an extra argument to 97 | // View the bundle analyzer report after build finishes: 98 | // `npm run build --report` 99 | // Set to `true` or `false` to always turn it on or off 100 | bundleAnalyzerReport: process.env.npm_config_report 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const devEnv = require('./dev.env') 4 | 5 | module.exports = merge(devEnv, { 6 | NODE_ENV: '"testing"' 7 | }) 8 | -------------------------------------------------------------------------------- /document/component.txt: -------------------------------------------------------------------------------- 1 | export default { 2 | name: ’string’ 3 | components: {}, //{组件1,组件2},所导入组件名 4 | props: {} || [], // 组件父组件传递值,推荐用对象形式,例如: 5 | props: { 6 | yearlimit: { 7 | type: Array, //注意若类型为Object||Array,default的值必须用工厂函数返回 8 | default: function() { 9 | return []; 10 | //[min,max] 11 | } 12 | }, 13 | }, 14 | data() { returen { dataobj: { key: value } } }, //组件数据源 15 | 16 | beforeCreate() { 17 | //alert("创建vue实例前") 18 | }, 19 | created() { 20 | //alert("实例创建完成") 21 | }, 22 | beforeMount() { 23 | //alert("虚拟dom开始挂载到实际dom树中") 24 | }, 25 | mounted() { 26 | //alert("虚拟dom已经挂载到实际dom树中,页面加载完成"); 27 | }, 28 | beforeUpdate() { 29 | //alert("更新前") 30 | }, 31 | updated() { 32 | //alert("更新完成") 33 | }, 34 | beforeDestroy() { 35 | //alert("销毁前") 36 | }, 37 | destroyed() { 38 | //alert("销毁完成") 39 | }, 40 | //以上8个为vue的一个生命周期 41 | 42 | activated() { 43 | //在vue对象存活的情况下,进入当前存在activated()函数的页面时,一进入页面就触发;可用于初始化页面数据等 44 | }, 45 | beforeRouteEnter(to, from, next) { 46 | // 进入路由前 47 | console.log(this, 'beforeRouteUpdate'); //undefined 48 | next(vm => { 49 | //因为当钩子执行前,组件实例还没被创建 50 | // vm 就是当前组件的实例相当于上面的 this,所以在 next 方法里你就可以把 vm 当 this 来用了。 51 | console.log(vm); //当前组件的实例 52 | }) 53 | }, 54 | beforeRouteUpdate(to, from, next) { 55 | //在当前路由改变,但是该组件被复用时调用 56 | //对于一个带有动态参数的路径 /good/:id,在 /good/1 和 /good/2 之间跳转的时候, 57 | // 由于会渲染同样的good组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 58 | // 可以访问组件实例 `this` 59 | console.log(this, 'beforeRouteUpdate'); //当前组件实例 60 | next(); 61 | }, 62 | beforeRouteLeave(to, from, next) { 63 | // 导航离开该组件的对应路由时调用 64 | // 可以访问组件实例 `this` 65 | console.log(this, 'beforeRouteLeave'); //当前组件实例 66 | next(); 67 | }, 68 | computed: { //计算属性 69 | key() { //这里的key相当于date里面的数据源,不能在data里面重复定义 70 | return a newValue by calculating and refining known properties in data 71 | //return a value(必须) 72 | } 73 | }, 74 | filters: { //过滤器,对一些绑定值进行过滤筛选,比如只允许输入数字 v-model=”value| filterDigital” 75 | filterName(value) { 76 | return a newValue by filter the value 77 | } 78 | }, 79 | methods: { 80 | methodName(arg…) { 81 | //要执行的操作 82 | }, 83 | }, 84 | watch: { 85 | dataobj: { 86 | handler() { 87 | //要执行的操作 88 | }, 89 | deep: true, //是否深度监听,意为对象dataobj内部任何属性发生变化则全局重新渲染 90 | immediate: true // 代表在wacth里声明了dataobj这个方法之后立即先去执行handler方法 91 | } 92 | } 93 | } 94 | 95 | 96 | 97 | 98 | Vue所有的生命周期钩子自动绑定在this上下文到实例中,因此你可以访问数据,对属性和方法进行运算。这意味着你不能使用箭头函数来定义一个生命周期方法。这是因为箭头函数绑定了父上下文,因此this与你期待的Vue实例不同。 99 | 1、beforeCreate 100 |   在实例初始化之后,数据观测和event/watcher时间配置之前被调用。 101 | 2、created 102 |   实例已经创建完成之后被调用。在这一步,实例已经完成以下的配置:数据观测,属性和方法的运算,watch/event事件回调。然而,挂载阶段还没开始,$el属性目前不可见。 103 | 3、beforeMount 104 |   在挂载开始之前被调用:相关的render函数首次被调用。 105 |   该钩子在服务器端渲染期间不被调用。 106 | 4、mounted 107 |   el被新创建的vm.$el替换,并挂在到实例上去之后调用该钩子函数。如果root实例挂载了一个文档内元素,当mounted被调用时vm.$el也在文档内。 108 |   该钩子在服务端渲染期间不被调用。 109 | 5、beforeUpdate 110 |   数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前。 111 |   你可以在这个钩子中进一步第更改状态,这不会触发附加的重渲染过程。 112 |   该钩子在服务端渲染期间不被调用。 113 | 6、updated 114 |   由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。 115 |   当这个钩子被调用时,组件DOM已经更新,所以你现在可以执行依赖于DOM的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无限循环。 116 |   该钩子在服务端渲染期间不被调用。 117 | 7、activated 118 |   keep-alive组件激活时调用。 119 |   该钩子在服务器端渲染期间不被调用。 120 | 8、deactivated 121 |    122 | 9、beforeDestroy 【类似于React生命周期的componentWillUnmount】 123 |   实例销毁之间调用。在这一步,实例仍然完全可用。 124 |   该钩子在服务端渲染期间不被调用。 125 | 10、destroyed 126 |   Vue实例销毁后调用。调用后,Vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。 127 |   该钩子在服务端渲染不会被调用。 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 这里放置全局组件 145 | 146 | 全局组件为了方便公用,及以后调用,全局组件中每一个组件文件夹中应包含组件名及所用素材资源文件,若仅为样式不需要img等资源则写为一个文件即可,另外每一个组件附上调用说明 147 | 148 | 关于全局组件和路由皆以如下懒加载的方式调用 149 | 150 | 路由和组件的常用两种懒加载方式: 151 | 1、vue异步组件实现路由懒加载 152 |   component:resolve=>(['需要加载的路由的地址',resolve]) 153 | 2、es提出的import(推荐使用这种方式) 154 |  const HelloWorld = ()=>import('需要加载的模块地址') 155 | npm run build后会新增路由数量与之加载相匹配的.js文件,在切到相应路由或组件时动态加载这个文件。 156 | 157 | // 这两条路由被打包在相同的块中,访问任一路由都会延迟加载该路由组件 158 | const OtherMassivePage = r => require.ensure([], () => r(require('./routes/OtherMassivePage.vue')), 'big-pages') 159 | const WeightLossPage = r => require.ensure([], () => r(require('./routes/WeightLossPage.vue')), 'big-pages') 160 | 161 | vue render函数说明 162 | render: (h, params) => { 163 | var vm = this; 164 | return h('Input', { 165 | attrs: { 166 | value: params.row.age, 167 | readonly: params.row.status == 2 ? false : true, 168 | class: params.row.status == 2 ? "border ivu-input" : "noborder ivu-input", 169 | }, 170 | on: { 171 | input(val) { 172 | 这里用的是iview Input组件,input事件的返回值是改变后的值,若要调用event,需直接调用:var event=window.event; 173 | 若直接用原生的input标签,input事件的返回值是event,改编后的值用event.target.value; 174 | //值改变时 175 | //将渲染后的值重新赋值给单元格值; 176 | params.row.age = val; 177 | vm.data8[params.index] = params.row; 178 | } 179 | } 180 | }) 181 | } 182 | 上面是渲染表格的某一列的一个例子,当需要分情况渲染不同元素时,可以如下格式去写: 183 | render: (h, params) => { 184 | return h('div', [ 185 | h('Button', { 186 | style: { 187 | display: params.row.status == 0 ? "inline-block" : "none", 188 | marginRight: '5px' 189 | }, 190 | on: { 191 | click: () => { 192 | this.edit(params.index) 193 | } 194 | } 195 | }, 'edit'), 196 | h('Button', { 197 | style: { 198 | display: params.row.status == 2 ? "inline-block" : "none", 199 | marginRight: '5px' 200 | }, 201 | on: { 202 | click: () => { 203 | this.endedit(params.index) 204 | } 205 | } 206 | }, 'endedit') 207 | ]); 208 | } 209 | } 210 | 211 | h相当于createElement,为一个回调函数,h的第二个参数为一个对象,也可以为一个数组,每个值又为一个对象,当然也可以嵌套多层标签,支持的所有属性如下(以下所有的属性值都支持表达式赋值) 212 | { 213 | // 和`v-bind:class`一样的 API 214 | 'class': { 215 | foo: true, 216 | bar: false 217 | }, 218 | // 和`v-bind:style`一样的 API 219 | style: { 220 | color: 'red', 221 | fontSize: '14px' 222 | }, 223 | // 正常的 HTML 特性 224 | attrs: { 225 | id: 'foo' 226 | }, 227 | // 组件 props 228 | props: { 229 | myProp: 'bar' 230 | }, 231 | // DOM 属性 232 | domProps: { 233 | innerHTML: 'baz' 234 | }, 235 | // 事件监听器基于 `on` 236 | // 所以不再支持如 `v-on:keyup.enter` 修饰器 237 | // 需要手动匹配 keyCode。 238 | on: { 239 | click: this.clickHandler 240 | }, 241 | // 仅对于组件,用于监听原生事件,而不是组件内部使用 `vm.$emit` 触发的事件。 242 | nativeOn: { 243 | click: this.nativeClickHandler 244 | }, 245 | // 自定义指令。注意事项:不能对绑定的旧值设值 246 | // Vue 会为您持续追踪 247 | directives: [ 248 | { 249 | name: 'my-custom-directive', 250 | value: '2', 251 | expression: '1 + 1', 252 | arg: 'foo', 253 | modifiers: { 254 | bar: true 255 | } 256 | } 257 | ], 258 | // Scoped slots in the form of 259 | // { name: props => VNode | Array } 260 | scopedSlots: { 261 | default: props => createElement('span', props.text) 262 | }, 263 | // 如果组件是其他组件的子组件,需为插槽指定名称 264 | slot: 'name-of-slot', 265 | // 其他特殊顶层属性 266 | key: 'myKey', 267 | ref: 'myRef' 268 | } 269 | 270 | -------------------------------------------------------------------------------- /document/main.txt: -------------------------------------------------------------------------------- 1 | 2 | import Vue from 'vue' 3 | import App from './App' 4 | 5 | //Vue.use(plugin) 6 | 7 | var curvue=new Vue({ 8 | el: '#app', 9 | router, 10 | store, 11 | components: { App }, 12 | template: '' 13 | }) 14 | console.log(curvue); 15 | 16 | 1、实例属性 17 | 组件树访问 18 | $parent -----> 用来访问当前组件实例的父实例; 19 | $root -----> 用来访问当前组件树的根实例,如果当前组件没有父实例,则$root表示当前组件实例本身; 20 | $children -----> 用来访问当前组件实例的 直接 子组件实例; 21 | $refs -----> 用来访问使用了v-ref指令的子组件; 22 | DOM访问 23 | $el -----> 用来访问挂载当前组件实例的DOM元素; 24 | $els -----> 用来访问使用了v-el指令的DOM元素(已经被废除); 25 | 数据访问 26 | $data -----> 用来访问组件实例观察的数据对象,该对象引用组件实例化时选项中的data属性; 27 | $options -----> 用来访问组件实例化时的初始化选项对象; 28 | 29 | 30 | 31 | 2、实例方法 32 | 33 | 方法: 34 | vm.$mount() 35 | #手动挂载 36 | //vm.$mount('#app'); 37 | 38 | vm.$destroy() 39 | #销毁实例 40 | 41 | vm.$nextTick(callback) 42 | #将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新,直到DOM结构加载完成;。 43 | 44 | vm.$set(object,key,value) 45 | #添加属性值 46 | Vue.set(this.user,'age',1) 47 | 48 | 49 | vm.$delete(object,key) 50 | #删除属性值 51 | Vue.delete(this.user,'age') 52 | 53 | vm.$watch(data,callback[,options]) 54 | #更新属性值 55 | 56 | vm.$watch(data,callback[,options]) 57 | #监测数值变化 58 | 59 | 60 | 内部插入 61 | $appendTo()可以将el指向的DOM元素或片段插入到目标元素中; 62 | 第一个参数:选择器字符串或者DOM元素 63 | 第二个参数:callback回调函数,成功插入到目标元素后被触发(并且如果el应用了过渡效果,则回调在过渡完成后触发) 64 | 65 | 同级插入 66 | $before()可以将el指向的DOM元素或片段插入到目标元素之前; 67 | 第一个参数:选择器字符串或者DOM元素 68 | 第二个参数:callback回调函数,成功插入到目标元素后被触发(并且如果el应用了过渡效果,则回调在过渡完成后触发) 69 | 70 | $after()可以将el指向的DOM元素或片段插入到目标元素之后; 71 | 第一个参数:选择器字符串或者DOM元素 72 | 第二个参数:callback回调函数,成功插入到目标元素后被触发(并且如果el应用了过渡效果,则回调在过渡完成后触发) 73 | 74 | 删除 75 | $remove()可以将el指向的DOM元素或片段从DOM中删除; 76 | 只有一个callback作为参数,在el元素从DOM中删除完成后触发(并且如果el应用了过渡效果,则回调在过渡完成后触发) 77 | $remove删除数据结构 splice根据索引值删除,批量删除都要采用倒序删除,获取到索引值非要使用$remove的方法是this.data.$remove(this.data[index]),还是删除数据结构 78 | 只有一个callback作为参数,回调函数的this会自动绑定到调用它的Vue实例上; 79 | 80 | 3、实例Event方法的使用 81 | 82 | 监听 83 | $on(event(事件名称),callback)监听实例的自定义事件,回调会在触发“触发事件”后进行触发 84 | $once(event(事件名称),callback)监听实例的自定义事件,但只执行一次,回调会在触发“触发事件”后进行触发 85 | 触发 86 | $emit(event(事件名称),args(传递给监听函数的参数))用来触发事件; 87 | $dispatch(event(事件名称),args(传递给监听函数的参数))用来派发事件,即先在当前实例触发,然后沿着父链一层一层向上,如果对应的监听函数返回false后停止; 88 | $broadcast(event(事件名称),args(传递给监听函数的参数))用来广播事件,即遍历当前实例的$children,如果对应的监听函数返回false后就停止; 89 | 删除 90 | $off(event(事件名称),callback)用来删除事件监听器;(如果没有参数,删除所有的事件监听器;如果只提供一个事件名称参数,则删除这一个事件监听器;如果提供事件名与回调,则删除对应的回调函数) 91 | 92 | -------------------------------------------------------------------------------- /document/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | 7 | // import HelloWorld from '@/components/HelloWorld' 8 | // const HelloWorld = () => import('../components/HelloWorld') 9 | const Home = r => require.ensure([], () => r(require('@/components/Home')), 'Home'); 10 | const HelloWorld = r => require.ensure([], () => r(require('@/components/childrenleve1/HelloWorld')), 'HelloWorld'); 11 | const Component1 = r => require.ensure([], () => r(require('@/components/childrenleve1/component1')), 'Component'); 12 | const Component2 = r => require.ensure([], () => r(require('@/components/childrenleve1/component2')), 'Component'); 13 | const Vuexstore = r => require.ensure([], () => r(require('@/components/childrenleve1/Vuexstore')), 'Vuexstore'); 14 | const Table = r => require.ensure([], () => r(require('@/components/childrenleve1/table')), 'Table'); 15 | const Vuerender = r => require.ensure([], () => r(require('@/components/childrenleve1/Vuerender')), 'Vuerender'); 16 | export default new Router({ 17 | routes: [{ 18 | path: '/', 19 | name: 'Home', 20 | component: Home, 21 | children: [{ 22 | path: 'HelloWorld', 23 | name: 'HelloWorld', 24 | component: HelloWorld, //resolve => require(['../components/HelloWorld'], resolve) 25 | meta: { 26 | auth: true, 27 | keepAlive: true 28 | } 29 | }, 30 | { 31 | path: 'HelloWorld/Component1', 32 | name: 'Component1', 33 | component: Component1, 34 | 35 | }, 36 | { 37 | path: 'Component2', 38 | name: 'Component2', 39 | component: Component2, 40 | meta: { 41 | keepAlive: true 42 | }, 43 | children: [{ 44 | path: '/Vuexstore', 45 | name: 'Vuexstore', 46 | component: Vuexstore, 47 | }] 48 | }, 49 | { 50 | path: 'Table', 51 | name: 'Table', 52 | component:Table , 53 | }, 54 | 55 | ] 56 | }] 57 | }) 58 | -------------------------------------------------------------------------------- /document/router/router.txt: -------------------------------------------------------------------------------- 1 | 使用Vue搭建项目的时候,为了避免一个页面过大,将本应该一个页面显示的内容分成多个页面,并使用同级视图展示。 2 | 3 | 路由说明 4 | 路由说明文字 是一个用来让用户在 vue-router 应用的不同路径间跳转的标签。该指令to属性 接收一个 JavaScript 表达式,并会在用户点击元素时用该表达式的值去调用 router.Go。 5 | router-link不支持target="_blank",它是一个开发单页应用的组件,所以,想要打开新窗口还是要使用a标签,如果要引入路由相关信息,一定要引入vue-router插件。 6 | 7 | 具体来讲,router-link有三种用法: 8 | 9 | name 10 | 11 | name 14 | v-link 会自动设置 的 href 属性,你无需使用href来处理浏览器的调整,原因如下: 15 | 它在 HTML5 history 模式和 hash 模式下的工作方式相同,所以如果你决定改变模式,或者 IE9 浏览器退化为 hash 模式时,都不需要做任何改变。 16 | 在 HTML5 history 模式下使用 root 选项时,不需要在 router-link 的 URL 中包含 root 路径。 17 | 18 | 除过 name,直接跳转外,路由也可使用编程式路由进行跳转: 19 | 具体如下 20 | $router.push(“name”); 21 | $router.push({path:”name”}); 22 | $router.push({path:”name”?a=123}); //传参 23 | $router.push({path:”name”,query:{a:123}}); 24 | $router.go(*); go(-1)返回到上一个路由,go(1),若有返回记录则前进到下一个路由 25 | 参数查询:$router.query.[参数名] 26 | 27 | 路由对象: 28 | 在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新。 29 | $route:{ 30 | path:"str",//绝对路径 31 | params:{},//包含路由中的动态片段和全匹配片段的键值对 32 | query:{}, //包含路由中查询参数的键值对。例如,对于 /home/news/detail/. 01?favorite=yes ,会得到$route.query.favorite == 'yes' 。 33 | hash:'', 34 | router:"",//路由规则所属的路由器(以及其所属的组件)。 35 | fullPath:'str', 36 | matched:[],//数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。 37 | name:"name",//当前路径的名字,如果没有使用具名路径,则名字为空。 38 | redirectedFrom:"name",//当路由中设置了重定向会显示此参数,路由重定向来源 39 | } 40 | 当路由地址中使用一个通配符*时,$route.params 内会自动添加一个名为 pathMatch 参数,同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。 41 | 42 | 在页面上添加以下代码,可以显示这些路由对象的属性: 43 |
44 |

当前路径:{{$route.path}}

45 |

当前参数:{{$route.params | json}}

46 |

路由名称:{{$route.name}}

47 |

路由查询参数:{{$route.query | json}}

48 |

路由匹配项:{{$route.matched | json}}

49 |
50 | 51 | 使用标签,它用于渲染匹配的组件,router-view放置路径位置与routers 对应一致, 52 | 53 | 扩展:指定路由跳转放置插槽,可以使用name属性指定,这里的name值一定是组件name,即路由配置中component的值, 54 | 同一路由渲染多个组件亦可路由中配置component:{default:组件1,hello:组件2,text:组件3} 55 | //将渲染组件1 56 | //将渲染组件2 57 | //将渲染组件3 58 | */ 59 | const router = new VueRouter({ 60 | routes: [ 61 | { 62 | path: '/', 63 | name:"Hello", 64 | components: { 65 | default: componentsDefault, 66 | Hello: componentsHello, 67 | Text: componentsText 68 | }, 69 | redirect: '/Hello', // { name: 'Hello' } || to => {// 方法接收 目标路由 作为参数// return 重定向的 字符串路径/路径对} 70 | alias: '/Hello', / 的别名是 /Hello,意味着,当用户访问 /Hello 时,URL 会保持为 /Hello,但是路由匹配则为 /,就像用户访问 / 一样。 71 | props: { default: true, Hello: false,Text:false },//参数解耦 72 | beforeEnter: (to, from, next) => { //专属守卫 73 | // ... 74 | } 75 | meta: {//路由申明 76 | auth: true, 77 | keepAlive: true 78 | }, 79 | children: [] 80 | } 81 | } 82 | ] 83 | }) 84 | 85 | 86 | 87 | 88 | router 方法 89 | router.push(location, onComplete?, onAbort?) 90 | router.replace(location, onComplete?, onAbort?) 91 | router.go(n) 92 | router.back() 93 | router.forward() 94 | router.addRoutes(routes: Array) 动态添加更多的路由规则。参数必须是一个符合 routes 选项要求的数组。 95 | router.onReady(callback, [errorCallback]) 该方法把一个回调排队,在路由完成初始导航时调用,这意味着它可以解析所有的异步进入钩子和路由初始化相关联的异步组件 96 | router.onError(callback)注册一个回调,该回调会在路由导航过程中出错时被调用。注意被调用的错误必须是下列情形中的一种:错误在一个路由守卫函数中被同步抛出;错误在一个路由守卫函数中通过调用 next(err) 的方式异步捕获并处理;渲染一个路由的过程中,需要尝试解析一个异步组件时发生错误。 97 | 98 | 99 | 100 | const router = new VueRouter({ 101 | routes: [...], 102 | scrollBehavior (to, from, savedPosition) { 103 | // `to` 和 `from` 都是路由对象 104 | // return 期望滚动到哪个的位置 105 | if (savedPosition) { 106 | return savedPosition 107 | } else { 108 | return { x: 0, y: 0 } 109 | } 110 | 111 | //异步滚动 112 | return new Promise((resolve, reject) => { 113 | setTimeout(() => { 114 | resolve({ x: 0, y: 0 }) 115 | }, 500) 116 | }) 117 | 118 | if (to.hash) { 119 | return { 120 | selector: to.hash 121 | } 122 | } 123 | }, 124 | 125 | }) 126 | 127 | 路由守卫 128 | router.beforeEach((to, from, next) => { 129 | // `to` 和 `from` 都是路由对象 130 | /* must call `next` */ 131 | next() 132 | next(false) 133 | next({ path: '/' })||next('/') 134 | next(error) 135 | }) 136 | 137 | router.beforeResolve((to, from, next) => { 138 | /* must call `next` */ 139 | }) 140 | router.afterEach((to, from) => {}) 141 | 142 | 143 | 组件内部守卫 144 | beforeRouteEnter(to, from, next) { 145 | // 在渲染该组件的对应路由被 confirm 前调用 146 | // 不!能!获取组件实例 `this` 147 | // 因为当守卫执行前,组件实例还没被创建 148 | next(vm => { 149 | // 通过 `vm` 访问组件实例 150 | }) 151 | }, 152 | beforeRouteUpdate(to, from, next) { 153 | // 在当前路由改变,但是该组件被复用时调用 154 | // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候, 155 | // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。 156 | // 可以访问组件实例 `this` 157 | // just use `this` 158 | next() 159 | }, 160 | beforeRouteLeave(to, from, next) { 161 | // 导航离开该组件的对应路由时调用 162 | // 可以访问组件实例 `this` 163 | const answer = window.confirm('Do you really want to leave? you have unsaved changes!') 164 | if (answer) { 165 | next() 166 | } else { 167 | next(false) 168 | } 169 | } 170 | 171 | 172 | 173 | 动态过渡 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 完整的导航解析流程 183 | 导航被触发。 184 | 在失活的组件里调用离开守卫。 185 | 调用全局的 beforeEach 守卫。 186 | 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。 187 | 在路由配置里调用 beforeEnter。 188 | 解析异步路由组件。 189 | 在被激活的组件里调用 beforeRouteEnter。 190 | 调用全局的 beforeResolve 守卫 (2.5+)。 191 | 导航被确认。 192 | 调用全局的 afterEach 钩子。 193 | 触发 DOM 更新。 194 | 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。 195 | 196 | 197 | 198 | 生命周期钩子:必要的保持,不必要不要保持 199 | 在被keep-alive包含的组件/路由中,会多出两个生命周期的钩子:activated 与 deactivated 200 | activated在组件第一次渲染时会被调用,之后在每次缓存组件被激活时调用 201 | deactivated:组件被停用(离开路由)时调用 202 | 注意:使用了keep-alive就不会调用beforeDestroy(组件销毁前钩子)和destroyed(组件销毁),因为组件没被销毁,被缓存起来了。 203 | keep-alive的生命周期 204 | activated: 页面第一次进入的时候,钩子触发的顺序是created->mounted->activated 205 | deactivated: 页面退出的时候会触发deactivated,当再次前进或者后退的时候只触发activated 206 | 207 | 208 | 209 | 210 | 我不想把查询条件和查询结果被缓存,那么我可以这样写: 211 | mounted: function() { 212 | this.loaddata(1) 213 | }, 214 | activated: function () { 215 | this.productclass.name=""//查询条件 216 | this.loaddata(1) //查询结果的方法 217 | } 218 | 新增属性: 219 | include 字符串或正则表达式,只有名称匹配的组件会被缓存 220 | exclude 字符串或正则表达式,任何名称匹配的组件都不会被缓存 221 | max 数字,最多可以缓存多少组件实例 222 | include和exclude支持三种方式来有条件的缓存路由:采用逗号分隔的字符串形式,正则形式,数组形式。 223 | 正则和数组形式,必须采用v-bind形式来使用 224 | 225 | 缓存组件的使用方式: 226 | 227 | 228 | 229 | 230 | 231 | 232 | 但更多场景中,我们会使用keep-alive来缓存路由: 233 | 234 | 235 | 236 | 注:当组件被exclude匹配,该组件将不会被缓存,不会调用activated 和 deactivated。 237 | 238 | include和exclude的值一定是组件名(组件export default 里面的name) 239 | 240 | 241 | //以下是成对出现的 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | //router配置 254 | new Router({ 255 | routes: [ 256 | { 257 | path: '/', 258 | name: 'home', 259 | component: Home, 260 | meta: { 261 | keepAlive: true // 需要被缓存 262 | } 263 | }, 264 | { 265 | path: '/edit', 266 | name: 'edit', 267 | component: Edit, 268 | meta: { 269 | keepAlive: false // 不需要被缓存 270 | } 271 | } 272 | ] 273 | }) 274 | 275 | 276 | 路由生命周期执行顺序: 277 | 278 | main.js 279 | import Vue from 'vue'; 280 | // 实例化Vue对象并挂载 281 | new Vue({ 282 | router 283 | }).$mount('#app'); 284 | 285 | 286 | mport Vue from 'vue'; 287 | import VueRouter from 'vue-router'; 288 | // Vue中插件必须use注册 289 | Vue.use(VueRouter); 290 | 291 | // 路由配置项,此处是路由级钩子的定义 292 | const routes = [{ 293 | path: '/', 294 | component: resolve => require(['./index.vue'], resolve), 295 | keepAlive: true, 296 | }, 297 | { 298 | path: '/user/:userName', 299 | keepAlive: true, 300 | beforeEnter(to,from,next){ 301 | console.log('router beforeEnter'); 302 | next(); 303 | }, 304 | component: resolve => require(['./user.vue'], resolve), 305 | }]; 306 | 307 | // 实例化路由对象 308 | const router = new VueRouter({ 309 | routes 310 | }); 311 | // 全局钩子 312 | router.beforeEach((to,from,next)=>{ 313 | console.log('global beforeEach') 314 | next(); 315 | }); 316 | router.beforeResolve((to,from,next)=>{ 317 | console.log('global beforeResolve') 318 | next(); 319 | }); 320 | router.afterEach((to,from,next)=>{ 321 | console.log('global afterEach') 322 | }); 323 | 324 | user.vue 325 | 331 | 332 | 361 | 362 | 执行时机 363 | 由首页进入user页面: 364 | global beforeEach > router beforeEnter > component beforeRouteEnter > global beforeResolve > global afterEach > mounted 365 | 由user回到首页: 366 | component beforeRouteLeave => global beforeEach => global beforeResolve => global afterEach 367 | 排除beforeRouteUpdate,其余六个导航钩子的执行时机其实很好理解。大体按照leave、before、enter、resolve、after的顺序并全局优先的思路执行。beforeRouteUpdate的触发是在动态路由情形下,比如 path: '/user/:userName' 这条路由,当页面不变更只动态的改变参数userName时,beforeRouteUpdate便会触发。 368 | 总结:使用vue组件拼凑成整个应用,每个页面是独立的,路由依靠链接跳转,会刷新页面。使用vue-router则可以不刷新页面加载对应组件,hash和history模式模拟路径变化,不刷新页面。 369 | 370 | -------------------------------------------------------------------------------- /document/vue-multipage-platform-project.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/document/vue-multipage-platform-project.docx -------------------------------------------------------------------------------- /document/vuex/Vuexstore.vue: -------------------------------------------------------------------------------- 1 | 14 | 110 | 111 | 119 | -------------------------------------------------------------------------------- /document/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | const state = { 7 | loading: false, 8 | userInfo: { 9 | phone: 123456789000000, 10 | account: "Titans", 11 | }, //用户信息 12 | login: false, //是否登录 13 | shopList:[{ 14 | id: 1, 15 | name: '兰博基尼', 16 | price: 10 17 | },{ 18 | id: 2, 19 | name: '五菱宏光', 20 | price: 99999 21 | }], 22 | }; 23 | 24 | const getters = { //实时监听state值的变化(最新状态) 25 | isloading(state) { //承载变化的login的值. //.$store.getters.isloading 26 | return state.loading 27 | }, 28 | islogin(state) { 29 | return state.login 30 | }, 31 | getuserInfo(state){ 32 | return state.userInfo 33 | } 34 | }; 35 | const mutations = { 36 | setloading(state, isshow) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象); 37 | state.loading = isshow; 38 | }, 39 | setlogin(state, islogin) { //this.$store.commit("setlogin", true) 40 | state.login = islogin; 41 | }, 42 | setuserInfo(state, userInfoobj){ 43 | state.userInfo=userInfoobj 44 | } 45 | }; 46 | const actions = { 47 | asyncsetoading: (context,loadingstatus) => {//this.$store.dispatch("asyncsetoading", false) 48 | context.commit('setloading',loadingstatus); 49 | }, 50 | }; 51 | const modulea = { 52 | namespaced: true, 53 | state: { 54 | usera: "taitan", 55 | shopList: [{ 56 | id: 1, 57 | name: '兰博基尼', 58 | price: 10 59 | }, { 60 | id: 2, 61 | name: '五菱宏光', 62 | price: 99999 63 | }], 64 | }, 65 | mutations: { 66 | setusera(state,name) { 67 | state.usera = name 68 | } 69 | }, 70 | actions: { 71 | asyncsetusera:(context, name)=> { 72 | context.commit("setusera", name) 73 | } 74 | }, 75 | getters: { 76 | getusera(state) { 77 | return state.modulea.usera 78 | } 79 | 80 | } 81 | } 82 | export default new Vuex.Store({ 83 | state, 84 | getters, 85 | mutations, 86 | actions, 87 | modules: { modulea 88 | } 89 | }); 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /document/vuex/vueX.txt: -------------------------------------------------------------------------------- 1 | 2 | vueX使用说明 3 | 4 | 1、this.$store : 我们可以通过 this.$store 在vue的组件中获取vuex的实例。 5 | 2、State : vuex中的数据源,我们可以通过 this.$store.state 获取我们在vuex中声明的全局变量的值。 6 | 3、Getter: 相当于vue中的computed , 及 计算属性, 可以用于监听、计算 state中的值的变化 7 | 4、Mutation: vuex中去操作数据的方法 (只能同步执行) 8 | 5、Action: 用来操作 Mutation 的动作 , 他不能直接去操作数据源,但可以把mutation变为异步的 9 | 6、Module: 模块化,当你的应用足够大的时候,你可以把你的vuex分成多个子模块 10 | 11 | import Vue from 'vue'; 12 | import Vuex from 'vuex'; 13 | Vue.use(Vuex); 14 | export default new Vuex.Store({ 15 | // 在state中去声明全局变量,可以通过 this.$store.state 访问 16 | state: { 17 | count: 0 18 | }, 19 | // 在getters中声明state中变量的计算函数,缓存计算后的数据, 通过 this.$store.getters 调用 20 | getters: { 21 | // 接受state作为参数,每次 count发生变化时 , 都会被调用 22 | consoleCount: state => { 23 | console.log('the state count : ' + state.count); 24 | return state.count; 25 | } 26 | }, 27 | // 只能执行同步方法,不要去执行异步方法 通过 this.$store.commit 方法去调用 28 | mutations: { 29 | // 改变state状态的方法,不建议直接通过 30 | // this.$store.state.? = ?的方式改变state中的状态 31 | addCount: state => { 32 | ++state.count; 33 | }, 34 | // 自定义改变state初始值的方法,mutations的第一个参数即为state对象,并且可以向mutation传入额外的参数(变量或对象); 35 | addNumCount: (state, n) => { 36 | state.count+=n; 37 | }, 38 | }, 39 | // 借助actions的手去 执行 mutations , 通过 this.$store.dispatch 的方式调用 40 | // 可以用来执行异步操作,可以跟踪异步数据状态变化 41 | actions: { 42 | // 调用 mutation 43 | addCount: context => { 44 | context.commit('addCount'); 45 | }, 46 | addNumCount: (context, n) => { 47 | context.commit('addNumCount', n); 48 | } 49 | } 50 | }) 51 | 52 | 我们在代码中分别注册了,state、getters、mutations、actions。 53 | 这样我们就可以在任何一个 component中通过this.store.dispatch(′addNumCount′,5);或者 this.$store.dispatch('addCount'); 去触发actions操作来改变state中的值。 -------------------------------------------------------------------------------- /moduletemplate/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | 14 | 24 | -------------------------------------------------------------------------------- /moduletemplate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | vue-multipage 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /moduletemplate/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vue from 'vue' 3 | import App from './App' 4 | import router from './router' 5 | import iView from 'iview'; 6 | import 'iview/dist/styles/iview.css'; 7 | import store from '../../vuex/store'; 8 | import { fetch, post } from '../../axios/http'; 9 | import Vuex from 'vuex'; 10 | 11 | Vue.use(Vuex) 12 | Vue.use(iView); 13 | 14 | Vue.config.productionTip = false 15 | 16 | Vue.prototype.$fetch = fetch 17 | Vue.prototype.$post = post 18 | Vue.prototype.$loading = function (show) { 19 | Vue.nextTick(function () { 20 | store.commit('FETCH_LOADING', show) 21 | }) 22 | } 23 | router.beforeEach((to, from, next) => { 24 | iView.LoadingBar.start(); 25 | next(); 26 | }); 27 | 28 | router.afterEach(route => { 29 | iView.LoadingBar.finish(); 30 | }); 31 | /* eslint-disable no-new */ 32 | new Vue({ 33 | el: '#app', 34 | router, 35 | render: h => h(App) 36 | //components: { App }, 37 | template: '' 38 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-multipage-platform-project", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "Titans,2396757591@qq.com", 6 | "private": true, 7 | "scripts": { 8 | "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js", 9 | "start": "npm run dev", 10 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", 11 | "e2e": "node test/e2e/runner.js", 12 | "test": "npm run unit && npm run e2e", 13 | "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs", 14 | "build": "node build/build.js", 15 | "build-all": "node build/build-all.js", 16 | "deploy": "node build/autodeploy.js" 17 | }, 18 | "dependencies": { 19 | "axios": "^1.6.0", 20 | "echarts": "^4.2.1", 21 | "echarts-gl": "^1.1.1", 22 | "iview": "^3.5.0", 23 | "v-viewer": "^1.4.2", 24 | "vue": "^2.6.10", 25 | "vue-croppa": "^1.3.8", 26 | "vue-i18n": "^8.14.0", 27 | "vue-router": "^3.1.2", 28 | "vue-scroll-behavior": "^0.2.0", 29 | "vue-video-player": "^6.0.0", 30 | "vuex": "^3.1.1" 31 | }, 32 | "devDependencies": { 33 | "autoprefixer": "^7.1.2", 34 | "babel-polyfill": "^6.26.0", 35 | "babel-core": "^6.22.1", 36 | "babel-eslint": "^8.2.1", 37 | "babel-helper-vue-jsx-merge-props": "^2.0.3", 38 | "babel-loader": "^7.1.1", 39 | "babel-plugin-istanbul": "^4.1.1", 40 | "babel-plugin-syntax-jsx": "^6.18.0", 41 | "babel-plugin-transform-runtime": "^6.22.0", 42 | "babel-plugin-transform-vue-jsx": "^3.5.0", 43 | "babel-preset-env": "^1.3.2", 44 | "babel-preset-stage-2": "^6.22.0", 45 | "babel-register": "^6.22.0", 46 | "chai": "^4.1.2", 47 | "chalk": "^2.0.1", 48 | "clean-webpack-plugin": "^3.0.0", 49 | "compression-webpack-plugin": "1.1.12", 50 | "copy-webpack-plugin": "^4.0.1", 51 | "cross-env": "^5.0.1", 52 | "cross-spawn": "^5.0.1", 53 | "css-loader": "^0.28.0", 54 | "eslint": "^4.15.0", 55 | "eslint-config-standard": "^10.2.1", 56 | "eslint-friendly-formatter": "^3.0.0", 57 | "eslint-loader": "^1.7.1", 58 | "eslint-plugin-import": "^2.7.0", 59 | "eslint-plugin-node": "^5.2.0", 60 | "eslint-plugin-promise": "^3.4.0", 61 | "eslint-plugin-standard": "^3.0.1", 62 | "eslint-plugin-vue": "^4.0.0", 63 | "extract-text-webpack-plugin": "^3.0.0", 64 | "file-loader": "^1.1.4", 65 | "friendly-errors-webpack-plugin": "^1.6.1", 66 | "html-webpack-plugin": "^5.5.3", 67 | "inject-loader": "^3.0.0", 68 | "karma": "^6.4.2", 69 | "karma-coverage": "^1.1.1", 70 | "karma-mocha": "^1.3.0", 71 | "karma-phantomjs-launcher": "^1.0.2", 72 | "karma-phantomjs-shim": "^1.4.0", 73 | "karma-sinon-chai": "^1.3.1", 74 | "karma-sourcemap-loader": "^0.3.7", 75 | "karma-spec-reporter": "0.0.31", 76 | "karma-webpack": "^2.0.2", 77 | "less-loader": "^5.0.0", 78 | "mocha": "^3.2.0", 79 | "nightwatch": "^0.9.12", 80 | "node-notifier": "^5.1.2", 81 | "node-sass": "^4.12.0", 82 | "optimize-css-assets-webpack-plugin": "^3.2.0", 83 | "ora": "^1.2.0", 84 | "phantomjs-prebuilt": "^2.1.14", 85 | "portfinder": "^1.0.13", 86 | "postcss-import": "^11.0.0", 87 | "postcss-loader": "^2.0.8", 88 | "postcss-url": "^7.2.1", 89 | "rimraf": "^2.6.0", 90 | "sass-loader": "7.3.1", 91 | "selenium-server": "^3.0.1", 92 | "semver": "^5.3.0", 93 | "shelljs": "^0.7.6", 94 | "sinon": "^4.0.0", 95 | "sinon-chai": "^2.8.0", 96 | "uglifyjs-webpack-plugin": "^1.1.1", 97 | "url-loader": "^0.5.8", 98 | "vue-loader": "^13.3.0", 99 | "vue-style-loader": "^3.0.1", 100 | "vue-template-compiler": "^2.6.10", 101 | "webpack": "^3.6.0", 102 | "webpack-bundle-analyzer": "^2.9.0", 103 | "webpack-dev-server": "^2.9.1", 104 | "webpack-merge": "^4.1.0" 105 | }, 106 | "engines": { 107 | "node": ">= 6.0.0", 108 | "npm": ">= 3.0.0" 109 | }, 110 | "browserslist": [ 111 | "> 1%", 112 | "last 2 versions", 113 | "not ie <= 8" 114 | ] 115 | } 116 | -------------------------------------------------------------------------------- /projectConfig/index.js: -------------------------------------------------------------------------------- 1 | const projectconfig = { 2 | framePage: "framePage", //defalt:framePage 框架页文件夹名称,这里需要指定, 3 | //原项目默认为src/framePage文件夹,此文件夹可根据自己需要自主更名,当更名后这里必须进行配置,值为当前文件夹名 4 | buildmodules: ["framePage","blogmodule",], 5 | isbuildassignmodules: false,//defalt:false,会执行命令行参数指定的几个单页面模块,命令行不传参数,默认构建项目中的所有包 6 | //当参数为真时,buildmodules值必须为数组,每个值为包名,打包只会构建buildmodules指定的包 7 | modulesconfig: { //key为单页面模块文件夹名称 8 | a: { 9 | plugin: [{ 10 | name: "axios", 11 | version: "^0.19.0" 12 | },{ 13 | name: "vuex", 14 | version: "^3.1.1" 15 | }, 16 | { 17 | name: "vue-router", 18 | version: "^3.1.2" 19 | }] 20 | }, 21 | b: { 22 | plugin: [{ 23 | name: "iview", 24 | version: "" 25 | }] 26 | } 27 | }, 28 | proxy:{//配置代理 29 | '/api': { 30 | target: 'http://www.abc.com', //目标接口域名 31 | changeOrigin: true, //是否跨域 32 | pathRewrite: { 33 | '^/api': '/api' //重写接口 34 | } 35 | } 36 | }, 37 | autoOpenBrowser: true,//是否自动打开浏览器 defalt:false 38 | useEslint:false, // 是否启用Eslint语法检查 defalt:false 39 | showEslintErrorsInOverlay:false, 40 | productionSourceMap:false,// 打包时是否建立映射 defalt:false 41 | productionGzip:false,//is gzip all static defalt:false 42 | 43 | } 44 | exports.framePage = projectconfig.framePage 45 | exports.modulesconfig = projectconfig.modulesconfig 46 | exports.buildmodules = projectconfig.buildmodules 47 | exports.isbuildassignmodules = projectconfig.isbuildassignmodules 48 | exports.proxy = projectconfig.proxy 49 | exports.autoOpenBrowser = projectconfig.autoOpenBrowser 50 | exports.useEslint = projectconfig.useEslint 51 | exports.showEslintErrorsInOverlay = projectconfig.showEslintErrorsInOverlay 52 | exports.productionSourceMap = projectconfig.productionSourceMap 53 | exports.productionGzip = projectconfig.productionGzip 54 | 55 | 56 | //项目默认已经安装dependencies,使用时只需要引入即可 57 | // "axios": "^0.19.0", 58 | // "echarts": "^4.2.1", 59 | // "iview": "^3.5.0-rc.1", 60 | // "v-viewer": "^1.4.2", 61 | // "vue": "^2.6.10", 62 | // "vue-croppa": "^1.3.8", 63 | // "vue-i18n": "^8.14.0", 64 | // "vue-router": "^3.1.2", 65 | // "vue-scroll-behavior": "^0.2.0", 66 | // "vue-video-player": "^5.0.2", 67 | // "vuex": "^3.1.1" 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/api/http.js: -------------------------------------------------------------------------------- 1 | // 本文件不允许私自修改,环保除引用第三方接口外一律使用post请求方式,接口定义请参考接口规范书写,这里只做全局http请求状态拦截,其他用户状态一律放行,页面内部做判断自行处理 2 | import axios from 'axios' 3 | import viewDesign from 'view-design' 4 | import { 5 | baseUrl 6 | } from './url' 7 | import Qs from 'qs' 8 | window.globalHttpUrl = { 9 | baseURL: baseUrl 10 | } 11 | axios.defaults.timeout = 60000 12 | axios.defaults.baseURL = baseUrl 13 | axios.defaults.headers.post['Content-Type'] = 'application/json' 14 | axios.defaults.headers.get['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8' 15 | const oldUrl = axios.defaults.baseURL 16 | // 请求拦截 17 | axios.interceptors.request.use(function (config) { 18 | viewDesign.LoadingBar.start() 19 | const token = sessionStorage.getItem('accessToken') || localStorage.getItem('accessToken') 20 | if (token) { 21 | config.headers.Authorization = token 22 | } 23 | return config 24 | }, function (error) { 25 | return Promise.reject(error.response) 26 | }) 27 | // axios.interceptors.request.onerror = function handleError() { 28 | // Promise.reject(createError('Network Error', axios.interceptors.request.config, null, axios.interceptors.request)) 29 | // } 30 | axios.interceptors.response.use(function (response) { 31 | viewDesign.LoadingBar.finish() 32 | if (response.status === 200) { 33 | switch (response.data.code) { 34 | case (401): 35 | console.log('Unauthorized,表示用户没有权限(令牌、用户名、密码错误)') 36 | break 37 | case (400): 38 | console.log('Invalid Request,用户发出的请求有错误') 39 | break 40 | case (403): 41 | console.log('Forbidden, 表示用户得到授权(与 401 错误相对),但是访问是被禁止的') 42 | break 43 | case (404): 44 | console.log('Not Found,用户发出的请求针对的是不存在的记录,服务器没有进行操作') 45 | break 46 | case (406): 47 | console.log('Not Acceptable, 用户请求的格式不可得(比如用户请求 JSON格式,但是只有XMLs格式)。') 48 | break 49 | case (422): 50 | console.log('Unprocesable entitz, 当创建一个对象时,发生一个验证错误') 51 | break 52 | case (500): 53 | console.log('Internal Server Error, 服务器发生错误,用户将无法判断发出的请求是否成功。') 54 | break 55 | default: 56 | break 57 | } 58 | } 59 | return response 60 | }, function (error) { 61 | // 对响应错误做处理 62 | return { 63 | data: { 64 | code: 0, 65 | errorInfor: error 66 | }, 67 | code: 0 68 | } 69 | }) 70 | export let Axios = axios 71 | // 封装axios的get请求 72 | export function get(url, params, Origin, openLoading) { 73 | axios.defaults.baseURL = oldUrl 74 | if (Origin) { 75 | axios.defaults.baseURL = Origin 76 | } 77 | return new Promise((resolve, reject) => { 78 | axios 79 | .get(url, { 80 | params: params, 81 | headers: { 82 | 'Access-Control-Allow-Origin': '*', 83 | 'Content-Type': 'application/json;charset=UTF-8' 84 | } 85 | }) 86 | .then(response => { 87 | // console.log('get', '\n', url, '\n', params, '\n', response) 88 | resolve(response.data) 89 | }) 90 | .catch(error => { 91 | reject(error) 92 | }) 93 | }) 94 | } 95 | 96 | // 封装axios的post请求 97 | export function post(url, data = {}, Origin, openLoading) { 98 | axios.defaults.baseURL = oldUrl 99 | if (Origin) { 100 | axios.defaults.baseURL = Origin 101 | } 102 | return new Promise((resolve, reject) => { 103 | axios 104 | .post(url, data) 105 | .then(response => { 106 | console.log('post', '\n', url, 'response', response, '\n', data, '\n', response) 107 | resolve(response.data) 108 | }) 109 | .catch(error => { 110 | reject(error) 111 | }) 112 | }) 113 | } 114 | 115 | // 封装axios的post请求-序列化 116 | export function postStringify(url, data = {}, 117 | Origin, openLoading) { 118 | axios.defaults.baseURL = oldUrl 119 | if (Origin) { 120 | axios.defaults.baseURL = Origin 121 | } 122 | return new Promise((resolve, reject) => { 123 | axios({ 124 | method: 'post', 125 | url: url, 126 | data: Qs.stringify(data) 127 | }) 128 | .then(response => { 129 | resolve(response.data) 130 | }) 131 | .catch(error => { 132 | reject(error) 133 | }) 134 | }) 135 | } 136 | 137 | // 封装axios的下载数据流转换成excel 138 | export function DownLoadToExcel(url, data = {}, fileName) { 139 | fileName = fileName + '.xls' 140 | return new Promise((resolve, reject) => { 141 | axios 142 | .post(url, data, { 143 | responseType: 'blob' 144 | }) 145 | .then(response => { 146 | const blob = new Blob([response.data], { 147 | type: 'application/vnd.ms-excel' 148 | }) 149 | if ('download' in document.createElement('a')) { 150 | // 非IE下载 151 | const elink = document.createElement('a') 152 | elink.download = fileName 153 | elink.style.display = 'none' 154 | elink.href = URL.createObjectURL(blob) 155 | document.body.appendChild(elink) 156 | elink.click() 157 | URL.revokeObjectURL(elink.href) 158 | document.body.removeChild(elink) 159 | } else { 160 | // IE10+下载 161 | navigator.msSaveBlob(blob, fileName) 162 | } 163 | resolve() 164 | }) 165 | .catch(error => { 166 | console.log(error) 167 | reject(error) 168 | }) 169 | }) 170 | } 171 | // 封装axios的下载数据流转换成excel 172 | export function DownLoadToFile (url, data = {}, fileName, Origin, openLoading) { 173 | axios.defaults.baseURL = oldUrl 174 | if (Origin) { 175 | axios.defaults.baseURL = Origin 176 | } 177 | fileName = fileName + '.xlsx' || 'download.xlsx' 178 | return new Promise((resolve, reject) => { 179 | axios 180 | .get(url, data, { 181 | 'responseType': 'blob', 182 | 'Access-Control-Allow-Origin': '*', 183 | 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8' 184 | }) 185 | .then(response => { 186 | const blob = new Blob([response.data], { 187 | type: 'application/octet-stream' 188 | }) 189 | let objectUrl = URL.createObjectURL(blob) 190 | if ('download' in document.createElement('a')) { 191 | let a = document.createElement('a') 192 | a.setAttribute('href', objectUrl) 193 | a.setAttribute('download', fileName) 194 | a.click() 195 | } else { 196 | // IE10+下载 197 | navigator.msSaveBlob(blob, fileName) 198 | } 199 | resolve(blob) 200 | }) 201 | .catch(error => { 202 | console.log(error) 203 | reject(error) 204 | }) 205 | }) 206 | } 207 | -------------------------------------------------------------------------------- /src/api/url.js: -------------------------------------------------------------------------------- 1 | export const baseUrl = '' // 服务端请求地址域 2 | export const sysUrl = '' // 服务端统一身份认证请求基地址 3 | export const fileUrl = '' // 服务端文件资源请求基地址 4 | export const prefixUrl ='' // 服务端请求地址前缀 5 | -------------------------------------------------------------------------------- /src/assets/css/style.css: -------------------------------------------------------------------------------- 1 | #app .deving, 2 | #app h2 { 3 | /*background: rgba(67, 99, 86, 0.15);*/ 4 | background: rgb(227, 227, 236); 5 | } 6 | 7 | #app h2 { 8 | text-align: center; 9 | padding: 50px; 10 | font-size: 30px; 11 | color: #815f88; 12 | background: transparent; 13 | } 14 | 15 | #app .deving-con { 16 | text-align: center; 17 | } 18 | 19 | #app .deving { 20 | display: inline-block; 21 | padding: 50px; 22 | margin: 0 auto; 23 | max-width: 1000px; 24 | text-align: center; 25 | min-width: calc(100% - 200px); 26 | 27 | } 28 | 29 | #app .deving h1 { 30 | background: transparent; 31 | font-size: 30px; 32 | color: #6a668b; 33 | } 34 | 35 | #app .deving h2 { 36 | margin: 50px 0 0 0; 37 | font-size: 30px; 38 | color: #c5e5d5; 39 | background: #606d72; 40 | } 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/common/css/font/reducto_condensed_ssi_condensed-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/css/font/reducto_condensed_ssi_condensed-webfont.eot -------------------------------------------------------------------------------- /src/common/css/font/reducto_condensed_ssi_condensed-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/css/font/reducto_condensed_ssi_condensed-webfont.ttf -------------------------------------------------------------------------------- /src/common/css/font/reducto_condensed_ssi_condensed-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/css/font/reducto_condensed_ssi_condensed-webfont.woff -------------------------------------------------------------------------------- /src/common/css/font/reducto_condensed_ssi_condensed-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/css/font/reducto_condensed_ssi_condensed-webfont.woff2 -------------------------------------------------------------------------------- /src/common/img/rwtx.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/img/rwtx.png -------------------------------------------------------------------------------- /src/common/js/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | const state = { 7 | loading: false, 8 | curlanguage: "Chinese", 9 | curtheme: "luxury", 10 | userInfo: { 11 | phone: 123456789000000, 12 | account: "Titans", 13 | theme: "luxury", 14 | language: "Chinese" 15 | }, //用户信息 16 | login: false, //是否登录 17 | themelist: { 18 | luxury: { 19 | wrapperbg: "#c7d0d6", 20 | navbg: "rgba(48,51,52,0.8)", 21 | navcolor: "#ddd", 22 | navaccolor: "#fff", 23 | containerbj: "#fff", 24 | containercolor: "#414a53", 25 | mainbg: "#fcfbfd", 26 | maincolor: "#71717f", 27 | }, 28 | vitality: { 29 | wrapperbg: "#c7d0d6", 30 | navbg: "rgba(48,51,52,0.8)", 31 | navcolor: "#ddd", 32 | navaccolor: "#fff", 33 | containerbj: "#fff", 34 | containercolor: "#414a53", 35 | mainbg: "#fcfbfd", 36 | mainbg: "#424561", 37 | }, 38 | youth: { 39 | wrapperbg: "#c7d0d6", 40 | navbg: "rgba(48,51,52,0.8)", 41 | navcolor: "#ddd", 42 | navaccolor: "#fff", 43 | containerbj: "#fff", 44 | containercolor: "#414a53", 45 | mainbg: "#fcfbfd", 46 | mainbg: "#424561", 47 | }, 48 | mature: { 49 | wrapperbg: "#c7d0d6", 50 | navbg: "rgba(48,51,52,0.8)", 51 | navcolor: "#ddd", 52 | navaccolor: "#fff", 53 | containerbj: "#fff", 54 | containercolor: "#414a53", 55 | mainbg: "#fcfbfd", 56 | mainbg: "#424561", 57 | } 58 | }, 59 | }; 60 | 61 | const getters = { //实时监听state值的变化(最新状态) 62 | isloading(state) { //承载变化的login的值. //this.$store.getters.isloading 63 | return state.loading 64 | }, 65 | islogin(state) { 66 | return state.login 67 | }, 68 | getuserInfo(state) { 69 | return state.userInfo 70 | }, 71 | getlanguage(state) { 72 | return state.curlanguage 73 | }, 74 | gettheme(state) { 75 | return state.curtheme 76 | }, 77 | getthemelist(state) { 78 | return state.themelist 79 | }, 80 | getcurtheme(state) { 81 | return state.curtheme 82 | } 83 | }; 84 | const mutations = { 85 | setloading(state, isshow) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象); 86 | state.loading = isshow; 87 | }, 88 | setlogin(state, islogin) { //this.$store.commit("setlogin", true) 89 | state.login = islogin; 90 | }, 91 | setuserInfo(state, userInfoobj) { 92 | state.userInfo = userInfoobj 93 | }, 94 | setcurtheme(state, curtheme) { 95 | state.curtheme = curtheme 96 | }, 97 | setlanguage(state, curlanguage) { 98 | state.curlanguage = curlanguage 99 | }, 100 | 101 | }; 102 | const actions = { 103 | asyncsetoading: (context, loadingstatus) => { //this.$store.dispatch("asyncsetoading", false) 104 | context.commit('setloading', loadingstatus); 105 | }, 106 | }; 107 | const modulea = { 108 | namespaced: true, 109 | state: { 110 | usera: "taitan", 111 | }, 112 | mutations: { 113 | setusera(state, name) { 114 | state.usera = name 115 | } 116 | }, 117 | actions: { 118 | asyncsetusera: (context, name) => { 119 | context.commit("setusera", name) 120 | } 121 | }, 122 | getters: { 123 | getusera(state) { 124 | return state.modulea.usera 125 | } 126 | 127 | } 128 | } 129 | export default new Vuex.Store({ 130 | state, 131 | getters, 132 | mutations, 133 | actions, 134 | modules: { 135 | modulea 136 | } 137 | }); 138 | -------------------------------------------------------------------------------- /src/common/js/viewport/viewport1366.js: -------------------------------------------------------------------------------- 1 | var scare=1; 2 | (function (doc, win) { 3 | var dpr = window.devicePixelRatio || 1; 4 | var docEl = doc.documentElement, 5 | resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize', 6 | recalc = function () { 7 | var clientWidth = docEl.clientWidth; 8 | if (!clientWidth) return; 9 | docEl.style.fontSize = 40 * (clientWidth / 1366) + 'px'; 10 | scare=Math.round(clientWidth / 1366); 11 | // 设置data-dpr属性,留作的css hack之用 12 | docEl.setAttribute('data-dpr', dpr); 13 | var delObj = document.getElementById("loading"); 14 | if(delObj){ 15 | $("#loading").remove(); 16 | } 17 | }; 18 | if (!doc.addEventListener) return; 19 | win.addEventListener(resizeEvt, recalc, false); 20 | doc.addEventListener('DOMContentLoaded', recalc, false); 21 | })(document, window); 22 | -------------------------------------------------------------------------------- /src/common/video/test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/src/common/video/test.mp4 -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 9 | 20 | 21 | 23 | -------------------------------------------------------------------------------- /src/components/Pagenation.vue: -------------------------------------------------------------------------------- 1 | 2 | 49 | 275 | 415 | 433 | -------------------------------------------------------------------------------- /src/framePage/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 17 | 18 | 21 | -------------------------------------------------------------------------------- /src/framePage/components/account.vue: -------------------------------------------------------------------------------- 1 | 20 | 200 | 287 | -------------------------------------------------------------------------------- /src/framePage/components/index.vue: -------------------------------------------------------------------------------- 1 | 64 | 337 | 569 | -------------------------------------------------------------------------------- /src/framePage/components/login.vue: -------------------------------------------------------------------------------- 1 | 5 | 39 | 42 | -------------------------------------------------------------------------------- /src/framePage/components/theme.vue: -------------------------------------------------------------------------------- 1 | 5 | 39 | 42 | -------------------------------------------------------------------------------- /src/framePage/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 泰坦社区 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/framePage/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Titans on 2019/9/10. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | import Router from 'vue-router' 8 | import store from '@/common/js/store.js' 9 | Vue.config.productionTip = false 10 | import '@/common/css/common.css' 11 | import '@/common/js/viewport/viewport1366.js' 12 | 13 | import initUtil from '@/common/js/util.js' 14 | //console.log(initUtil) 15 | const routerPush = Router.prototype.push 16 | Router.prototype.push = function push(location) { 17 | return routerPush.call(this, location).catch(error => error) 18 | } 19 | Vue.prototype.$initUtil = initUtil 20 | window.framePage = new Vue({ 21 | el: '#app', 22 | store, 23 | router, 24 | render: h => h(App) 25 | }) 26 | console.log("Vue.$initUtil:", window.framePage.$initUtil) 27 | -------------------------------------------------------------------------------- /src/framePage/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import index from '../components/index' 4 | 5 | Vue.use(Router) 6 | 7 | const routerPush = Router.prototype.push 8 | Router.prototype.push = function push(location) { 9 | return routerPush.call(this, location).catch(error => error) 10 | } 11 | const createRouter = routes => new VueRouter({ 12 | routes 13 | }) 14 | 15 | // 在使用addRoutes的地方 16 | // 重置当前router的match = 初始router.match 17 | 18 | Router.prototype.resetRouter = function resetRouter(routerData) { 19 | this.matcher = createRouter(routerData).matcher 20 | this.options.routes = routerData 21 | } 22 | // import HelloWorld from '@/components/HelloWorld' 23 | // const HelloWorld = () => import('../components/HelloWorld') 24 | //resolve => require(['../components/HelloWorld'], resolve) 25 | //const Home = r => require.ensure([], () => r(require('@/components/Home')), 'Home'); 26 | export default new Router({ 27 | //mode:"history", 28 | routes: [{ 29 | path: '/', 30 | name: 'index', 31 | component: index 32 | }] 33 | }) 34 | -------------------------------------------------------------------------------- /src/modules/bbsmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/bbsmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/bbsmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 模块b 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/bbsmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | /* eslint-disable no-new */ 13 | window.bbsmodule=new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | -------------------------------------------------------------------------------- /src/modules/bbsmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/blogmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/blogmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/blogmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 博客(blog) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/blogmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | 14 | /* eslint-disable no-new */ 15 | window.blogmodule=new Vue({ 16 | el: '#app', 17 | router, 18 | render: h => h(App) 19 | }) 20 | -------------------------------------------------------------------------------- /src/modules/blogmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/clubmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/clubmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/clubmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 社区(club) 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/clubmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | /* eslint-disable no-new */ 13 | window.clubmodule=new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | -------------------------------------------------------------------------------- /src/modules/clubmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/coursemodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/coursemodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/coursemodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 网课(course) 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/coursemodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | /* eslint-disable no-new */ 13 | window.coursemodule=new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | -------------------------------------------------------------------------------- /src/modules/coursemodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/homemodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /src/modules/homemodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/homemodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 首页(home) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/homemodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | 14 | /* eslint-disable no-new */ 15 | window.homemodule=new Vue({ 16 | el: '#app', 17 | router, 18 | render: h => h(App) 19 | }) 20 | -------------------------------------------------------------------------------- /src/modules/homemodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/musicmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /src/modules/musicmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/musicmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 音乐(music) 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/musicmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | /* eslint-disable no-new */ 13 | window.musicmodule=new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | -------------------------------------------------------------------------------- /src/modules/musicmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/productmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/productmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/productmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 产品(product) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/productmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | 14 | /* eslint-disable no-new */ 15 | window.productmodule=new Vue({ 16 | el: '#app', 17 | router, 18 | render: h => h(App) 19 | }) 20 | -------------------------------------------------------------------------------- /src/modules/productmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/socialmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /src/modules/socialmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/socialmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 社交(social) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/socialmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | /* eslint-disable no-new */ 14 | window.socialmodule=new Vue({ 15 | el: '#app', 16 | router, 17 | render: h => h(App) 18 | }) 19 | -------------------------------------------------------------------------------- /src/modules/socialmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/storemodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /src/modules/storemodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/storemodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 店铺(store) 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/storemodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | /* eslint-disable no-new */ 13 | window.storemodule=new Vue({ 14 | el: '#app', 15 | router, 16 | render: h => h(App) 17 | }) 18 | -------------------------------------------------------------------------------- /src/modules/storemodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/supportmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/supportmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/supportmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 支持(support) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/supportmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | /* eslint-disable no-new */ 14 | window.supportmodule=new Vue({ 15 | el: '#app', 16 | router, 17 | render: h => h(App) 18 | }) 19 | -------------------------------------------------------------------------------- /src/modules/supportmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/modules/textmodule/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /src/modules/textmodule/components/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 22 | -------------------------------------------------------------------------------- /src/modules/textmodule/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 文字(text) 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/modules/textmodule/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Created by Administrator on 2018/4/22. 3 | */ 4 | import Vue from 'vue' 5 | import App from './App' 6 | import router from './router' 7 | 8 | Vue.config.productionTip = false 9 | import '@/common/css/common.css' 10 | import '@/assets/css/style.css' 11 | 12 | 13 | 14 | /* eslint-disable no-new */ 15 | window.textmodule=new Vue({ 16 | el: '#app', 17 | router, 18 | render: h => h(App) 19 | }) 20 | -------------------------------------------------------------------------------- /src/modules/textmodule/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Index from '../components/index' 4 | 5 | import HelloWorld from '*/HelloWorld.vue' 6 | Vue.use(Router) 7 | 8 | export default new Router({ 9 | routes: [ 10 | { 11 | path: '', 12 | redirect: '/index' 13 | }, 14 | { 15 | path: '/index', 16 | name: 'index', 17 | component: Index 18 | } 19 | ] 20 | }) -------------------------------------------------------------------------------- /src/util/mixins/clickOutside.js: -------------------------------------------------------------------------------- 1 | function validate(binding) { 2 | if (typeof binding.value !== 'function') { 3 | console.warn('[Vue-click-outside:] provided expression', binding.expression, 'is not a function.') 4 | return false 5 | } 6 | return true 7 | } 8 | 9 | function isPopup(popupItem, elements) { 10 | if (!popupItem || !elements) { 11 | return false 12 | } 13 | for (var i = 0, len = elements.length; i < len; i++) { 14 | try { 15 | if (popupItem.contains(elements[i]) && !event.stopPropagation()) { 16 | return true 17 | } 18 | if (elements[i].contains(popupItem)) { 19 | return false 20 | } 21 | } catch (e) { 22 | return false 23 | } 24 | } 25 | return false 26 | } 27 | 28 | function isServer(vNode) { 29 | return typeof vNode.componentInstance !== 'undefined' && vNode.componentInstance.$isServer 30 | } 31 | exports = module.exports = { 32 | bind: function (el, binding, vNode) { 33 | if (!validate(binding)) return 34 | // Define Handler and cache it on the element 35 | function handler(e) { 36 | if (!vNode.context) return 37 | // some components may have related popup item, on which we shall prevent the click outside event handler. 38 | var elements = e.path || (e.composedPath && e.composedPath()) 39 | elements && elements.length > 0 && elements.unshift(e.target) 40 | 41 | if ((el.contains(e.target) || isPopup(vNode.context.popupItem, elements)) && !event.stopPropagation()) return 42 | el.__vueClickOutside__.callback(e) 43 | } 44 | // add Event Listeners 45 | el.__vueClickOutside__ = { 46 | handler: handler, 47 | callback: binding.value 48 | } 49 | !isServer(vNode) && document.addEventListener('click', handler) 50 | }, 51 | 52 | update: function (el, binding) { 53 | if (validate(binding)) el.__vueClickOutside__.callback = binding.value 54 | }, 55 | unbind: function (el, binding, vNode) { 56 | // Remove Event Listeners 57 | !isServer(vNode) && document.removeEventListener('click', el.__vueClickOutside__.handler) 58 | delete el.__vueClickOutside__ 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/util/mixins/emitter.js: -------------------------------------------------------------------------------- 1 | function broadcast(componentName, eventName, params) { 2 | this.$children.forEach(child => { 3 | const name = child.$options.name 4 | if (name === componentName) { 5 | child.$emit.apply(child, [eventName].concat(params)) 6 | } else { 7 | // todo 如果 params 是空数组,接收到的会是 undefined 8 | broadcast.apply(child, [componentName, eventName].concat([params])) 9 | } 10 | }) 11 | } 12 | export default { 13 | methods: { 14 | dispatch(componentName, eventName, params) { 15 | let parent = this.$parent || this.$root 16 | let name = parent.$options.name 17 | while (parent && (!name || name !== componentName)) { 18 | parent = parent.$parent 19 | if (parent) { 20 | name = parent.$options.name 21 | } 22 | } 23 | if (parent) { 24 | parent.$emit.apply(parent, [eventName].concat(params)) 25 | } 26 | }, 27 | broadcast(componentName, eventName, params) { 28 | broadcast.call(this, componentName, eventName, params) 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/util/mixins/locale.js: -------------------------------------------------------------------------------- 1 | import { t } from '../local/index' 2 | 3 | export default { 4 | methods: { 5 | t(...args) { 6 | return t.apply(this, args) 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/util/secret.js: -------------------------------------------------------------------------------- 1 | import { 2 | KEY, 3 | IV 4 | } from '@/config/config' 5 | import CryptoJS from 'crypto-js' // 引用AES源码js 6 | const key = CryptoJS.enc.Utf8.parse(KEY) // 十六位十六进制数作为秘钥 7 | const iv = CryptoJS.enc.Utf8.parse(IV) // 十六位十六进制数作为秘钥偏移量 8 | // 加密方法不可逆 9 | function EncryptIrreversible(word) { 10 | let key = CryptoJS.enc.Utf8.parse(KEY) 11 | let srcs = CryptoJS.enc.Utf8.parse(word) 12 | let encrypted = CryptoJS.AES.encrypt(srcs, key, { 13 | iv: CryptoJS.enc.Utf8.parse(IV), 14 | mode: CryptoJS.mode.ECB, 15 | padding: CryptoJS.pad.Pkcs7 16 | }) 17 | return encrypted.toString().toUpperCase() 18 | } 19 | // 解密方法 20 | function Decrypt(word, keys, ivs) { 21 | keys = keys || key 22 | ivs = ivs || iv 23 | let encryptedHexStr = CryptoJS.enc.Hex.parse(word) 24 | let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr) 25 | let decrypt = CryptoJS.AES.decrypt(srcs, keys, { 26 | iv: ivs, 27 | mode: CryptoJS.mode.CBC, 28 | padding: CryptoJS.pad.Pkcs7 29 | }) 30 | let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8) 31 | return decryptedStr.toString() 32 | } 33 | // 加密方法 34 | function Encrypt(word, keys, ivs) { 35 | keys = keys || key 36 | ivs = ivs || iv 37 | let srcs = CryptoJS.enc.Utf8.parse(word) 38 | let encrypted = CryptoJS.AES.encrypt(srcs, keys, { 39 | iv: iv, 40 | mode: CryptoJS.mode.CBC, 41 | padding: CryptoJS.pad.Pkcs7 42 | }) 43 | return encrypted.ciphertext.toString().toUpperCase() 44 | } 45 | // MD5加密方法 46 | function MD5(words) { 47 | return CryptoJS.MD5(words).toString() 48 | } 49 | export default { 50 | Decrypt, 51 | Encrypt, 52 | EncryptIrreversible, 53 | MD5 54 | } 55 | -------------------------------------------------------------------------------- /src/util/tools.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-sparse-arrays */ 2 | /** 3 | * @description 存储sessionStorage 4 | * @param {存储的keyName} name 5 | * @param {存储的值} value 6 | */ 7 | export const setStore = (name, value) => { 8 | if (!name) { 9 | return false 10 | } 11 | window.sessionStorage.setItem(name, typeof value !== 'string' ? JSON.stringify(value) : value) 12 | } 13 | 14 | /** 15 | * @description 读取sessionStorage 16 | * @param {存储的keyName} name 17 | */ 18 | export const getStore = (name) => { 19 | if (!name) { 20 | return false 21 | } 22 | return window.sessionStorage.getItem(name) 23 | } 24 | 25 | /** 26 | * @description 删除sessionStorage 27 | * @param {需要删除的keyName} name 28 | */ 29 | export const removeStroe = (name) => { 30 | if (!name) { 31 | return false 32 | } 33 | window.sessionStorage.removeItem(name) 34 | } 35 | 36 | /** 37 | * @description 存储localstorage 38 | * @param {存储的keyName} name 39 | * @param {存储的值} value 40 | */ 41 | export const setLocal = (name, value) => { 42 | if (!name) { 43 | return false 44 | } 45 | window.localStorage.setItem(name, typeof value !== 'string' ? JSON.stringify(value) : value) 46 | } 47 | 48 | /** 49 | * @description 读取localstorage 50 | * @param {存储的keyName} name 51 | */ 52 | export const getLocal = (name) => { 53 | if (!name) { 54 | return false 55 | } 56 | return window.localStorage.getItem(name) 57 | } 58 | 59 | /** 60 | * @description 删除localstorage 61 | * @param {需要删除的keyName} name 62 | */ 63 | export const removeLocal = (name) => { 64 | if (!name) { 65 | return false 66 | } 67 | window.localStorage.removeItem(name) 68 | } 69 | 70 | /** 71 | * @description 按日处理时间为xxxx-yy-dd 72 | * @param {需要处理的时间} time:object 73 | */ 74 | export const timeProcessDay = (time) => { 75 | if (!time) { 76 | return '' 77 | } 78 | let d = new Date(time) 79 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? ('-' + (d.getMonth() + 1)) : ('-0' + (d.getMonth() + 1))) + '-' + (d.getDate() >= 10 ? d.getDate() : '0' + d.getDate()) 80 | } 81 | /** 82 | * @description 按月处理时间为xxxx-yy 83 | * @param {需要处理的时间} time:object 84 | */ 85 | export const timeProcessMonth = (time) => { 86 | let d = new Date(time) 87 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? ('-' + (d.getMonth() + 1)) : ('-0' + (d.getMonth() + 1))) 88 | } 89 | /** 90 | * @description 按月处理时间为yyyyMM 91 | * @param {需要处理的时间} time:object 92 | */ 93 | export const timeProcessMonth1 = (time) => { 94 | let d = new Date(time) 95 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? (d.getMonth() + 1) : ('0' + (d.getMonth() + 1))) 96 | } 97 | export const getUrlKey = function (name) { 98 | return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ''])[1].replace(/\+/g, '%20')) || null 99 | } 100 | -------------------------------------------------------------------------------- /src/util/utils/secret.js: -------------------------------------------------------------------------------- 1 | import { 2 | KEY, 3 | IV 4 | } from '@/config/config' 5 | import CryptoJS from 'crypto-js' // 引用AES源码js 6 | const key = CryptoJS.enc.Utf8.parse(KEY) // 十六位十六进制数作为秘钥 7 | const iv = CryptoJS.enc.Utf8.parse(IV) // 十六位十六进制数作为秘钥偏移量 8 | // 加密方法不可逆 9 | function EncryptIrreversible(word) { 10 | let key = CryptoJS.enc.Utf8.parse(KEY) 11 | let srcs = CryptoJS.enc.Utf8.parse(word) 12 | let encrypted = CryptoJS.AES.encrypt(srcs, key, { 13 | iv: CryptoJS.enc.Utf8.parse(IV), 14 | mode: CryptoJS.mode.ECB, 15 | padding: CryptoJS.pad.Pkcs7 16 | }) 17 | return encrypted.toString().toUpperCase() 18 | } 19 | // 解密方法 20 | function Decrypt(word, keys, ivs) { 21 | keys = keys || key 22 | ivs = ivs || iv 23 | let encryptedHexStr = CryptoJS.enc.Hex.parse(word) 24 | let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr) 25 | let decrypt = CryptoJS.AES.decrypt(srcs, keys, { 26 | iv: ivs, 27 | mode: CryptoJS.mode.CBC, 28 | padding: CryptoJS.pad.Pkcs7 29 | }) 30 | let decryptedStr = decrypt.toString(CryptoJS.enc.Utf8) 31 | return decryptedStr.toString() 32 | } 33 | // 加密方法 34 | function Encrypt(word, keys, ivs) { 35 | keys = keys || key 36 | ivs = ivs || iv 37 | let srcs = CryptoJS.enc.Utf8.parse(word) 38 | let encrypted = CryptoJS.AES.encrypt(srcs, keys, { 39 | iv: iv, 40 | mode: CryptoJS.mode.CBC, 41 | padding: CryptoJS.pad.Pkcs7 42 | }) 43 | return encrypted.ciphertext.toString().toUpperCase() 44 | } 45 | // MD5加密方法 46 | function MD5(words) { 47 | return CryptoJS.MD5(words).toString() 48 | } 49 | export default { 50 | Decrypt, 51 | Encrypt, 52 | EncryptIrreversible, 53 | MD5 54 | } 55 | -------------------------------------------------------------------------------- /src/util/utils/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * tool 3 | */ 4 | 5 | // import Vue from 'vue'; 6 | // import axios from "axios"; 7 | /** 8 | * @description 存储sessionStorage 9 | * @param {存储的keyName} name 10 | * @param {存储的值} value 11 | */ 12 | export const setStore = (name, value) => { 13 | if (!name) return; 14 | if (typeof value !== 'string') { 15 | value = JSON.stringify(value) 16 | } 17 | window.sessionStorage.setItem(name, value) 18 | } 19 | 20 | /** 21 | * @description 读取localstorage 22 | * @param {存储的keyName} name 23 | */ 24 | export const getStore = (name) => { 25 | if (!name) return; 26 | return window.sessionStorage.getItem(name) 27 | } 28 | 29 | /** 30 | * @description 删除localstorage 31 | * @param {需要删除的keyName} name 32 | */ 33 | export const removeStroe = (name) => { 34 | if (!name) return; 35 | window.sessionStorage.removeItem(name) 36 | } 37 | 38 | 39 | 40 | /** 41 | * @description 按日处理时间为xxxx-yy-dd 42 | * @param {需要处理的时间} time:object 43 | */ 44 | export const timeProcessDay = (time) => { 45 | if(!time){return ""} 46 | let d = new Date(time); 47 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? ('-' + (d.getMonth() + 1)) : ('-0' + (d.getMonth() + 1))) + "-" + (d.getDate() >= 10 ? d.getDate() : '0' + d.getDate()); 48 | 49 | } 50 | /** 51 | * @description 按月处理时间为xxxx-yy 52 | * @param {需要处理的时间} time:object 53 | */ 54 | export const timeProcessMonth = (time) => { 55 | let d = new Date(time); 56 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? ('-' + (d.getMonth() + 1)) : ('-0' + (d.getMonth() + 1))); 57 | 58 | } 59 | /** 60 | * @description 按月处理时间为yyyyMM 61 | * @param {需要处理的时间} time:object 62 | */ 63 | export const timeProcessMonth1 = (time) => { 64 | let d = new Date(time); 65 | return d.getFullYear() + ((d.getMonth() + 1) >= 10 ? (d.getMonth() + 1) : ('0' + (d.getMonth() + 1))); 66 | 67 | } 68 | export const getUrlKey = function (name) { 69 | return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ""])[1].replace(/\+/g, '%20')) || null; 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/util/utils/valid.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 校验 3 | */ 4 | 5 | import Vue from 'vue' 6 | import Validator from 'vue-validator' 7 | 8 | Vue.use(Validator) 9 | 10 | const validataconfig = { 11 | isEmpty: function(str) { /*是否为空*/ 12 | return !/0+/.test(str) && !str; 13 | }, 14 | isNumber: function(str) { /*是否为数字*/ 15 | return /^[0-9]*$/.test(str); 16 | }, 17 | isZipCode: function(str) { /*是否为邮编*/ 18 | return /^[0-9]{6}$/.test(str); 19 | }, 20 | isIdCardNo: function(str) { /*是否为身份证好*/ 21 | // return /^(\d{6})()?(\d{4})(\d{2})(\d{2})(\d{3})(\w)$/.test(str); 22 | return /^(^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$)|(^[1-9]\d{5}\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{2}$)$/.test( 23 | str) 24 | }, 25 | isMobile: function(str) { /*是否为手机号码*/ 26 | return str.length == 11 && /^1[3|4|5|8|7][0-9]\d{4,8}$/.test(str); 27 | }, 28 | isQQ: function(str) { /*是否为QQ号码*/ 29 | return /^\s*[.0-9]{5,11}\s*$/.test(str); 30 | }, 31 | isEmail: function(str) { /*是否为邮箱*/ 32 | return /\w@\w*\.\w/.test(str); 33 | }, 34 | isBackId: (value) => { /*银行卡号合法16-19位*/ 35 | return /^([1-9]{1})(\d{15}|\d{18})$/.test(value) 36 | }, 37 | isUrl: function(str) { /*是否为网页url*/ 38 | return /(https?|ftp|mms):\/\/([A-z0-9]+[_\-]?[A-z0-9]+\.)*[A-z0-9]+\-?[A-z0-9](\/.*)*\/?/.test(str); 39 | }, 40 | isPhone: function(str) { /*是否为固定电话*/ 41 | return /^(0[0-9]{2,3}-?)?([2-9][0-9]{6,7})+(-?[0-9]{1,4})?$/.test(str); 42 | }, 43 | isTel: function(str) { /*是否为手机号码或固定电话*/ 44 | var _length = str.length, 45 | _mobile = /^(((13[0-9]{1})|(15[0-9]{1})|(18[0-9]{1})|(17[0-9]{1}))+\d{8})$/, 46 | _tel = /^(0[0-9]{2,3}-?)?([2-9][0-9]{6,7})+(-?[0-9]{1,4})?$/; 47 | return (_tel.test(str) && _length <= 12) || (_mobile.test(str) && _length == 11); 48 | }, 49 | isIp: function(str) { /*是否为ip地址*/ 50 | return /^(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.)(([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))\.){2}([1-9]|([1-9]\d)|(1\d\d)|(2([0-4]\d|5[0-5])))$/.test(str); 51 | }, 52 | cnLength: function(str, params) { /*验证字符串长度是否在params([smax,smin])范围内*/ 53 | var _length = str.length, 54 | _totalLen = _length, 55 | smin = 0, 56 | smax = 0; 57 | if (params instanceof Array) { 58 | switch (params.length) { 59 | case 0: 60 | return false; 61 | break; 62 | case 1: 63 | smax = parseInt(params[0]); 64 | if (smax == 0 || isNaN(smax)) { 65 | return false; 66 | } 67 | break; 68 | default: 69 | smin = parseInt(params[0]); 70 | smax = parseInt(params[1]); 71 | if (smax == 0 || isNaN(smax) || isNaN(smin)) { 72 | return false; 73 | } 74 | } 75 | } else { 76 | return false; 77 | } 78 | for (var i = 0; i < _length; i++) { 79 | if (str.charCodeAt(i) > 127) { 80 | _totalLen += 2; 81 | } 82 | } 83 | return _totalLen >= smin && _totalLen <= smax; 84 | }, 85 | chineseMax: function(str, params) { /*验证字符串长度是否在0-params范围内*/ 86 | var _length = str.length, 87 | smin = 0; 88 | var smax = parseInt(params); 89 | return _length >= smin && _length <= smax;; 90 | }, 91 | charMin: function(str, params) { /*验证字符串的长度是否大于params*/ 92 | return str.length >= parseInt(params); 93 | }, 94 | cnMax: function(str, params) { /*验证字符数字是否小于params*/ 95 | return Number(str) <= Number(params); 96 | }, 97 | cnMin: function(str, params) { /*验证字符数字是否大于params*/ 98 | return Number(str) > Number(params); 99 | }, 100 | userName: function(str) { /*只允许输入中英文字符,数字和下划线*/ 101 | return /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/.test(str); 102 | }, 103 | userNameExtend: function(str) { /*只允许输入中英文字符,数字和下划线,括号 以及 ·.、*/ 104 | return /^[a-zA-Z0-9_\(\)\{\}·.、\[\]\(\)\【\】\u4e00-\u9fa5]+$/.test(str); 105 | }, 106 | chrnum: function(str) { /*字母和数字的验证*/ 107 | return /^([a-zA-Z0-9]+)$/.test(str); 108 | }, 109 | decimal2: function(str) { /*是否为两位小数*/ 110 | return /^-?\d+\.?\d{0,2}$/.test(str); 111 | }, 112 | decimal_num: function(str) { /*是否为数字和小数*/ 113 | return /(^d*.?d*[0-9]+d*$)|(^[0-9]+d*.d*$)/.test(str); 114 | }, 115 | chinese: function(str) { /*是否为中文*/ 116 | return /^[\u4e00-\u9fa5]+$/.test(str); 117 | }, 118 | userPassword: function(str) { /*密码的验证a-zA-Z0-9 5-17位*/ 119 | return /^[a-zA-Z]\w{5,17}$/.test(str); 120 | }, 121 | isDefaultPassword: function(str, params) { /*是否默认密码params(["123456",'111111','111222'])*/ 122 | var isd = false; 123 | for (var strp in params) { 124 | if (str.toString() == params[strp]) { 125 | isd = true; 126 | } 127 | } 128 | return isd; 129 | }, 130 | isSimplePassword: function(str) { /*是否简单密码*/ 131 | function isASC(test) { 132 | for (var i = 1; i < test.length; i++) { 133 | if (test.charCodeAt(i) != (test.charCodeAt(i - 1) + 1)) { 134 | return false; 135 | } 136 | } 137 | return true; 138 | } 139 | 140 | function isDESC(test) { 141 | for (var i = 1; i < test.length; i++) { 142 | if (test.charCodeAt(i) != (test.charCodeAt(i - 1) - 1)) { 143 | return false; 144 | } 145 | } 146 | return true; 147 | } 148 | 149 | function isSame(test) { 150 | for (var i = 1; i < test.length; i++) { 151 | if (test.charCodeAt(i) != (test.charCodeAt(i - 1))) { 152 | return false; 153 | } 154 | } 155 | return true; 156 | } 157 | return !(isASC(str) || isDESC(str) || isSame(str)); 158 | }, 159 | identifier: function(str) { /*是否是编号*/ 160 | return /^[a-zA-Z0-9_\u4e00-\u9fa5\-]+$/.test(str); 161 | }, 162 | isPic: function(str) { /*是否是图片*/ 163 | return /.jpg|.png|.gif|.jpeg$/.test(str.toLowerCase()); 164 | }, 165 | isInteger: function(str) { /*是否是正整数*/ 166 | return /^[1-9]+[0-9]*$/.test(str); 167 | }, 168 | isPInt: function(str) { /*校验正整数*/ 169 | return /^[0-9]*[0-9][0-9]*$/.test(str); 170 | }, 171 | onlyEn_Num: function(str) { /*只允许输入英文字符,数字和下划线*/ 172 | return /^\w+$/.test(str); 173 | }, 174 | onlyCn_En_Num: function(str) { /*只允许输入中英文字符,数字和下划线*/ 175 | return /^[a-zA-Z0-9_\u4e00-\u9fa5]+$/.test(str); 176 | }, 177 | onlyCn_En_Num_Point: function(str) { /*只能包括中英文字母、数字、下划线和中文标点符号*/ 178 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,。“”;!?@、]+$/.test(str); 179 | }, 180 | onlyCn_En_Num_Point_zhong_ying: function(str) { /*只能包括中英文字母、数字、下划线和中英文标点符号*/ 181 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,。“”;!?@、,.?!"";]+$/.test(str); 182 | }, 183 | onlyCn_En_Num_Point_extend: function(str) { /*只能包括中英文字母、数字、下划线和中文标点符号及部分特殊符号*/ 184 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,。“”;!:?@、\(\)\{\}·.:\[\]\(\)\【\】]+$/.test(str); 185 | }, 186 | onlyCn_En_Num_Point_return: function(str) { /*只能包括中英文字母、数字、下划线和中英文标点符号、空格、回车、括号类符号*/ 187 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,,。.“”;"";:·:!!??@、.\(\)\(\)\[\]\{\}\【\】\n\s]+$/.test(str); 188 | }, 189 | onlyCn_En_Num_bufen_return: function(str) { /*只能包括中英文字母、数字、下划线、横杠和中英文标点符号、空格、回车、括号类符号*/ 190 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,,。.“”;‘’''"";::!!??@、.<>\-《》\(\)\(\)\[\]\{\}\【\】\n\s]+$/.test(str); 191 | }, 192 | onlyCn_En_Num_Point_all_extend: function(str) { /*只能包括中英文字母、数字、下划线、中文标点符号、空格和回车及部分特殊符号*/ 193 | return /^[a-zA-Z0-9_\u4e00-\u9fa5,。“”;:!?@、\(\)\{\}·.\[\]\(\)\【\】\n\s]+$/.test(str); 194 | }, 195 | onlyNum_Point: function(str) { /*只能是数字、小数点后两位*/ 196 | return /^(\d)*(\.(\d){1,2})?$/.test(str); 197 | }, 198 | onlyNum_Point3: function(str) { /*只能是数字、小数点后两位*/ 199 | return /^(\d)*(\.(\d){0,3})?$/.test(str); 200 | }, 201 | doubles7: function(str) { /*是否小于9999999*/ 202 | var par = parseInt(str) 203 | return par <= 9999999; 204 | }, 205 | doubles5: function(str) { /*是否小于999*/ 206 | var par = parseInt(str) 207 | return par <= 999; 208 | }, 209 | onlyNum_Point4: function(str) { /*是否数字、小数点后四位*/ 210 | return /^(\d)*(\.(\d){0,4})?$/.test(str); 211 | }, 212 | 213 | onlyNum_Point7: function(str) { /*是否数字、小数点后七位*/ 214 | return /^(\d)*(\.(\d){0,7})?$/.test(str); 215 | }, 216 | socode: function(str) { /*是否统一社会信用代码*/ 217 | return /^[0-9A-Z]+$/.test(str); 218 | }, 219 | onlycar_number_Eng: function(str) { /*是否为车牌号*/ 220 | return /(^[\u4E00-\u9FA5]{1}[A-Z0-9]{6}$)|(^[A-Z]{2}[A-Z0-9]{2}[A-Z0-9\u4E00-\u9FA5]{1}[A-Z0-9]{4}$)|(^[\u4E00-\u9FA5]{1}[A-Z0-9]{5}[挂学警军港澳]{1}$)|(^[A-Z]{2}[0-9]{5}$)|(^(08|38){1}[A-Z0-9]{4}[A-Z0-9挂学警军港澳]{1}$)|(^[A-Z]{2}[\u4E00-\u9FA5]{1}[A-Z0-9]{4}[A-Z0-9挂学警军港澳]{1}$)/.test(str); 221 | }, 222 | onlyChNun_Eng: function(str) { /*是否为英文字母、数字和中文*/ 223 | //return /^[\u4e00-\u9fa5]{1}[A-Z]{1}[A-Z_0-9]{5}$/.test(str); 224 | return /^(([\u4e00-\u9fa5]|[a-zA-Z0-9])+)$/.test(str); 225 | }, 226 | specialChar: function(str) { /*排除特殊字符验证 (可以输入加号|斜杠|顿号|括号 中英文)*/ 227 | return new RegExp( 228 | "[`~!@#$^&*=|':;',.<>?~!@#¥……&*‘;:”“'。,?%———— ]" 229 | ).test(str) 230 | }, 231 | isChineseCharacters: function(value) { /*排除特殊字符验证*/ 232 | return new RegExp( 233 | "[`~!@#$^&*()=|{}':;',\\[\\].<>/?~!@#¥……&*()|{}【】‘;:”“'。,、?%+———— ]" 234 | ).test(value) 235 | }, 236 | postSal5: function(value) { /*工资只能为5位数以内*/ 237 | return value !== "" && value !== null && value !== undefined && !/^(0|[1-9]\d{0,4})$/.test(value) 238 | }, 239 | nonnegativeInteger: function(value) { /*1~4)位非负整数验证*/ 240 | return /^\d{1,4}$/.test(value) 241 | }, 242 | isNumber5: function(value) { /*5位数字验证*/ 243 | return value !== "" && value !== null && value !== undefined && !/^\d{5}$/.test(value) 244 | }, 245 | Number0To100: function(value) { /*(0~100)的数字*/ 246 | return /^100$|^(\d|[1-9]\d)(\.\d{1,2})*$/.test(value) 247 | }, 248 | Numberint0To100: function(value) { /*(0~100)的整数*/ 249 | return value !== "" && value !== null && value !== undefined && !/^([1-4][0-9]{2}|100|[1-9]?[0-9])$/.test(value) 250 | }, 251 | isNumber8: function(value) { /*数字0~8位可为空,如果输入多位,第一位不能为0(可保留2位小数)*/ 252 | return value != "" && !/^(0|[1-9]\d{0,7})(\.\d{1,2})?$/.test(value) 253 | }, 254 | isPositive: function(value) { /*输入必须为正数*/ 255 | return /^[0-9]+([.]{1}[0-9]{1,2})?$/.test(value) 256 | }, 257 | 258 | checkTax: function(value) { /* 验证税号,15或者17或者18或者20位字母、数字组成*/ 259 | return /^[A-Z0-9]{15}$|^[A-Z0-9]{17}$|^[A-Z0-9]{18}$|^[A-Z0-9]{20}$/.test(value) 260 | }, 261 | isUserCode: function(value) { /* 人员编号合法验证 字母和数字的组合 最长10位 /^[0-9]{8,10}$/*/ 262 | return value !== "" || value !== null || value !== undefined && /^([a-z]|[A-Z]|[0-9]){1,10}$/.test(value) 263 | }, 264 | isComAccount: function(value) { /*账户合法验证*/ 265 | return /^[0-9]{15}$/.test(value) 266 | 267 | }, 268 | isInsurBaseRule: function(value) { /*险种基数为1位到8位数字,小数点后最多两位*/ 269 | return /^(0|[1-9]\d{0,7})(\.\d{1,2})?$/.test(value); 270 | 271 | }, 272 | isPercent: function(value) { /*百分数,最多两位小数点*/ 273 | return !/^(100|(([1-9]\d|\d)(\.\d{1,2})?))$/.test(value) 274 | }, 275 | //错误信息 276 | } 277 | const validataeMsg = { 278 | "notEmpty": "不能为空!", 279 | "isNumber": "只能输入数字!", 280 | "isZipCode": "邮政编码不正确!", 281 | "isIdCardNo": "身份证号码格式不正确!", 282 | "isMobile": "手机号码格式错啦!", 283 | "isPhone": "电话号码格式错啦!", 284 | "isTel": "联系电话格式错啦!", 285 | "isQQ": "QQ号码格式错啦!", 286 | "isEmail": "email格式错啦!", 287 | "isBackId": "请正确填写您的银行卡号!", 288 | "isUrl": "网址格式错啦!", 289 | "isIp": "ip地址格式错啦!", 290 | "cnLength": "长度要介于{0}到{1}之间!", 291 | "cnLength": "您可输入{0}到{1}个字符,中文占3个字符!", 292 | "chineseMax": "您最多能输入{0}个字!", 293 | "cnMax": "请输入介于0到{0}之间的数字!", 294 | "cnMin": "请输入大于{0}的数字!", 295 | "userName": "只能包括中英文、数字和下划线!", 296 | "chrnum": "只能输入数字和字母(字符A-Z, a-z, 0-9)!", 297 | "chinese": "只能输入中文!", 298 | "userPassword": "以字母开头,长度在6-18之间,只能包含字符、数字或下划线!", 299 | "isDefaultPassword": "登录密码不能为默认密码!", 300 | "isSimplePassword": "登录密码太简单!", 301 | "isPic": "只能是jpg、png、gif、jpeg格式的图片!", 302 | "isPInt": "只能输入非负整数!", 303 | "charMin": "至少15位", 304 | "isInteger": "只能输入正整数!", 305 | "onlyEn_Num": "只能输入英文,数字和下划线!", 306 | "onlyCn_En_Num": "只能输入中英文,数字和下划线!", 307 | "onlyCn_En_Num_Point": "只能输入中英文,数字、下划线和中文标点符号!", 308 | "onlyCn_En_Num_Point_zhong_ying": "只能输入中英文,数字、下划线和标点符号!", 309 | "onlyCn_En_Num_Point_extend": "只能输入中英文,数字、下划线和中文标点符号及部分特殊符号!", 310 | "onlyCn_En_Num_Point_all_extend": "只能包括中英文、数字、下划线、中文标点符号、空格和回车及部分特殊符号", 311 | "onlyCn_En_Num_Point_return": "只能输入中英文,数字、下划线、中英文标点符号、空格、换行及括号类符号!", 312 | "orgTreeValid": "您还没有选择用户!", 313 | "equalTo": "请输入相同的值!", 314 | "decimal2": "请输入数字,小数点后保留2位!", 315 | "equalTo": "请输入相同的值!", 316 | "onlyNum_Point": "只能输入自然数,小数点后两位!", 317 | "onlyNum_Point3": "只能输入自然数,最多小数点后三位!", 318 | "onlyNum_Point4": "只能输入自然数,最多小数点后四位!", 319 | "onlyNum_Point7": "只能输入自然数,最多小数点后七位!", 320 | "onlycar_number_Eng": "请输入正确的车牌号!", 321 | "onlyCn_En_Num_bufen_return": "只能输入中英文字符、中英文标点符号、空格以及下划线和中线", 322 | //"decimal_num":"请输入数字或小数" 323 | "onlyChNun_Eng": "只能输入英文字母、数字和中文!", 324 | "socode": "统一社会信用代码!", 325 | "doubles7": "您输入的值的整数部分不能大于9999999,请重新输入!", 326 | "doubles5": "您输入的值的整数部分不能大于999,请重新输入!", 327 | // 排除特殊字符验证 项目名称可以输入+号 (可以输入加号|斜杠|顿号|括号 中英文) 328 | "specialChar": "内容不能出现特殊字符!", 329 | "postSal5": "薪资最多为5位整数", 330 | "isChineseCharacters": "内容不能出现特殊字符!", 331 | "nonnegativeInteger": "输入内容必须为(1~4)位非负整数!", 332 | "isNumber5": "只能输入5位数字", 333 | "Number0To100": "只能输入(0~100)的数字(可保留到2位小数)", 334 | "Numberint0To100": "只能输入(0~100)的整数", 335 | "isNumber8": "最多8位整数(可保留2位小数)", 336 | "isPositive": "输入必须为正数", 337 | "checkTax": "请输入正确的税号", 338 | "isUserCode": "数字、字母均可,最长10位!", 339 | "isComAccount": "请输入正确的账号!", 340 | "isInsurBaseRule": "请输入合法的基数!", 341 | "isPercent": "只能输入百分数" 342 | } 343 | 344 | 345 | /** 346 | vue-validato官方提供的api如下 347 | input[type="text"] 348 | input[type="radio"] 349 | input[type="checkbox"] 350 | input[type="number"] 351 | input[type="password"] 352 | input[type="email"] 353 | input[type="tel"] 354 | input[type="url"] 355 | select 356 | textarea 357 | 但是以上的不一定满足我们的需求,这时就需要用到另一个全局api,用于注册和获取全局验证器。 358 | */ 359 | 360 | //自定义验证器:Vue.validator( id, [definition] ) 361 | //例如添加一个简单的手机号验证 362 | 363 | Vue.validator('phone', function(val) { 364 | return validataconfig.isPhone(val) 365 | }); 366 | //添加一个密码验证 367 | //匹配6-20位的任何字类字符,包括下划线。与“[A-Za-z0-9_]”等效。 368 | Vue.validator('passw', function(val) { 369 | return /^(\w){6,20}$/.test(val) 370 | }); 371 | /* 372 | 验证器语法 373 | 374 | 375 |
376 | 不得少于3个字符 377 | 不得大于15个字符 378 |
379 |
380 | 381 | Terminal 指令问题 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | //导入validation.js 此处的validation.js就是上文中自定义验证器的内容 390 | import validator from '../validator/validation'; 391 | 392 | export default{ 393 | data(){ 394 | return{ 395 | phone:'',//电话号码 396 | } 397 | }, 398 | methods:{ 399 | //手机号验证失败时执行的方法 400 | notphone(){ 401 | //设置提示信息内容 402 | alert('手机不正确'); 403 | }, 404 | //密码验证成功时执行的方法 405 | isphone(){ 406 | //user option 407 | }, 408 | passwInvalid(){ 409 | alert('只能输入6-20个字母、数字、下划线'); 410 | }, 411 | passwok(){ 412 | //alert('验证码符合规范') 413 | } 414 | } 415 | } 416 | 417 | 默认情况下,vue-validator 会根据 validator 和 v-validate 指令自动进行验证。然而有时候我们需要关闭自动验证,在有需要时手动触发验证。如果你不需要自动验证,可以通过 initial 属性或 v-validate 验证规则来关闭自动验证。如下: 418 | 419 | 420 | 421 |
422 | 不得少于3个字符 423 | 不得大于15个字符 424 |
425 |
426 | */ 427 | -------------------------------------------------------------------------------- /src/vuex/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | vueX使用说明 4 | 5 | 1、this.$store : 我们可以通过 this.$store 在vue的组件中获取vuex的实例。 6 | 2、State : vuex中的数据源,我们可以通过 this.$store.state 获取我们在vuex中声明的全局变量的值。 7 | 3、Getter: 相当于vue中的computed , 及 计算属性, 可以用于监听、计算 state中的值的变化 8 | 4、Mutation: vuex中去操作数据的方法 (只能同步执行) 9 | 5、Action: 用来操作 Mutation 的动作 , 他不能直接去操作数据源,但可以把mutation变为异步的 10 | 6、Module: 模块化,当你的应用足够大的时候,你可以把你的vuex分成多个子模块 11 | 12 | import Vue from 'vue'; 13 | import Vuex from 'vuex'; 14 | Vue.use(Vuex); 15 | export default new Vuex.Store({ 16 | // 在state中去声明全局变量,可以通过 this.$store.state 访问 17 | state: { 18 | count: 0 19 | }, 20 | // 在getters中声明state中变量的计算函数,缓存计算后的数据, 通过 this.$store.getters 调用 21 | getters: { 22 | // 接受state作为参数,每次 count发生变化时 , 都会被调用 23 | consoleCount: state => { 24 | console.log('the state count : ' + state.count); 25 | return state.count; 26 | } 27 | }, 28 | // 只能执行同步方法,不要去执行异步方法 通过 this.$store.commit 方法去调用 29 | mutations: { 30 | // 改变state状态的方法,不建议直接通过 31 | // this.$store.state.? = ?的方式改变state中的状态 32 | addCount: state => { 33 | ++state.count; 34 | }, 35 | // 自定义改变state初始值的方法,mutations的第一个参数即为state对象,并且可以向mutation传入额外的参数(变量或对象); 36 | addNumCount: (state, n) => { 37 | state.count+=n; 38 | }, 39 | }, 40 | // 借助actions的手去 执行 mutations , 通过 this.$store.dispatch 的方式调用 41 | // 可以用来执行异步操作,可以跟踪异步数据状态变化 42 | actions: { 43 | // 调用 mutation 44 | addCount: context => { 45 | context.commit('addCount'); 46 | }, 47 | addNumCount: (context, n) => { 48 | context.commit('addNumCount', n); 49 | } 50 | } 51 | }) 52 | 53 | 我们在代码中分别注册了,state、getters、mutations、actions。 54 | 这样我们就可以在任何一个 component中通过 this.$store.dispatch('addNumCount', 5); 或者 this.$store.dispatch('addCount'); 去触发actions操作来改变state中的值。 -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | 4 | Vue.use(Vuex); 5 | 6 | const state = { 7 | loading: false, 8 | userInfo: { 9 | phone: 12345678900, 10 | account: "Titans", 11 | }, //用户信息 12 | login: true, //是否登录 13 | }; 14 | 15 | const getters = { //实时监听state值的变化(最新状态) 16 | isshowloading(state) { 17 | return state.loading 18 | }, 19 | islogin(state) { 20 | return state.login 21 | }, 22 | getuserInfo(state){ 23 | return state.userInfo 24 | } 25 | }; 26 | const mutations = { 27 | showloading(state, isshow) { //自定义改变state初始值的方法,这里面的参数除了state之外还可以再传额外的参数(变量或对象); 28 | state.loading = isshow; 29 | }, 30 | setlogin(state, islogin) { 31 | state.islogin = islogin; 32 | }, 33 | setuserInfo(state, userInfoobj){ 34 | state.userInfo=userInfoobj 35 | } 36 | }; 37 | const actions = { 38 | showloading: context => { 39 | context.commit('showloading',false); 40 | }, 41 | }; 42 | export default new Vuex.Store({ 43 | state, 44 | getters, 45 | mutations, 46 | actions 47 | }); 48 | -------------------------------------------------------------------------------- /static/webfavicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Titans1001/vue-multipage-platform-project/c44b30c1828ece29698b163a5b1096740b4a103d/static/webfavicon/favicon.ico -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // The assertion name is the filename. 3 | // Example usage: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // For more information on custom assertions see: 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | 10 | exports.assertion = function (selector, count) { 11 | this.message = 'Testing if element <' + selector + '> has count: ' + count 12 | this.expected = count 13 | this.pass = function (val) { 14 | return val === this.expected 15 | } 16 | this.value = function (res) { 17 | return res.value 18 | } 19 | this.command = function (cb) { 20 | var self = this 21 | return this.api.execute(function (selector) { 22 | return document.querySelectorAll(selector).length 23 | }, [selector], function (res) { 24 | cb.call(self, res) 25 | }) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/gettingstarted#settings-file 5 | module.exports = { 6 | src_folders: ['test/e2e/specs'], 7 | output_folder: 'test/e2e/reports', 8 | custom_assertions_path: ['test/e2e/custom-assertions'], 9 | 10 | selenium: { 11 | start_process: true, 12 | server_path: require('selenium-server').path, 13 | host: '127.0.0.1', 14 | port: 4444, 15 | cli_args: { 16 | 'webdriver.chrome.driver': require('chromedriver').path 17 | } 18 | }, 19 | 20 | test_settings: { 21 | default: { 22 | selenium_port: 4444, 23 | selenium_host: 'localhost', 24 | silent: true, 25 | globals: { 26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port) 27 | } 28 | }, 29 | 30 | chrome: { 31 | desiredCapabilities: { 32 | browserName: 'chrome', 33 | javascriptEnabled: true, 34 | acceptSslCerts: true 35 | } 36 | }, 37 | 38 | firefox: { 39 | desiredCapabilities: { 40 | browserName: 'firefox', 41 | javascriptEnabled: true, 42 | acceptSslCerts: true 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server using production config 2 | process.env.NODE_ENV = 'testing' 3 | 4 | const webpack = require('webpack') 5 | const DevServer = require('webpack-dev-server') 6 | 7 | const webpackConfig = require('../../build/webpack.prod.conf') 8 | const devConfigPromise = require('../../build/webpack.dev.conf') 9 | 10 | let server 11 | 12 | devConfigPromise.then(devConfig => { 13 | const devServerOptions = devConfig.devServer 14 | const compiler = webpack(webpackConfig) 15 | server = new DevServer(compiler, devServerOptions) 16 | const port = devServerOptions.port 17 | const host = devServerOptions.host 18 | return server.listen(port, host) 19 | }) 20 | .then(() => { 21 | // 2. run the nightwatch test suite against it 22 | // to run in additional browsers: 23 | // 1. add an entry in test/e2e/nightwatch.conf.js under "test_settings" 24 | // 2. add it to the --env flag below 25 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 26 | // For more information on Nightwatch's config file, see 27 | // http://nightwatchjs.org/guide#settings-file 28 | let opts = process.argv.slice(2) 29 | if (opts.indexOf('--config') === -1) { 30 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 31 | } 32 | if (opts.indexOf('--env') === -1) { 33 | opts = opts.concat(['--env', 'chrome']) 34 | } 35 | 36 | const spawn = require('cross-spawn') 37 | const runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 38 | 39 | runner.on('exit', function (code) { 40 | server.close() 41 | process.exit(code) 42 | }) 43 | 44 | runner.on('error', function (err) { 45 | server.close() 46 | throw err 47 | }) 48 | }) 49 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | // automatically uses dev Server port from /config.index.js 7 | // default: http://localhost:8080 8 | // see nightwatch.conf.js 9 | const devServer = browser.globals.devServerURL 10 | 11 | browser 12 | .url(devServer) 13 | .waitForElementVisible('#app', 5000) 14 | .assert.elementPresent('.hello') 15 | .assert.containsText('h1', 'Welcome to Your Vue.js App') 16 | .assert.elementCount('img', 1) 17 | .end() 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | Vue.config.productionTip = false 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var webpackConfig = require('../../build/webpack.test.conf') 7 | 8 | module.exports = function karmaConfig (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' } 30 | ] 31 | } 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /test/unit/specs/HelloWorld.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import HelloWorld from '@/components/HelloWorld' 3 | 4 | describe('HelloWorld.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(HelloWorld) 7 | const vm = new Constructor().$mount() 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .to.equal('Welcome to Your Vue.js App') 10 | }) 11 | }) 12 | --------------------------------------------------------------------------------