├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── README.md ├── build ├── build.js ├── dev-client.js ├── dev-server.js ├── utils.js ├── webpack.base.conf.js ├── webpack.dev.conf.js └── webpack.prod.conf.js ├── config ├── dev.env.js ├── index.js ├── prod.env.js └── test.env.js ├── dist ├── static │ ├── api │ │ ├── .gitkeep │ │ ├── center │ │ │ ├── getCenter.json │ │ │ ├── getFavourite.json │ │ │ ├── getNotification.json │ │ │ └── images │ │ │ │ ├── collect1.jpg │ │ │ │ ├── collect2.jpg │ │ │ │ ├── collect3.jpg │ │ │ │ └── collect4.jpg │ │ ├── destination │ │ │ ├── getDestination.json │ │ │ └── images │ │ │ │ ├── d_1.jpg │ │ │ │ ├── d_2.jpg │ │ │ │ ├── d_3.jpg │ │ │ │ └── d_4.jpg │ │ ├── home │ │ │ ├── homepageV3.json │ │ │ └── images │ │ │ │ ├── a1.jpg │ │ │ │ ├── a2.jpg │ │ │ │ ├── a3.jpg │ │ │ │ ├── banner1.jpg │ │ │ │ ├── banner2.jpg │ │ │ │ ├── l1.jpg │ │ │ │ ├── l2.jpg │ │ │ │ ├── l3.jpg │ │ │ │ ├── mu1.jpg │ │ │ │ ├── mu2.jpg │ │ │ │ ├── mu3.jpg │ │ │ │ ├── mu4.jpg │ │ │ │ ├── mu5.jpg │ │ │ │ ├── mu6.jpg │ │ │ │ ├── r1.jpg │ │ │ │ ├── r2.jpg │ │ │ │ ├── remai1.jpg │ │ │ │ ├── remai2.jpg │ │ │ │ └── remai3.jpg │ │ ├── order │ │ │ ├── countShopCartNum.json │ │ │ ├── deleteShopCart.json │ │ │ └── shopCart.json │ │ └── user │ │ │ └── login.json │ ├── css │ │ ├── center.648e76953f5e55ed22da2a4105a9fde8.css │ │ ├── destinationIndex.a06f9f4562800ea7a1521640fb01b7ce.css │ │ ├── index.3d5cd0837bdb92d6cd84fd45307504fc.css │ │ ├── login.c2d494d0e20f62bb52603ed6b4466099.css │ │ └── shoppingCart.88d4f1ac6dd10f7ebebf1d6640bb3be9.css │ ├── images │ │ ├── logined.536d85d.jpg │ │ ├── qq_login.59cc5b5.png │ │ ├── sina_login.3e2c8da.png │ │ └── wechat_login.617486b.png │ └── js │ │ ├── 0.1489d44a271ef2eedeed.js │ │ ├── 1.1fa23c38d9aed86b1147.js │ │ ├── 2.19f3b5257d948643990d.js │ │ ├── 3.94ceb073a05646b5ad62.js │ │ ├── 4.d7c4439221431031cbe7.js │ │ ├── 5.49cea5f6f4fb98e959e3.js │ │ ├── center.44c7b859c2e838fb3da9.js │ │ ├── destinationIndex.35369b96573b7ec198d7.js │ │ ├── flexible.63f20e39e6dee4aa5948.js │ │ ├── index.cd01b2f45b8c09baa884.js │ │ ├── lib │ │ ├── base64.js │ │ └── flexible │ │ │ └── flexible.js │ │ ├── login.776892e061fdf7322881.js │ │ ├── manifest.4dfd36d9c5897eed2fe9.js │ │ ├── shoppingCart.f71f016296dbfb71a8f5.js │ │ └── vendor.23c55bb9879e852e44ed.js └── views │ ├── center.html │ ├── destinationIndex.html │ ├── index.html │ ├── login.html │ └── shoppingCart.html ├── note ├── R10_关于商品SKU选择问题.md ├── R1_base64插件expose或imports报错问题.md ├── R2_modules之间的action以及mutation如何相互调用.md ├── R3_根据某个key获取数组json对应的index.md ├── R4_selectall.md ├── R5_试点增加多语言的支持.md ├── R6_使用mock模拟后端接口返回.md ├── R7_对多页面功能组织划分的一些思考.md ├── R8_组件style样式npm_run_build样式生成不出来问题.md ├── R9_登录拦截.md ├── byluchanan.docx ├── vue生命周期来解释为什么vue-awesome-swiper插件中length=0.docx └── 消息列表使用vuex来获取数据工作流程.docx ├── package-lock.json ├── package.json ├── src ├── assets │ ├── css │ │ └── .gitkeep │ ├── fonts │ │ ├── .gitkeep │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ ├── images │ │ └── icon │ │ │ ├── arrow_right.png │ │ │ ├── cart.png │ │ │ ├── checkbox.png │ │ │ ├── checkbox_on.png │ │ │ ├── destination.png │ │ │ ├── destination_on.png │ │ │ ├── dot.png │ │ │ ├── dot_on.png │ │ │ ├── header_right_edit.png │ │ │ ├── home.png │ │ │ ├── home_on.png │ │ │ ├── lazy_load_fail.png │ │ │ ├── lazy_load_loading.png │ │ │ ├── loading.gif │ │ │ ├── my.png │ │ │ ├── my_on.png │ │ │ ├── search.png │ │ │ └── service.png │ ├── js │ │ ├── base.js │ │ ├── common.js │ │ ├── config.js │ │ ├── filters.js │ │ ├── lib │ │ │ └── calendar │ │ │ │ ├── calendar.js │ │ │ │ └── calendar.scss │ │ ├── mock │ │ │ ├── center │ │ │ │ ├── index.js │ │ │ │ └── waitForCommentList.js │ │ │ ├── index.js │ │ │ └── shopping.js │ │ └── tools.js │ ├── locales │ │ ├── en-US.json │ │ └── zh-CN.json │ ├── logo.png │ └── scss │ │ ├── base │ │ ├── _common.scss │ │ ├── _cssreset.scss │ │ ├── _extend.scss │ │ ├── _footer.scss │ │ ├── _function.scss │ │ ├── _header.scss │ │ ├── _mixin.scss │ │ ├── _necessary.scss │ │ └── _variable.scss │ │ └── common.scss ├── components │ ├── common │ │ ├── footer.vue │ │ ├── list-bottom.vue │ │ ├── search-icon.vue │ │ └── service-icon.vue │ ├── home │ │ ├── home-banner.vue │ │ ├── home-header.vue │ │ └── home-topic.vue │ └── my │ │ ├── images │ │ ├── back.png │ │ ├── message.png │ │ ├── search.png │ │ └── setting.png │ │ └── my-header.vue ├── views │ ├── center │ │ ├── App.vue │ │ ├── app.js │ │ ├── index.html │ │ ├── pages │ │ │ ├── becomment │ │ │ │ └── index.vue │ │ │ ├── collect │ │ │ │ └── index.vue │ │ │ ├── message │ │ │ │ └── index.vue │ │ │ ├── my │ │ │ │ ├── images │ │ │ │ │ ├── all.png │ │ │ │ │ ├── collect.png │ │ │ │ │ ├── comment.png │ │ │ │ │ ├── hotel.png │ │ │ │ │ ├── logined.jpg │ │ │ │ │ ├── nologin.jpg │ │ │ │ │ ├── paying.png │ │ │ │ │ ├── service.png │ │ │ │ │ ├── taobao.png │ │ │ │ │ └── traveller.png │ │ │ │ ├── index.vue │ │ │ │ └── scss │ │ │ │ │ └── my.scss │ │ │ ├── service │ │ │ │ ├── images │ │ │ │ │ └── tel.png │ │ │ │ └── index.vue │ │ │ └── setting │ │ │ │ └── index.vue │ │ └── scss │ │ │ ├── center.scss │ │ │ └── collect.scss │ ├── destinationIndex │ │ ├── destinationIndex.html │ │ ├── destinationIndex.js │ │ ├── destinationIndex.vue │ │ └── scss │ │ │ └── destinationIndex.scss │ ├── index │ │ ├── index.html │ │ ├── index.js │ │ ├── index.vue │ │ └── scss │ │ │ └── home.scss │ ├── login │ │ ├── images │ │ │ ├── hr_login.png │ │ │ ├── qq_login.png │ │ │ ├── sina_login.png │ │ │ └── wechat_login.png │ │ ├── login.html │ │ ├── login.js │ │ ├── login.vue │ │ └── scss │ │ │ └── login.scss │ └── shoppingCart │ │ ├── shoppingCart.html │ │ ├── shoppingCart.js │ │ └── shoppingCart.vue └── vuex │ ├── api.js │ ├── modules │ ├── center │ │ └── becomment.js │ ├── collect.js │ ├── common.js │ ├── destinationIndex.js │ ├── index.js │ ├── login.js │ ├── messageList.js │ ├── my.js │ └── shoppingCart.js │ ├── mutation-types.js │ └── store.js ├── static ├── .gitkeep ├── api │ ├── .gitkeep │ ├── center │ │ ├── getCenter.json │ │ ├── getFavourite.json │ │ ├── getNotification.json │ │ └── images │ │ │ ├── collect1.jpg │ │ │ ├── collect2.jpg │ │ │ ├── collect3.jpg │ │ │ └── collect4.jpg │ ├── destination │ │ ├── getDestination.json │ │ └── images │ │ │ ├── d_1.jpg │ │ │ ├── d_2.jpg │ │ │ ├── d_3.jpg │ │ │ └── d_4.jpg │ ├── home │ │ ├── homepageV3.json │ │ └── images │ │ │ ├── a1.jpg │ │ │ ├── a2.jpg │ │ │ ├── a3.jpg │ │ │ ├── banner1.jpg │ │ │ ├── banner2.jpg │ │ │ ├── l1.jpg │ │ │ ├── l2.jpg │ │ │ ├── l3.jpg │ │ │ ├── mu1.jpg │ │ │ ├── mu2.jpg │ │ │ ├── mu3.jpg │ │ │ ├── mu4.jpg │ │ │ ├── mu5.jpg │ │ │ ├── mu6.jpg │ │ │ ├── r1.jpg │ │ │ ├── r2.jpg │ │ │ ├── remai1.jpg │ │ │ ├── remai2.jpg │ │ │ └── remai3.jpg │ ├── order │ │ ├── countShopCartNum.json │ │ ├── deleteShopCart.json │ │ └── shopCart.json │ └── user │ │ └── login.json └── js │ └── lib │ ├── base64.js │ └── flexible │ └── flexible.js ├── test ├── e2e │ ├── custom-assertions │ │ └── elementCount.js │ ├── nightwatch.conf.js │ ├── runner.js │ └── specs │ │ └── test.js └── unit │ ├── .eslintrc │ ├── index.js │ ├── karma.conf.js │ └── specs │ └── Hello.spec.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.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 | build/*.js 2 | config/*.js 3 | src/assets/js/lib/**/*.js 4 | static/js/lib/**/*.js 5 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | rules: { 15 | 'indent': ['warn', 4], 16 | 'semi': 0, // off semi 17 | 'eol-last': 0, 18 | 'no-unused-vars': 0, 19 | // allow paren-less arrow functions 20 | 'arrow-parens': 0, 21 | // allow async-await 22 | 'generator-star-spacing': 0, 23 | 'no-unused-vars': 0, 24 | // allow debugger during development 25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules/ 4 | npm-debug.log 5 | test/unit/coverage 6 | test/e2e/reports 7 | selenium-debug.log 8 | /.idea 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue-cli(2.0) 多页面开发实战 2 | 3 | > 由于之前主要使用jquery方式开发,现在想换一种方式,使用MVVM开发(感觉vue跟我之前用的angular1.X差不多类似),所以在开发中会遇到很多问题,借此来记录一下;或者有很多不足,又或者里面可能存在些错误,anyway,请多多指教,共勉。 4 | 5 | ## 现在的开发环境 ## 6 | 7 | 1. nodejs v5.1.1 ,npm 3.3.1.12 8 | 2. 使用vue-cli(包含vue2.0,webpack,sass,es6等环境) 9 | 10 | ## 如何运行项目 ## 11 | 12 | ``` bash 13 | # 下载项目后,首先安装需要的包 14 | npm install 15 | 16 | # 开发运行环境;运行命令后,浏览器自动打开http://localhost:8080/views/index.html 17 | npm run dev 18 | 19 | # 开发完成后打包命令,会生成dist文件夹,不要在本地打开,请安装类似http-server来运行(dist后js/css/api路径会指向我的github,可以在config/index.js下修改assetsPublicPath) 20 | npm run build 21 | 22 | ``` 23 | 24 | ## 前期准备 ## 25 | 26 | 1. 选择一个多页面开发案例参考,结合自己的实际情况修改一下,这里主要参考了以下一些案例 27 | - [https://github.com/bluefox1688/vue-cli-multi-page](https://github.com/bluefox1688/vue-cli-multi-page)(参考多页面配置整体思想) 28 | - [https://github.com/jiananle/vue-multi-page](https://github.com/jiananle/vue-multi-page)(参考整个文件命名架构,比较适合我这种情况) 29 | - [https://github.com/jarvan4dev/vue-multi-page](https://github.com/jarvan4dev/vue-multi-page)(参考以模块名作为名字输出,避免以模块名里面的文件名作为名字输出导致覆盖) 30 | 31 | 2. 熟悉相关语法(基本了解就好,毕竟做项目的时候才会发现更多的问题) 32 | - [es6基本使用方法](http://es6.ruanyifeng.com/) 33 | - [vue2.0官网](https://cn.vuejs.org/v2/guide/),[vue2 api](https://cn.vuejs.org/v2/api/) 34 | - [sass基本语法](http://www.w3cplus.com/sassguide/) 35 | 36 | ## 遇到的问题及功能 ## 37 | 38 | - 引入资源路径不要写相对路径, 使用base.config.js中定义的alias,如index.vue 39 | 40 | ``` 41 | import CommonFooter from '../../components/common/footer.vue'' => import CommonFooter from 'components/common/footer.vue' 42 | 43 | 46 | ``` 47 | 48 | home.scss 49 | 50 | ``` 51 | @import "../../../assets/scss/base/necessary.scss"; => @import "~assets/scss/base/necessary.scss"; 52 | 53 | background: url(../../assets/images/icon/loading.gif) => background: url('~assets/images/icon/loading.gif') 54 | ``` 55 | 56 | - 多页面SPA的组织架构重整 UPDATAE 201.6.11 57 | 58 | - mockjs模拟接口数据返回(Demo:删除购物车功能, 待点评列表) 59 | 60 | - [基于vue-cli,使用vue2.3.3 + webpack2 + es6 + vuex2.3.1 + scss的脚手架](https://github.com/luchanan/vue_cli_multiple_page) 61 | 62 | - 试用网站多语言支持(R5) 63 | 64 | - 刚开始装上vue-cli,发现eslint语法太过严格(定义未使用,要多少个空格,结尾要空行等),所以进行适当调整(M4) 65 | 66 | - eslint会对assets下面的第三方插件(自己下载引入的)也进行语法检测,有三种方法解决(A11) 67 | 68 | - .vue如何使用组件(A4) 69 | 70 | - .vue使用sass,注意是lang='scss'~~不是lang='sass'~~ 也可以是lang='sass (A5) 71 | 72 | - 如何npm一个带版本号的插件(A8) 73 | 74 | - 如何请求后台数据(vue-resource方式),并且渲染到html上(A12) 75 | 76 | - 微信jssdk如何设置全局,并且使用 77 | 78 | - 使用v:bind:style设置background(A13) 79 | 80 | - class使用多条件进行判断(A15) 81 | 82 | - 如何生成一个tree目录(额外内容)(A18) 83 | 84 | - html-loader部分代替服务器SSI(.html文件使用SSI来include类似JS或CSS资源目前没有找到很好的解决方法)(M1) 85 | 86 | - 子传父,父传子,非父子组件(BUS方式)之间传值问题(M8/M9/M10/M11) 87 | 88 | - set使用导致html{{}}无法输出2层 以上的object(M15) 89 | 90 | - img:src绑定assets下图片404问题(M9) 91 | 92 | ``` 93 | // 使用 94 | 95 | ``` 96 | 97 | - 使用filters(M12) 98 | 99 | - .js或.vue中script使用import(或require)文件引入.scss文件没有自动添加浏览器前缀问题,npm run dev 和npm run build 编译后浏览器前缀解析(丢失部分)不一样问题(M17) 100 | 101 | - ~~加入vuex逐步取代之前bus组件通讯方式,axios代替之前的vue-resource方案~~ 已全部代替(M18/M22) 102 | 103 | - 使用async/await来处理多个异步action且有依赖关系(M23) 104 | 105 | - dev模式下插入到html文件的script标签顺序没问题(例如,先是vendor.js里面包含vue,vuex集合,然后再是index.js),但是build后,顺序是反过来的,导致Cannot read property 'call' of undefined报错(M25) 106 | 107 | - iscroll5.2 在谷歌V56模拟器或者真机不能滑动的解决方案(M28) 108 | 109 | > 以上括号数字代表note/byluchanan.docx(没有特殊说明都是这个文件)里面的问题序号(蓝色下划线部分),R*代表.md文件名序号,更多详情看note文件下 110 | 111 | > 由于docx在git对比的不方便性,于2017/3/3 21:27结束编写,之后的问题以.md方式记录,放在note下 112 | 113 | ## 目前完成的模块 ## 114 | 115 | - 首页 116 | 117 | - 登录 118 | 119 | - 个人中心SPA包含我的、消息列表、我的收藏、客服页,设置,待点评 120 | 121 | - 目的地选择 122 | 123 | - 购物车列表 124 | 125 | 126 | ### 说明 127 | 128 | > 使用的图片资源,接口均来自chrome分析出来的,学习之用。 129 | -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('shelljs/global') 3 | env.NODE_ENV = 'production' 4 | 5 | var path = require('path') 6 | var config = require('../config') 7 | var ora = require('ora') 8 | var webpack = require('webpack') 9 | var webpackConfig = require('./webpack.prod.conf') 10 | 11 | console.log( 12 | ' Tip:\n' + 13 | ' Built files are meant to be served over an HTTP server.\n' + 14 | ' Opening index.html over file:// won\'t work.\n' 15 | ) 16 | 17 | var spinner = ora('building for production...') 18 | spinner.start() 19 | 20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 21 | 22 | rm('-rf', assetsPath) // 删除 assetsPath(dist/static) 目录下的文件及目录, 忽略不存在的目录 23 | mkdir('-p', assetsPath) // 若路径中的某些目录尚不存在, 系统将自动建立好那些尚不存在的目录,即一次可以建立多个目录 24 | cp('-R', 'static/*', assetsPath) // 复制目录及目录内的所有项目 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /build/dev-server.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | if (!process.env.NODE_ENV) process.env.NODE_ENV = config.dev.env 3 | var path = require('path') 4 | var express = require('express') 5 | var webpack = require('webpack') 6 | var opn = require('opn') 7 | var proxyMiddleware = require('http-proxy-middleware') 8 | var webpackConfig = require('./webpack.dev.conf') 9 | 10 | // default port where dev server listens for incoming traffic 11 | var port = process.env.PORT || config.dev.port 12 | // Define HTTP proxies to your custom API backend 13 | // https://github.com/chimurai/http-proxy-middleware 14 | var proxyTable = config.dev.proxyTable 15 | 16 | var app = express() 17 | var compiler = webpack(webpackConfig) 18 | 19 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 20 | publicPath: webpackConfig.output.publicPath, 21 | stats: { 22 | colors: true, 23 | chunks: false 24 | } 25 | }) 26 | 27 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 28 | 29 | // force page reload when html-webpack-plugin template changes 30 | compiler.plugin('compilation', function (compilation) { 31 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 32 | hotMiddleware.publish({ action: 'reload' }) 33 | cb() 34 | }) 35 | }) 36 | 37 | // proxy api requests 38 | Object.keys(proxyTable).forEach(function (context) { 39 | var options = proxyTable[context] 40 | if (typeof options === 'string') { 41 | options = { target: options } 42 | } 43 | app.use(proxyMiddleware(context, options)) 44 | }) 45 | 46 | // handle fallback for HTML5 history API 47 | app.use(require('connect-history-api-fallback')()) 48 | 49 | // serve webpack bundle output 50 | app.use(devMiddleware) 51 | 52 | // enable hot-reload and state-preserving 53 | // compilation error display 54 | app.use(hotMiddleware) 55 | 56 | // serve pure static assets 57 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 58 | app.use(staticPath, express.static('./static')) 59 | 60 | module.exports = app.listen(port, function (err) { 61 | if (err) { 62 | console.log(err) 63 | return 64 | } 65 | var uri = 'http://localhost:' + port + '/views/index.html' // 直接显示页面 66 | console.log('Listening at ' + uri + '\n') 67 | opn(uri) 68 | }) 69 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | // glob模块,用于读取webpack入口目录文件 3 | var glob = require('glob'); 4 | var config = require('../config') 5 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 6 | 7 | /* 8 | * 返回静态资源路径(不需要被处理的资源) 9 | * project/static 10 | * */ 11 | exports.assetsPath = function (_path) { 12 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 13 | ? config.build.assetsSubDirectory 14 | : config.dev.assetsSubDirectory 15 | return path.posix.join(assetsSubDirectory, _path) 16 | } 17 | 18 | exports.cssLoaders = function (options) { 19 | options = options || {} 20 | // generate loader string to be used with extract text plugin 21 | function generateLoaders (loaders) { 22 | var sourceLoader = loaders.map(function (loader) { 23 | var extraParamChar; 24 | 25 | if (/\?/.test(loader)) { 26 | loader = loader.replace(/\?/, '-loader?') 27 | extraParamChar = '&' 28 | } else { 29 | loader = loader + '-loader' 30 | extraParamChar = '?' 31 | // 解决npm run dev 和 npm run build 编译后前缀不一样的问题 32 | if (loader === 'css-loader') { 33 | extraParamChar = '?-autoprefixer&' 34 | } 35 | } 36 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 37 | 38 | }).join('!'); 39 | 40 | // Extract CSS when that option is specified 41 | // (which is the case during production build) 42 | if (options.extract) { 43 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 44 | } else { 45 | return ['vue-style-loader', sourceLoader].join('!') 46 | } 47 | } 48 | 49 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 50 | return { 51 | css: generateLoaders(['css']), 52 | postcss: generateLoaders(['css']), 53 | less: generateLoaders(['css', 'less']), 54 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 55 | scss: generateLoaders(['css', 'sass']), 56 | stylus: generateLoaders(['css', 'stylus']), 57 | styl: generateLoaders(['css', 'stylus']) 58 | } 59 | } 60 | 61 | // Generate loaders for standalone style files (outside of .vue) 62 | exports.styleLoaders = function (options) { 63 | var output = []; 64 | var loaders = exports.cssLoaders(options); 65 | 66 | for (var extension in loaders) { 67 | // var loader = loaders[extension]; 68 | // 解决.js文件引入scss无法添加前缀问题 69 | var loader = loaders[extension].split('!'); 70 | // 解决.js文件引入scss无法添加前缀问题 71 | var isPreProcesser = ['less', 'sass', 'scss' ,'stylus', 'styl'].some(function (v) { 72 | return v === extension 73 | }) 74 | // 解决.js文件引入scss无法添加前缀问题 75 | if (isPreProcesser) { 76 | loader.splice(-1, 0, 'postcss-loader') 77 | } 78 | output.push({ 79 | test: new RegExp('\\.' + extension + '$'), 80 | // loader: loader 81 | // 解决.js文件引入scss无法添加前缀问题 82 | loader: loader.join('!') 83 | }) 84 | } 85 | 86 | return output 87 | } 88 | //获取js入口文件 89 | exports.getEntries = function (globPath,type) { 90 | var entries = {} 91 | var ishtml=type!==undefined?true:false; 92 | /** 93 | * 读取src目录,并进行路径裁剪 94 | */ 95 | glob.sync(globPath).forEach(function (entry) { 96 | /** 97 | * path.basename 提取出用 ‘/' 隔开的path的最后一部分,除第一个参数外其余是需要过滤的字符串 98 | * path.extname 获取文件后缀 99 | */ 100 | // var basename = path.basename(entry, path.extname(entry), 'router.js') // 过滤router.js 101 | // ***************begin*************** 102 | // 当然, 你也可以加上模块名称, 即输出如下: { module/main: './src/module/index/main.js', module/test: './src/module/test/test.js' } 103 | // 最终编译输出的文件也在module目录下, 访问路径需要时 localhost:8080/module/index.html 104 | // slice 从已有的数组中返回选定的元素, -3 倒序选择,即选择最后三个 105 | //以ocahost:8080/homeIndex.html这样形式访问 106 | if(ishtml){ 107 | //html以模块文件作为输出 108 | //以locahost:8080/views/index.html这样形式访问 109 | /*var tmp = entry.split('/').splice(-3) 110 | var moduleName = tmp.slice(0, 2).join("/"); 111 | console.log(moduleName); 112 | entries[moduleName] = entry*/ 113 | var tmp = entry.split('/').splice(-3) 114 | var moduleName = tmp.splice(0,2).join("/"); 115 | entries[moduleName] = entry 116 | 117 | } 118 | else{ 119 | //js以模块文件作为输出,比如indx.js 120 | var basename = path.basename(entry, path.extname(entry)); 121 | tmp = entry.split('/').splice(-3); 122 | pathname = tmp.splice(1, 1); 123 | entries[pathname] = entry; 124 | } 125 | //以locahost:8080/views/index.html这样形式访问 126 | // var tmp = entry.split('/').splice(-3) 127 | // var moduleName = tmp.slice(1, 2); 128 | // console.log(moduleName); 129 | // entries[moduleName] = entry 130 | }); 131 | // console.log(entries); 132 | // 获取的主入口如下: { main: './src/module/index/main.js', test: './src/module/test/test.js' } 133 | return entries; 134 | } 135 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var glob = require('glob') 5 | var autoprefixer = require('autoprefixer') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | var env = process.env.NODE_ENV 8 | // check env & config/index.js to decide weither to enable CSS Sourcemaps for the 9 | // various preprocessor loaders added to vue-loader at the end of this file 10 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 11 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 12 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 13 | 14 | var projectRoot = path.resolve(__dirname, '../') 15 | var srcDir = path.resolve(__dirname, '../src') 16 | var entries = utils.getEntries(srcDir + '/views/**/*.js') 17 | var libs=path.resolve(__dirname, '../static/js/lib') 18 | entries['flexible'] = path.resolve(__dirname, libs+'/flexible/flexible.js') 19 | var autoprefixerConf = autoprefixer({ browsers: ['last 2 versions','Android >= 4.0','iOS >= 6'] }); 20 | 21 | module.exports = { 22 | entry: entries, 23 | 24 | output: { 25 | path: config.build.assetsRoot, 26 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 27 | filename: '[name].js' 28 | }, 29 | 30 | resolve: { 31 | extensions: ['', '.js', '.vue'], 32 | fallback: [path.join(__dirname, '../node_modules')], 33 | alias: { 34 | 'vue$': 'vue/dist/vue', 35 | // 'jquery$': 'jquery/dist/jquery',// 注销,使用CDN 36 | 'src': path.resolve(__dirname, '../src'), 37 | 'assets': path.resolve(__dirname, '../src/assets'), 38 | 'images': path.resolve(__dirname, '../src/assets/images'), 39 | 'js': path.resolve(__dirname, '../src/assets/js'), 40 | 'components': path.resolve(__dirname, '../src/components'), 41 | 'scss': path.resolve(__dirname, '../src/assets/scss') 42 | } 43 | }, 44 | 45 | resolveLoader: { 46 | fallback: [path.join(__dirname, '../node_modules')] 47 | }, 48 | externals: { 49 | 'wx': 'jWeixin', // 使用cdn资源,暴露wx 50 | 'jquery': 'jQuery' // 使用cdn资源,暴露jquery 51 | }, 52 | module: { 53 | preLoaders: [ 54 | { 55 | test: /\.vue$/, 56 | loader: 'eslint', 57 | include: projectRoot, 58 | exclude: /node_modules/ 59 | }, 60 | { 61 | test: /\.js$/, 62 | loader: 'eslint', 63 | include: projectRoot, 64 | exclude: /node_modules/ 65 | } 66 | ], 67 | 68 | loaders: [ 69 | { 70 | test: /\.vue$/, 71 | loader: 'vue' 72 | }, 73 | { 74 | test: /\.js$/, 75 | loader: 'babel', 76 | include: projectRoot, 77 | exclude: /node_modules/ 78 | }, 79 | { 80 | test: /\.html$/, 81 | loader: 'html' 82 | }, 83 | { 84 | test: /\.json$/, 85 | loader: 'json' 86 | }, 87 | /*{ 88 | test: /\.(css|scss)$/, 89 | loader: "style!css!postcss!sass" 90 | },*/ 91 | { 92 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 93 | loader: 'url', 94 | query: { 95 | limit: 10000, 96 | name: utils.assetsPath('images/[name].[hash:7].[ext]') 97 | } 98 | }, 99 | { 100 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 101 | loader: 'url', 102 | query: { 103 | limit: 10000, 104 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 105 | } 106 | } 107 | ] 108 | }, 109 | // js 中引入的样式处理 110 | postcss: [autoprefixerConf], 111 | eslint: { 112 | formatter: require('eslint-friendly-formatter') 113 | }, 114 | vue: { 115 | // .vue 中的样式处理 116 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 117 | postcss: [autoprefixerConf] 118 | }, 119 | plugins:[] 120 | } 121 | var pages = utils.getEntries('./src/views/**/*.html',1); 122 | 123 | for (var pathname in pages) { 124 | // 生成html相关配置 125 | var conf = { 126 | filename: pathname + '.html', // html文件输出路径 127 | template: pages[pathname], // 模板路径 128 | inject: true, // js插入位置 129 | minify: { 130 | //压缩设置 131 | //removeComments: true, 132 | //collapseWhitespace: true, 133 | //removeAttributeQuotes: true 134 | // more options: 135 | // https://github.com/kangax/html-minifier#options-quick-reference 136 | }, 137 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 138 | chunksSortMode: 'dependency' 139 | }; 140 | pathname=pathname.split("/")[1];//去掉views 141 | if (pathname in module.exports.entry) { 142 | conf.inject = 'body'; 143 | //如果每个html没有进入这里的话,那么全部js将会插入html 144 | conf.chunks = ['flexible', pathname, 'vendor', 'manifest', 'bootstrap'], 145 | conf.hash = true; 146 | } 147 | module.exports.plugins.push(new HtmlWebpackPlugin(conf)); 148 | } 149 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | var merge = require('webpack-merge') 3 | var config = require('../config') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | 7 | // add hot-reload related code to entry chunks 8 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 9 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 10 | }) 11 | 12 | 13 | var devConf = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | ] 28 | }) 29 | 30 | module.exports = devConf; 31 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | var utils = require('./utils') 6 | var config = require('../config') 7 | var baseWebpackConfig = require('./webpack.base.conf') 8 | var env = config.build.env; 9 | 10 | 11 | var webpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 14 | }, 15 | 16 | devtool: config.build.productionSourceMap ? '#source-map' : false, 17 | 18 | output: { 19 | path: config.build.assetsRoot, 20 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 21 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 22 | }, 23 | 24 | vue: { 25 | loaders: utils.cssLoaders({ 26 | sourceMap: config.build.productionSourceMap, 27 | extract: true 28 | }) 29 | }, 30 | 31 | plugins: [ 32 | // http://vuejs.github.io/vue-loader/workflow/production.html 33 | new webpack.DefinePlugin({ 34 | 'process.env': env 35 | }), 36 | 37 | new webpack.optimize.UglifyJsPlugin({ 38 | compress: { 39 | warnings: false 40 | } 41 | }), 42 | // 有时候build出来的 -------------------------------------------------------------------------------- /dist/views/destinationIndex.html: -------------------------------------------------------------------------------- 1 | 目的地
-------------------------------------------------------------------------------- /dist/views/index.html: -------------------------------------------------------------------------------- 1 | 首页
-------------------------------------------------------------------------------- /dist/views/login.html: -------------------------------------------------------------------------------- 1 | 我的
-------------------------------------------------------------------------------- /dist/views/shoppingCart.html: -------------------------------------------------------------------------------- 1 | 购物车
-------------------------------------------------------------------------------- /note/R2_modules之间的action以及mutation如何相互调用.md: -------------------------------------------------------------------------------- 1 | #### 在.vue可以通过,来获取store.js定义的所有module的actions,mutations等 2 | 3 | ```javascript 4 | 16 | ``` 17 | ### 一:js文件调用其他module中的mutation方法 18 | 19 | #### 想在api.js在axios添加一个loading拦截器,调用mudule/common.js的方法 20 | 21 | 在mudule/common.js定义mutations 22 | 23 | ```javascript 24 | const mutations = { 25 | // 全局loading 26 | [types.GLOBAL_SET_LOADINNG] (state, flag) { 27 | state.globalLoadinng = flag 28 | if (state.globalLoadinng) { 29 | Indicator.open()//element中mint-ui的Indicator 30 | } else { 31 | Indicator.close() 32 | } 33 | } 34 | } 35 | ``` 36 | 37 | api.js 38 | 39 | ```javascript 40 | import store from './store'//首先要引入这个store 41 | axios.interceptors.request.use( 42 | config => { 43 | store.commit(types.GLOBAL_SET_LOADINNG, true) 44 | return config; 45 | }, 46 | err => { 47 | return Promise.reject(err); 48 | } 49 | ) 50 | axios.interceptors.response.use( 51 | response => { 52 | store.commit(types.GLOBAL_SET_LOADINNG, false)// 调用mudule/common.js中mutation方法 53 | return response; 54 | }, 55 | err => { 56 | return Promise.reject(err); 57 | } 58 | ) 59 | 60 | ``` 61 | 62 | ### 二:js文件中mutation调用其他module中的mutation方法 63 | 64 | 比如shoppingCart.js中某个mutation调用common.js中mutation方法 65 | 66 | api.js 67 | 引入了 68 | 69 | ```javascript 70 | import store from './store' 71 | ``` 72 | 可以在module下的js来来调用action或者mutation 73 | 74 | ```javascript 75 | const mutations = { 76 | [types.SHOW_CHECKBOX] (state) { 77 | if (state.shoppingCartCheckbox) { 78 | state.shoppingCartCheckbox = false 79 | store.commit('TOP_RIGHT_CLICK', {font: '完成'})//来自mudule/common.js 80 | } else { 81 | state.shoppingCartCheckbox = true 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | ### 三:js文件中action调用其他文件的action方法 88 | 89 | ``` 90 | // import store from './store'不用引入 91 | const actions = { 92 | getShoppingCartList: function ({commit}) { 93 | if (state.hasMore) { 94 | commit(types.LOADING);//来自common.js 的action方法 95 | return api.getShoppingCartList(state.currentPage, function (res) { 96 | commit(types.SHOPPINGCART_GET_LIST, res) 97 | }) 98 | } 99 | } 100 | } 101 | ``` 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /note/R3_根据某个key获取数组json对应的index.md: -------------------------------------------------------------------------------- 1 | ### 假设car_list的数据如下: 2 | ``` 3 | var cart_list=[ 4 | { 5 | "single_amount": 0, 6 | "adult_amount": "1", 7 | "child_amount": "1", 8 | "baby_amount": 0, 9 | "check_in_date": "", 10 | "check_out_date": "", 11 | "user_id": "2", 12 | "sale_id": "43", 13 | "sku_sale_id": "96", 14 | "sku_format_val": "门票+不含导游+不含接送", 15 | "go_time": "2016-12-31", 16 | "id": 7160, 17 | "payment": "110.00", 18 | "product_name": "【当日可订】清迈夜间动物园门票套餐", 19 | "category_id": "29", 20 | "category_code": "MP", 21 | "product_status": "1", 22 | "image": "../static/api/center/images/collect1.jpg", 23 | "sku_status": 1, 24 | "is_timeout": 1, 25 | "stock_status": 1, 26 | "adult_price": "68.00", 27 | "child_price": "42.00" 28 | }, 29 | { 30 | "single_amount": 0, 31 | "adult_amount": "3", 32 | "child_amount": "2", 33 | "baby_amount": 0, 34 | "check_in_date": "", 35 | "check_out_date": "", 36 | "user_id": "2", 37 | "sale_id": "43", 38 | "sku_sale_id": "95", 39 | "sku_format_val": "门票+含导游+含接送", 40 | "go_time": "2016-12-30", 41 | "id": 7159, 42 | "payment": "573.00", 43 | "product_name": "【当日可订】清迈夜间动物园门票套餐", 44 | "category_id": "29", 45 | "category_code": "MP", 46 | "product_status": "1", 47 | "image": "../static/api/center/images/collect2.jpg", 48 | "sku_status": 1, 49 | "is_timeout": 1, 50 | "stock_status": 1, 51 | "adult_price": "127.00", 52 | "child_price": "96.00" 53 | }, 54 | { 55 | "single_amount": 0, 56 | "adult_amount": "1", 57 | "child_amount": "0", 58 | "baby_amount": 0, 59 | "check_in_date": "", 60 | "check_out_date": "", 61 | "user_id": "2", 62 | "sale_id": "43", 63 | "sku_sale_id": "96", 64 | "sku_format_val": "门票+不含导游+不含接送", 65 | "go_time": "2016-12-28", 66 | "id": 7158, 67 | "payment": "68.00", 68 | "product_name": "【当日可订】清迈夜间动物园门票套餐", 69 | "category_id": "29", 70 | "category_code": "MP", 71 | "product_status": "1", 72 | "image": "../static/api/center/images/collect3.jpg", 73 | "sku_status": 1, 74 | "is_timeout": 1, 75 | "stock_status": 1, 76 | "adult_price": "68.00", 77 | "child_price": "42.00" 78 | } 79 | ] 80 | ``` 81 | 82 | ### 找id为***在car_list数组所在的索引 83 | 84 | #### 方法一: 85 | 86 | ``` 87 | cart_list.map(x=>x.id).indexOf(7158)// 2,如果找不到返回-1 88 | ``` 89 | 90 | #### 方法二: 91 | 92 | ``` 93 | cart_list.findIndex(x=>x.id==7159)// 1,如果找不到返回-1 94 | ``` 95 | -------------------------------------------------------------------------------- /note/R4_selectall.md: -------------------------------------------------------------------------------- 1 | 2 | ### 方法一 3 | 4 | ``` 5 |
  • 6 | 7 |
    8 | 9 | 10 |
  • 11 | ``` 12 | ``` 13 | const state = { 14 | shoppingCartCheckbox: false, 15 | shoppingList: [], 16 | hasMore: true, 17 | currentPage: 0, 18 | totalPrice: 0, 19 | buyBtnDisabled: true, 20 | buyBtnCurrentFont: buyBtnFont.go, 21 | priceShow: {visibility: 'visible'}, 22 | checkAll: false, 23 | itemChecked: [], 24 | isDelete: false 25 | } 26 | // select all event 27 | [types.SHOPPINGCART_SELECT_ALL] (state) { 28 | state.itemChecked = [] 29 | state.checkAll = !state.checkAll 30 | if (state.checkAll) { 31 | state.shoppingList.forEach(function (item, index) { 32 | state.itemChecked.push(state.shoppingList[index].id); 33 | }) 34 | } 35 | } 36 | ``` 37 | 但是如果没有checkbox被点击呢? 38 | 39 | ### 方法二 40 | 41 | 在返回的数据上加上checked标志 42 | 43 | 参考 44 | 45 | http://stackoverflow.com/questions/33571382/check-all-checkboxes-vuejs 46 | -------------------------------------------------------------------------------- /note/R5_试点增加多语言的支持.md: -------------------------------------------------------------------------------- 1 | 2 | ### 考虑到以后以后网站的扩展性,可能要支持多种语言,现在暂时在setting试点 3 | 4 | #### 假设网站支持的语言有 5 | 6 | 1. 简体, zh-CN 7 | 2. 英语, en 8 | 9 | #### 使用如下的插件来进行处理:[vue i18n v6.1.1](https://github.com/kazupon/vue-i18n) 10 | 11 | #### 使用方式 12 | 13 | - 安装 14 | 15 | ``` 16 | npm install vue-i18n 17 | ``` 18 | 19 | - 全局使用,base.js加入 20 | 21 | ``` 22 | import VueI18n from 'vue-i18n' 23 | Vue.use(VueI18n) 24 | //引入语言包 25 | import cn from '../locales/zh-CN.json' 26 | import en from '../locales/en-US.json' 27 | const messages = { 28 | 'zh-CN': cn, 29 | 'en-US': en 30 | } 31 | const i18n = new VueI18n({ 32 | locale: 'zh-CN', 33 | messages 34 | }) 35 | ... 36 | module.exports = { 37 | Vue, $, Common, wx, i18n 38 | } 39 | ``` 40 | - 语言包内容 41 | 42 | #### zh-CN.json 43 | ``` 44 | { 45 | "setting": { 46 | "logout": "退出登录" 47 | } 48 | } 49 | ``` 50 | #### en-US.json 51 | 52 | ``` 53 | { 54 | "setting": { 55 | "logout": "退出登录" 56 | } 57 | } 58 | 59 | ``` 60 | - 以setting为例子 61 | 62 | #### setting.js 63 | 64 | ``` 65 | import { Vue, $, Common, i18n } from 'js/base' 66 | ... 67 | var homeVue = new Vue({ 68 | el: '#setting', 69 | i18n,//加入 70 | store, 71 | template: '
    ', 72 | components: { 73 | 'my-header': myHeader, 74 | 'setting': setting 75 | } 76 | }) 77 | ``` 78 | 79 | ### html引入,setting.vue 80 | 81 | ``` 82 |

    {{ $t("global.logout") }}

    83 | ``` 84 | 最后在/views/setting.html可以看到处理的结果 85 | 86 | ``` 87 |

    退出登录

    88 | ``` 89 | ### js文件引入 90 | 91 | ``` 92 | 111 | ``` 112 | 113 | ### 切换语言,setting.vue 114 | ``` 115 | 136 | ``` 137 | 138 | #### 遗留问题,vuex dispatch 如何触发语言更换 139 | 140 | ``` 141 | created: function () { 142 | this.$store.dispatch('setPageInfo', { 143 | headerTitle: this.$t('setting.topTitle'),// 这样的话,切换语言的时候,这个还是默认语言,待解决!! 144 | left: {className: 'back'}, 145 | 'right': {hide: true} 146 | }) 147 | } 148 | ``` 149 | 150 | 151 | -------------------------------------------------------------------------------- /note/R6_使用mock模拟后端接口返回.md: -------------------------------------------------------------------------------- 1 | 之前是使用是之间写一个json的文件, 比如删除购物车deleteShopCart.json 2 | ``` 3 | { 4 | "error_code": "0000", 5 | "error_msg": "OK", 6 | "execute_time": 0.31 7 | } 8 | ``` 9 | 然后在对应的接口使用相对地址来请求这个接口 10 | ``` 11 | deleteShoppingCartList: function (parmas, cb) { 12 | axios.get(url + 'order/deleteShopCart.json?t=' + new Date() * 1 + '&callback=?').then(function (res) { 13 | if (res.status >= 200 && res.status < 300) { 14 | cb(res.data, parmas) 15 | } 16 | }).catch((error) => { 17 | return Promise.reject(error) 18 | }) 19 | } 20 | ``` 21 | 这种方法缺点是数据不够灵活,有可能返回的东西不一定是OK,要使得上面的三个参数返回随机化,那么就需要一些灵活的接口工具,这里使用[mockjs](http://mockjs.com/) 22 | 23 | ``` 24 | npm install mockjs --save 25 | ``` 26 | 27 | src/js新建mock文件夹,里面新建index.js和shopping.js 28 | 29 | ``` 30 | // shopping.js 31 | import Mock from 'mockjs' 32 | const shopping = [ 33 | { 34 | path: '/shopping/delete', 35 | data: { 36 | 'error_code|1': ['0000', '1000'], 37 | 'error_msg': function () { 38 | const errorCode = this.error_code 39 | let errorMsg = '' 40 | switch (errorCode) { 41 | case '0000': 42 | errorMsg = '删除成功' 43 | break 44 | case '1000': 45 | errorMsg = '删除失败' 46 | break 47 | default: 48 | errorMsg = '未知错误' 49 | } 50 | return errorMsg 51 | }, 52 | 'execute_time|1-10': 1 53 | } 54 | } 55 | ] 56 | 57 | export default shopping 58 | 59 | ``` 60 | 61 | ``` 62 | // index.js 63 | import Mock from 'mockjs' 64 | import shopping from 'js/mock/shopping' 65 | function addToMock (api) { 66 | api.forEach(item => { 67 | Mock.mock(item.path, item.data) 68 | }) 69 | } 70 | addToMock(shopping) 71 | export default Mock 72 | ``` 73 | 74 | ``` 75 | base.js 放在这里是对所有符合条件的ajax进行拦截,符合条件将会调用mock定义的数据 76 | import mock from 'js/mock/index' 77 | ``` 78 | 79 | 调用: 80 | 81 | ``` 82 | // api.js 83 | deleteShoppingCartList: function (parmas, cb) { 84 | axios.get('/shopping/delete').then(function (res) { 85 | if (res.status >= 200 && res.status < 300) { 86 | cb(res.data, parmas) 87 | } 88 | }).catch((error) => { 89 | return Promise.reject(error) 90 | }) 91 | } 92 | ``` 93 | 94 | 这里点击删除,其实在chrome network看不到接口请求的,因为mockjs已经拦截了ajax请求,转到去调用对应的js方法 95 | 96 | -------------------------------------------------------------------------------- /note/R7_对多页面功能组织划分的一些思考.md: -------------------------------------------------------------------------------- 1 | 发觉我对多页面的划分有些错误的认识,如果我将要做一个全站的网站,可能涉及三四十个页面,如果我按照目前的方式,一个页面一个文件夹,里面都是对应这个页面的html,js,vue或者其他资源文件,觉得有以下的缺点: 2 | 3 | - 这样导致views下的文件数量很多 4 | - 页面所属于的大类不清晰,比如我需要这样views/my/collect,views/my/order...,而之前的是views/collect.html,views/order.html 5 | 6 | 所以现在要改变一个策略,以模块/功能的方式去划为多个spa(而不是之前的一个页面一个页面划为单页),不同spa通过链接跳转 7 | 8 | - 个人中心模块作为一个spa, 所有页面归类到center,这里的所有功能用路由连接 9 | - 首页作为一个spa 10 | - 目的地模块作为一个spa 11 | - 订单作为一个spa 12 | 13 | 参考: 14 | 15 | - [滴滴 webapp 5.0 Vue 2.0 重构经验分享](https://github.com/DDFE/DDFE-blog/issues/13) 16 | 17 | 18 | -------------------------------------------------------------------------------- /note/R8_组件style样式npm_run_build样式生成不出来问题.md: -------------------------------------------------------------------------------- 1 | 自从把个人中心瓜分了个SPA后,发现npm run build的时候,个人中心涉及列表加载的loading组件的style生成不出来,而npm run dev是没有问题 2 | 3 | src/views/shoppingCart/shoppingCart.vue 4 | ``` 5 | 12 | 18 | ``` 19 | src/views/shoppingCart/shoppingCart.js 20 | ``` 21 | import { Vue, $, Common } from 'js/base' 22 | import myHeader from '../../components/my/my-header.vue' 23 | import store from '../../vuex/store' 24 | require('../center/scss/collect.scss') 25 | import shoppingCart from './shoppingCart.vue' 26 | var homeVue = new Vue({ 27 | el: '#shoppingCart', 28 | store, 29 | template: '
    ', 30 | components: { 31 | 'my-header': myHeader, 32 | 'shopping-cart': shoppingCart 33 | } 34 | }) 35 | ``` 36 | 个人中心的route设置 37 | ``` 38 | import { Vue, VueRouter, i18n } from 'js/base' 39 | import myHeader from '../../components/my/my-header.vue' 40 | import store from '../../vuex/store' 41 | import app from './App.vue' 42 | const beComment = resolve => require(['./pages/becomment'], resolve) 43 | const my = resolve => require(['./pages/my'], resolve) 44 | const service = resolve => require(['./pages/service'], resolve) 45 | const setting = resolve => require(['./pages/setting'], resolve) 46 | const message = resolve => require(['./pages/message'], resolve) 47 | const collect = resolve => require(['./pages/collect'], resolve) 48 | import './scss/center.scss' 49 | const router = new VueRouter({ 50 | routes: [ 51 | { 52 | path: '/', 53 | component: my 54 | }, 55 | { 56 | path: '/becomment', 57 | component: beComment, 58 | meta: { 59 | requireAuth: true // 进入路由需要登录 60 | } 61 | }, 62 | { 63 | path: '/service', 64 | component: service 65 | }, 66 | { 67 | path: '/setting', 68 | component: setting 69 | }, 70 | { 71 | path: '/message', 72 | component: message 73 | }, 74 | { 75 | path: '/collect', 76 | component: collect 77 | } 78 | ] 79 | }) 80 | new Vue({ 81 | router, 82 | store, 83 | i18n, 84 | template: '
    ', 85 | components: { 86 | myHeader, 87 | app 88 | } 89 | }).$mount('#app') 90 | ``` 91 | 个人中心的src/views/center/pages/collect/index.vue 92 | ``` 93 | 100 | 106 | ``` 107 | src/components/common/list-bottom.vue 108 | ``` 109 | 112 | 123 | 152 | ``` 153 | 后来样式被打包到shoppingCart.css这里去,而个人中心的没有打包到对应的css文件,可能是配置的问题吧,目前把组件的style样式移到common.scss, 但是有点违背组件化的思想 154 | -------------------------------------------------------------------------------- /note/R9_登录拦截.md: -------------------------------------------------------------------------------- 1 | 如果需要登陆的话进入token判断,然后判断token是否存在, 否者进去next()相当于放行进入页面 2 | 3 | 登录拦截有两个方面 4 | 5 | - 进入对应需要登录的路由,需要拦截,没有token要跳转到登录页面 6 | 7 | - 需要登录接口token发生过期/超时/失效等问题,跳转到登录页面 8 | -------------------------------------------------------------------------------- /note/byluchanan.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/note/byluchanan.docx -------------------------------------------------------------------------------- /note/vue生命周期来解释为什么vue-awesome-swiper插件中length=0.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/note/vue生命周期来解释为什么vue-awesome-swiper插件中length=0.docx -------------------------------------------------------------------------------- /note/消息列表使用vuex来获取数据工作流程.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/note/消息列表使用vuex来获取数据工作流程.docx -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-multi-page", 3 | "version": "1.0.0", 4 | "description": "Vue 多页面开发", 5 | "author": "“yluchanan <“398778994@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "unit": "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/specs test/e2e/specs" 14 | }, 15 | "keywords": [ 16 | "vue", 17 | "es6", 18 | "multi-page", 19 | "webpack" 20 | ], 21 | "license": "ISC", 22 | "devDependencies": { 23 | "autoprefixer": "^6.5.1", 24 | "axios": "^0.15.3", 25 | "babel-core": "^6.18.0", 26 | "babel-eslint": "^7.0.0", 27 | "babel-loader": "^6.2.7", 28 | "babel-plugin-transform-runtime": "^6.15.0", 29 | "babel-preset-es2015": "^6.18.0", 30 | "babel-preset-stage-2": "^6.18.0", 31 | "babel-register": "^6.0.0", 32 | "chai": "^3.5.0", 33 | "chromedriver": "^2.21.2", 34 | "connect-history-api-fallback": "^1.1.0", 35 | "cross-spawn": "^4.0.2", 36 | "css-loader": "^0.25.0", 37 | "eslint": "^3.7.1", 38 | "eslint-config-standard": "^6.1.0", 39 | "eslint-friendly-formatter": "^2.0.5", 40 | "eslint-loader": "^1.5.0", 41 | "eslint-plugin-html": "^1.3.0", 42 | "eslint-plugin-promise": "latest", 43 | "eslint-plugin-standard": "^2.0.1", 44 | "eventsource-polyfill": "^0.9.6", 45 | "exports-loader": "^0.6.4", 46 | "expose-loader": "^0.7.1", 47 | "express": "^4.14.0", 48 | "extract-loader": "0.0.2", 49 | "extract-text-webpack-plugin": "^1.0.1", 50 | "file-loader": "^0.9.0", 51 | "function-bind": "^1.0.2", 52 | "glob": "^7.1.1", 53 | "html-loader": "^0.4.4", 54 | "html-webpack-plugin": "^2.24.1", 55 | "http-proxy-middleware": "^0.17.2", 56 | "imports-loader": "^0.6.5", 57 | "inject-loader": "^2.0.1", 58 | "iscroll": "^5.2.0", 59 | "isparta-loader": "^2.0.0", 60 | "jquery": "^2.2.4", 61 | "json-loader": "^0.5.4", 62 | "karma": "^1.3.0", 63 | "karma-coverage": "^1.1.1", 64 | "karma-mocha": "^1.2.0", 65 | "karma-phantomjs-launcher": "^1.0.0", 66 | "karma-sinon-chai": "^1.2.0", 67 | "karma-sourcemap-loader": "^0.3.7", 68 | "karma-spec-reporter": "0.0.26", 69 | "karma-webpack": "^1.7.0", 70 | "lolex": "^1.4.0", 71 | "mint-ui": "^2.2.5", 72 | "mocha": "^3.1.0", 73 | "nightwatch": "^0.9.8", 74 | "node-sass": "^4.11.0", 75 | "opn": "^4.0.2", 76 | "ora": "^0.3.0", 77 | "phantomjs-prebuilt": "^2.1.3", 78 | "postcss-loader": "^1.1.0", 79 | "sass-loader": "^7.1.0", 80 | "script-loader": "^0.7.0", 81 | "selenium-server": "2.53.1", 82 | "shelljs": "^0.7.5", 83 | "sinon": "^1.17.3", 84 | "sinon-chai": "^2.8.0", 85 | "style-loader": "^0.13.1", 86 | "url-loader": "^0.5.7", 87 | "vue-awesome-swiper": "^2.2.9", 88 | "vue-bus": "^0.3.0", 89 | "vue-cookie": "^1.1.4", 90 | "vue-i18n": "^6.1.1", 91 | "vue-iscroll-view": "^1.0.0", 92 | "vue-lazyload": "^0.9.3", 93 | "vue-loader": "^9.7.0", 94 | "vue-mugen-scroll": "^0.2.1", 95 | "vue-resource": "^1.0.3", 96 | "vue-router": "^2.0.1", 97 | "vue-style-loader": "^1.0.0", 98 | "vuex": "^2.1.1", 99 | "webpack": "^1.13.3", 100 | "webpack-dev-middleware": "^1.8.3", 101 | "webpack-dev-server": "^1.16.2", 102 | "webpack-hot-middleware": "^2.12.2", 103 | "webpack-merge": "^0.15.0" 104 | }, 105 | "dependencies": { 106 | "mockjs": "^1.0.1-beta3", 107 | "vue": "^2.0.1", 108 | "vue-resource": "^1.0.3" 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/assets/css/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/css/.gitkeep -------------------------------------------------------------------------------- /src/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/fonts/.gitkeep -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1497016987732'); /* IE9*/ 4 | src: url('iconfont.eot?t=1497016987732#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('iconfont.woff?t=1497016987732') format('woff'), /* chrome, firefox */ 6 | url('iconfont.ttf?t=1497016987732') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1497016987732#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-arrow:before { content: "\e604"; } 19 | 20 | -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/fonts/iconfont.eot -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Created by FontForge 20120731 at Fri Jun 9 22:03:07 2017 6 | By admin 7 | 8 | 9 | 10 | 24 | 26 | 28 | 30 | 32 | 34 | 38 | 42 | 47 | 50 | 52 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/fonts/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/fonts/iconfont.woff -------------------------------------------------------------------------------- /src/assets/images/icon/arrow_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/arrow_right.png -------------------------------------------------------------------------------- /src/assets/images/icon/cart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/cart.png -------------------------------------------------------------------------------- /src/assets/images/icon/checkbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/checkbox.png -------------------------------------------------------------------------------- /src/assets/images/icon/checkbox_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/checkbox_on.png -------------------------------------------------------------------------------- /src/assets/images/icon/destination.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/destination.png -------------------------------------------------------------------------------- /src/assets/images/icon/destination_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/destination_on.png -------------------------------------------------------------------------------- /src/assets/images/icon/dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/dot.png -------------------------------------------------------------------------------- /src/assets/images/icon/dot_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/dot_on.png -------------------------------------------------------------------------------- /src/assets/images/icon/header_right_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/header_right_edit.png -------------------------------------------------------------------------------- /src/assets/images/icon/home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/home.png -------------------------------------------------------------------------------- /src/assets/images/icon/home_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/home_on.png -------------------------------------------------------------------------------- /src/assets/images/icon/lazy_load_fail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/lazy_load_fail.png -------------------------------------------------------------------------------- /src/assets/images/icon/lazy_load_loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/lazy_load_loading.png -------------------------------------------------------------------------------- /src/assets/images/icon/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/loading.gif -------------------------------------------------------------------------------- /src/assets/images/icon/my.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/my.png -------------------------------------------------------------------------------- /src/assets/images/icon/my_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/my_on.png -------------------------------------------------------------------------------- /src/assets/images/icon/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/search.png -------------------------------------------------------------------------------- /src/assets/images/icon/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/images/icon/service.png -------------------------------------------------------------------------------- /src/assets/js/base.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import $ from 'jquery' 3 | import Common from './common' 4 | import wx from 'wx' 5 | import Mint from 'mint-ui'; 6 | import VueI18n from 'vue-i18n' 7 | import VueLazyload from 'vue-lazyload' 8 | import VueRouter from 'vue-router' 9 | import VueCookie from 'vue-cookie' 10 | Vue.use(VueCookie) 11 | Vue.use(VueRouter) 12 | Vue.use(VueLazyload) 13 | Vue.use(Mint) 14 | Vue.use(VueI18n) 15 | import mock from 'js/mock/index' 16 | import cn from '../locales/zh-CN.json' 17 | import en from '../locales/en-US.json' 18 | const messages = { 19 | 'zh-CN': cn, 20 | 'en-US': en 21 | } 22 | const i18n = new VueI18n({ 23 | locale: 'zh-CN', 24 | messages 25 | }) 26 | 27 | // 导入全局css,scss路径在webpack.base.config.js配置了别名 28 | require('scss/common.scss') 29 | import 'mint-ui/lib/style.css'; 30 | module.exports = { 31 | Vue, $, Common, wx, i18n, VueRouter 32 | } 33 | -------------------------------------------------------------------------------- /src/assets/js/common.js: -------------------------------------------------------------------------------- 1 | const Common = { 2 | isLogin: () => { 3 | if (window.localStorage.getItem('userInfo') == null) { 4 | return false 5 | } 6 | return true 7 | }, 8 | hasDeviceId: false, 9 | index2PageCount: (index, count) => Math.ceil(index / (count || 10)), // return lastIndex转总页数 10 | goBack: () => { 11 | window.history.go(-1) 12 | } 13 | } 14 | // 使用:Common.isLogin 15 | module.exports = Common 16 | // 使用Common.Common.isLogin 17 | /* export default { 18 | // Common: Common缩写 19 | Common 20 | } */ 21 | -------------------------------------------------------------------------------- /src/assets/js/config.js: -------------------------------------------------------------------------------- 1 | const APP_NAME = 'App Name'; 2 | 3 | export default { 4 | APP_NAME 5 | } -------------------------------------------------------------------------------- /src/assets/js/filters.js: -------------------------------------------------------------------------------- 1 | const filters = { 2 | toFriendlyTime: function (timestamp) { 3 | // var nowTimestamp = Math.round(new Date().getTime() / 1000)// js返回的是毫秒数,现转为秒 4 | var nowTimestamp = 1469695314;// 2016-7-28 16:41:54 5 | var distance = nowTimestamp - timestamp;// 相差的时间,秒 6 | var getday = parseInt(distance / 86400);// 多少天 7 | var timeFriendly = ''; 8 | if (getday >= 180) { 9 | if (getday <= 360) { 10 | timeFriendly = '半年前' 11 | } else { 12 | timeFriendly = Math.ceil(getday / 360) + '年前' 13 | } 14 | } else if (getday > 30) { 15 | timeFriendly = parseInt(getday / 30) + '个月前' 16 | } else if (getday >= 7 && getday <= 30) { 17 | timeFriendly = parseInt(getday / 7) + '周前' 18 | } else if (distance < 30) { 19 | timeFriendly = '刚刚'; 20 | } else if (distance < 60) { 21 | timeFriendly = Math.floor(distance) + '秒前' 22 | } else if (distance < 3600) { 23 | timeFriendly = Math.floor(distance / 60) + '分钟前'; 24 | } else if (distance < 86400) { 25 | // 小于1天 26 | timeFriendly = Math.floor(distance / 3600) + '小时前' 27 | } else if (distance < 604800) { 28 | // 小于7天 29 | if (getday < 2) { 30 | timeFriendly = '昨天' 31 | } else if (getday < 3) { 32 | timeFriendly = '前天' 33 | } else { 34 | timeFriendly = getday + '天前' 35 | } 36 | } 37 | return timeFriendly 38 | } 39 | } 40 | module.exports = filters 41 | -------------------------------------------------------------------------------- /src/assets/js/lib/calendar/calendar.js: -------------------------------------------------------------------------------- 1 | const name = 'This is a Calendar Plugin' 2 | 3 | export default { 4 | name 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/js/lib/calendar/calendar.scss: -------------------------------------------------------------------------------- 1 | .calendar { 2 | border: 1px solid pink; 3 | } -------------------------------------------------------------------------------- /src/assets/js/mock/center/index.js: -------------------------------------------------------------------------------- 1 | // 个人中心api 2 | import waitForCommentList from 'js/mock/center/waitForCommentList' 3 | let Center = [] 4 | Center.push(waitForCommentList) 5 | export default Center 6 | -------------------------------------------------------------------------------- /src/assets/js/mock/center/waitForCommentList.js: -------------------------------------------------------------------------------- 1 | 2 | import Mock from 'mockjs' 3 | const waitForCommentList = { 4 | path: '/center/waitForCommentList', 5 | data: { 6 | 'error_code': 1000, 7 | 'error_msg': 'ok', 8 | 'execute_time|1-10': 1, 9 | 'comment_list|10': [{ // 每次返回10条数据 10 | 'product_name': '@cparagraph()', // 随机生成一个随机文本 11 | 'id|+1': 1000, // 1000开始,每次+1自增 12 | 'order_date': '@datetime()' 13 | }], 14 | 'last_index|+10': 9, // 从9开始,每次请求index+10 15 | 'total_index': 31 // 31/10, 共4页 16 | } 17 | } 18 | 19 | export default waitForCommentList 20 | -------------------------------------------------------------------------------- /src/assets/js/mock/index.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | import shopping from 'js/mock/shopping' 3 | import center from 'js/mock/center/index' 4 | function addToMock (api) { 5 | api.forEach(item => { 6 | Mock.mock(item.path, item.data) 7 | }) 8 | } 9 | addToMock(shopping) 10 | addToMock(center) 11 | export default Mock 12 | -------------------------------------------------------------------------------- /src/assets/js/mock/shopping.js: -------------------------------------------------------------------------------- 1 | import Mock from 'mockjs' 2 | const shopping = [ 3 | { 4 | path: '/center/waitForCommentList', 5 | data: { 6 | 'error_code|1': ['0000', '1000'], 7 | 'error_msg': function () { 8 | const errorCode = this.error_code 9 | let errorMsg = '' 10 | switch (errorCode) { 11 | case '0000': 12 | errorMsg = '删除成功' 13 | break 14 | case '1000': 15 | errorMsg = '删除失败' 16 | break 17 | default: 18 | errorMsg = '未知错误' 19 | } 20 | return errorMsg 21 | }, 22 | 'execute_time|1-10': 1 23 | } 24 | } 25 | ] 26 | 27 | export default shopping 28 | -------------------------------------------------------------------------------- /src/assets/js/tools.js: -------------------------------------------------------------------------------- 1 | // image load 2 | const preloadImg = function (path) { 3 | return new Promise((resolve, reject) => { 4 | let img = new Image(); 5 | img.onload = resolve; 6 | img.onerror = reject; 7 | img.src = path; 8 | }) 9 | } 10 | 11 | export default{ 12 | preloadImg 13 | } -------------------------------------------------------------------------------- /src/assets/locales/en-US.json: -------------------------------------------------------------------------------- 1 | { 2 | "setting": { 3 | "topTitle": "setting", 4 | "share": "share friends", 5 | "advice": "advice", 6 | "changeLanguage": "change language", 7 | "logout": "log out" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/locales/zh-CN.json: -------------------------------------------------------------------------------- 1 | { 2 | "setting": { 3 | "topTitle": "设置", 4 | "share": "告诉朋友", 5 | "advice": "意见反馈", 6 | "changeLanguage": "切换语言", 7 | "logout": "退出登录" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/scss/base/_common.scss: -------------------------------------------------------------------------------- 1 | html *{ 2 | box-sizing:border-box; 3 | -webkit-tap-highlight-color: rgba(0,0,0,0); 4 | outline: 0; 5 | text-size-adjust: none; 6 | } 7 | html,body{ 8 | background-color: $color_F3F5F8; 9 | } 10 | body{ 11 | width:px2rem(750);/*设计稿大小*/ 12 | line-height: 1.5; 13 | margin:0 auto; 14 | word-break: break-all; 15 | word-wrap: break-word; 16 | } 17 | a{ 18 | text-decoration: none; 19 | display:block; 20 | } 21 | input[type="password"],input[type="text"],input[type="button"],input[type="submit"],input[type="reset"],input[type="file"]::-webkit-file-upload-button,button,select,textarea{ 22 | -webkit-appearance:none; 23 | appearance:none; 24 | border: none; 25 | border-radius: 0; 26 | } 27 | input:-ms-input-placeholder,textarea:-ms-input-placeholder{ 28 | color:$color_9E9E9E; 29 | } 30 | input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{ 31 | color:$color_9E9E9E; 32 | } 33 | input::-moz-placeholder,textarea::-moz-placeholder{ 34 | color: $color_9E9E9E; 35 | } 36 | img, embed, object, video, iframe { 37 | max-width:100% !important; 38 | } 39 | -------------------------------------------------------------------------------- /src/assets/scss/base/_cssreset.scss: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font: inherit; 18 | font-size: 100%; 19 | vertical-align: baseline; 20 | } 21 | 22 | html { 23 | line-height: 1; 24 | } 25 | 26 | ol, ul { 27 | list-style: none; 28 | } 29 | 30 | table { 31 | border-collapse: collapse; 32 | border-spacing: 0; 33 | } 34 | 35 | caption, th, td { 36 | text-align: left; 37 | font-weight: normal; 38 | vertical-align: middle; 39 | } 40 | 41 | q, blockquote { 42 | quotes: none; 43 | } 44 | q:before, q:after, blockquote:before, blockquote:after { 45 | content: ""; 46 | content: none; 47 | } 48 | 49 | a img { 50 | border: none; 51 | } 52 | 53 | article, aside, details, figcaption, figure, footer, header, hgroup, main, menu, nav, section, summary { 54 | display: block; 55 | } -------------------------------------------------------------------------------- /src/assets/scss/base/_extend.scss: -------------------------------------------------------------------------------- 1 | .fixed{ 2 | position: fixed; 3 | left: 0; 4 | width: 100%; 5 | } 6 | %pink{ 7 | color: $color_FC5D7B; 8 | } 9 | .relative{ 10 | position: relative; 11 | } 12 | .bg_white{ 13 | background: $white; 14 | } 15 | .pointer{ 16 | cursor:pointer; 17 | } 18 | .block{ 19 | display: block; 20 | } 21 | .none{ 22 | display: none; 23 | } 24 | .inline_block{ 25 | display: inline-block; 26 | } 27 | .cover{ 28 | background-size:cover important(); 29 | } 30 | .contain{ 31 | background-size:contain important(); 32 | } 33 | .clearfix:after { 34 | content: ""; 35 | display: block; 36 | height: 0; 37 | clear: both; 38 | visibility: hidden; 39 | } 40 | .clearfix{ 41 | zoom: 1; 42 | } 43 | .float_left{ 44 | float:left; 45 | } 46 | .float_right{ 47 | float:right; 48 | } 49 | .padding_l_r_24{ 50 | padding:0 px2rem(24); 51 | } 52 | .padding_24{ 53 | padding:px2rem(24); 54 | } 55 | .padding_b_120{ 56 | padding-bottom: px2rem(120); 57 | } 58 | .padding_t_122{ 59 | padding-top: px2rem(120); 60 | } 61 | .padding_tb_120{ 62 | padding: px2rem(122) 0 px2rem(120) 0; 63 | } 64 | 65 | .padding_tb_100{ 66 | padding: px2rem(122) 0 px2rem(100) 0; 67 | } 68 | .margin_b_20{ 69 | margin-bottom: px2rem(20); 70 | } 71 | .text_center{ 72 | text-align: center; 73 | } 74 | .text_right{ 75 | text-align: right; 76 | } 77 | .flex{ 78 | display: flex; 79 | &.flex_v_center{ 80 | align-items:center; 81 | } 82 | .flex_item{ 83 | flex: 1; 84 | } 85 | } 86 | .xoverflow_scroll{ 87 | overflow-x: auto; 88 | -webkit-overflow-scrolling: touch; 89 | } 90 | -------------------------------------------------------------------------------- /src/assets/scss/base/_footer.scss: -------------------------------------------------------------------------------- 1 | .footer{ 2 | @extend .fixed; 3 | border-top: solid 1px $color_DBDBDB; 4 | background: $white; 5 | bottom: 0; 6 | li{ 7 | float: left; 8 | width: 25%; 9 | padding: px2rem(17) 0; 10 | a{ 11 | &:before{ 12 | content: attr(data-font); 13 | padding-top:px2rem(46); 14 | display: block; 15 | @include px2px(font-size,20); 16 | text-align: center; 17 | color:$color_9E9E9E; 18 | background: url(../images/icon/home.png) no-repeat top center; 19 | @include bg_size_px(36); 20 | line-height: 1; 21 | } 22 | &.on{ 23 | &:before{ 24 | background: url(../images/icon/home_on.png) no-repeat top center; 25 | @include bg_size_px(36); 26 | color: $color_55C1DD; 27 | } 28 | &.destination{ 29 | &:before{ 30 | background-image: url(../images/icon/destination_on.png); 31 | } 32 | } 33 | &.my{ 34 | &:before{ 35 | background-image: url(../images/icon/my_on.png); 36 | } 37 | } 38 | } 39 | &.destination{ 40 | &:before{ 41 | background-image: url(../images/icon/destination.png); 42 | } 43 | } 44 | &.cart{ 45 | @extend .relative; 46 | &:before{ 47 | background-image: url(../images/icon/cart.png); 48 | } 49 | &[data-count]:after{ 50 | content: attr(data-count); 51 | position: absolute; 52 | right:50%; 53 | margin-right: px2rem(-48); 54 | top:px2rem(-10); 55 | font-size:px2rem(18); 56 | width: px2rem(36); 57 | height: px2rem(24); 58 | line-height:px2rem(24); 59 | text-align: center; 60 | border-radius:px2rem(20); 61 | color: #fff; 62 | background:$color_FC5D7B; 63 | @extend .inline_block; 64 | } 65 | &[data-count='0']:after{ 66 | display:none; 67 | } 68 | } 69 | &.my{ 70 | &:before{ 71 | background-image: url(../images/icon/my.png); 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/assets/scss/base/_function.scss: -------------------------------------------------------------------------------- 1 | /* 2 | iphone3gs: 320px / 10 = 32px 3 | iphone4/5: 320px * 2 / 10 = 64px 4 | iphone6: 375px * 2 / 10 = 75px 5 | iphone6+: 414px * 3 / 10 = 124.2px 6 | */ 7 | $rem:75;/*基准数也就是html,font-size有关:设计稿大小为640,转变就是拿设计稿的实际距离除以基准数*/ 8 | /*除了字体或者特殊要求需要用到的*/ 9 | @function px2rem($px){ 10 | @return ($px/$rem)*1rem; 11 | } 12 | 13 | @function important(){ 14 | @return !important; 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/assets/scss/base/_header.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/assets/scss/base/_header.scss -------------------------------------------------------------------------------- /src/assets/scss/base/_mixin.scss: -------------------------------------------------------------------------------- 1 | /*针对字体*/ 2 | @mixin px2px($name, $px) { 3 | #{$name}: round($px / 2) * 1px; 4 | [data-dpr="2"] & { 5 | #{$name}: $px * 1px; 6 | } 7 | [data-dpr="2.5"] & { 8 | #{$name}: round($px * 2.5 / 2) * 1px; 9 | } 10 | [data-dpr="2.75"] & { 11 | #{$name}: round($px * 2.75 / 2) * 1px; 12 | } 13 | [data-dpr="3"] & { 14 | #{$name}: round($px / 2 * 3) * 1px 15 | } 16 | [data-dpr="4"] & { 17 | #{$name}: $px * 2px; 18 | } 19 | } 20 | 21 | /*图片媒体查询*/ 22 | @mixin retina($url) { 23 | background-image: url($url+ '.png'); 24 | [data-dpr="2"] & { 25 | background-image: url($url+ '@2x.png'); 26 | } 27 | [data-dpr="3"] & { 28 | background-image: url($url+ '@3x.png'); 29 | } 30 | } 31 | 32 | /*多行文字省略号*/ 33 | @mixin clamp($num) { 34 | overflow: hidden; 35 | text-overflow: ellipsis; 36 | display: -webkit-box; 37 | -webkit-line-clamp: $num; 38 | -webkit-box-orient: vertical; 39 | } 40 | 41 | /*background-size rem数值转换*/ 42 | @mixin bg_size_rem($x:auto,$y:auto) { 43 | @if $x==auto{ 44 | $x:auto; 45 | } @else { 46 | $x:px2rem($x); 47 | } 48 | @if $y==auto{ 49 | $y:auto; 50 | } @else { 51 | $y:px2rem($y); 52 | } 53 | background-size: ($x, $y); 54 | } 55 | 56 | /*background-size px数值转换*/ 57 | @mixin bg_size_px($x:auto,$y:auto) { 58 | @if $x==auto{ 59 | $x:auto; 60 | } @else { 61 | $x:px2rem($x); 62 | } 63 | @if $y==auto{ 64 | $y:auto; 65 | } @else { 66 | $y:px2rem($y); 67 | } 68 | background-size: ($x, $y); 69 | } 70 | 71 | /*多行文字省略号*/ 72 | @mixin padding_top($num:102) { 73 | padding-top: px2rem($num); 74 | } 75 | 76 | @mixin padding_bottom($num:120) { 77 | padding-bottom: px2rem($num); 78 | } 79 | 80 | -------------------------------------------------------------------------------- /src/assets/scss/base/_necessary.scss: -------------------------------------------------------------------------------- 1 | @import "variable.scss"; 2 | @import "function.scss"; 3 | @import "mixin.scss"; 4 | @import "extend.scss"; 5 | -------------------------------------------------------------------------------- /src/assets/scss/base/_variable.scss: -------------------------------------------------------------------------------- 1 | $white:#fff; 2 | $color_55C1DD:#55C1DD; 3 | $color_424242:#424242; 4 | $color_9E9E9E:#9E9E9E; 5 | $color_FC5D7B:#FC5D7B; 6 | $color_DBDBDB:#DBDBDB; 7 | $color_F3F5F8:#F3F5F8; 8 | $color_E1E9F0:#E1E9F0; 9 | $color_8FA0B1:#8FA0B1; 10 | 11 | -------------------------------------------------------------------------------- /src/assets/scss/common.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import "base/cssreset.scss"; 3 | @import "base/necessary.scss"; 4 | @import "base/common.scss"; 5 | @import "base/header.scss"; 6 | @import "base/footer.scss"; 7 | /*warn begin:这里原本来要放在_extend.scss里面的,但是由于home.scss import _necessary.scss 而_necessary.scss import _extend.scss,导致背景图片路径怎么相对都是错误的, 8 | 现在的解决方法是涉及图片路径的都放在这里,暂时过度,待找到原因 9 | */ 10 | .swiper-container{ 11 | /*padding-top:66.66666666666667%;/*500/700*/ 12 | height: px2rem(500); 13 | overflow: hidden; 14 | a{ 15 | width: 100%; 16 | height: 100%; 17 | } 18 | .swiper-pagination{ 19 | &.swiper-pagination-bullets{ 20 | bottom: px2rem(20); 21 | .swiper-pagination-bullet{ 22 | vertical-align: bottom; 23 | width: px2rem(10); 24 | height:px2rem(10); 25 | margin:0 px2rem(10) 0 0 important(); 26 | opacity: 1; 27 | background:url(../images/icon/dot.png) scroll no-repeat center center important(); 28 | @extend .contain; 29 | &.swiper-pagination-bullet-active{ 30 | background:url(../images/icon/dot_on.png) scroll no-repeat center center important(); 31 | @extend .contain; 32 | } 33 | } 34 | } 35 | } 36 | } 37 | /*lazyload*/ 38 | /*background lazyload style*/ 39 | .bg_lazyload{ 40 | &[lazy=loading]{ 41 | background:url(../images/icon/lazy_load_loading.png) scroll no-repeat center center important(); 42 | background-size: px2rem(159) important(); 43 | } 44 | &[lazy=error]{ 45 | background:url(../images/icon/lazy_load_fail.png) scroll no-repeat center center important(); 46 | background-size: px2rem(138) important(); 47 | } 48 | &[lazy=loaded]{ 49 | @extend .cover; 50 | height: 100%; 51 | } 52 | } 53 | /*img lazyload style*/ 54 | .img_lazyload{ 55 | &[lazy=loading]{ 56 | background:url(../images/icon/lazy_load_loading.png) scroll no-repeat center center important(); 57 | background-size: px2rem(159) important(); 58 | } 59 | &[lazy=error]{ 60 | 61 | } 62 | &[lazy=loaded]{ 63 | 64 | } 65 | } 66 | /*lazyload*/ 67 | .arrow_right{ 68 | &:after{ 69 | content:''; 70 | display: inline-block; 71 | position:absolute; 72 | right:0; 73 | top:50%; 74 | margin-top: px2rem(-12); 75 | width:px2rem(15); 76 | height:px2rem(25); 77 | background: url(../images/icon/arrow_right.png) scroll no-repeat center center; 78 | @extend .contain; 79 | } 80 | } 81 | .checkbox_wrap{ 82 | &.select_all span:after{ 83 | content:'全选'; 84 | display:inline-block; 85 | width: px2rem(100); 86 | text-align: left; 87 | position: absolute; 88 | top:0; 89 | left: px2rem(60); 90 | line-height: px2rem(40); 91 | @include px2px(font-size,30) 92 | } 93 | padding-right: px2rem(24); 94 | .checkbox_label{ 95 | display: inline-block; 96 | vertical-align:top; 97 | line-height: 1; 98 | position: relative; 99 | width:px2rem(40); 100 | height: 100%; 101 | input{ 102 | @extend .none; 103 | &:checked + span:before{ 104 | background: url(../images/icon/checkbox_on.png) scroll no-repeat center center; 105 | @include bg_size_rem(40); 106 | } 107 | } 108 | span{ 109 | width:100%; 110 | height:px2rem(40); 111 | display: inline-block; 112 | position: absolute; 113 | left: 0; 114 | top: 50%; 115 | margin-top: px2rem(-20); 116 | &:before{ 117 | content:''; 118 | width:100%; 119 | height:100%; 120 | display:inline-block; 121 | background: url(../images/icon/checkbox.png) scroll no-repeat center center; 122 | @include bg_size_rem(40); 123 | } 124 | } 125 | } 126 | } 127 | /*warn end*/ 128 | .list_bottom{ 129 | padding: px2rem(30) px2rem(24); 130 | @extend .text_center; 131 | color:$color_9E9E9E; 132 | @extend .relative; 133 | @include px2px(line-height,32); 134 | @include px2px(font-size,28); 135 | span{ 136 | &.finished{ 137 | &:before{ 138 | @extend .none; 139 | } 140 | } 141 | &:before{ 142 | content: ''; 143 | @extend .inline_block; 144 | @include px2px(width,32); 145 | @include px2px(height,32); 146 | background: url(../../assets/images/icon/loading.gif) scroll no-repeat center center; 147 | @extend .contain; 148 | vertical-align: top; 149 | margin-right: px2rem(10); 150 | } 151 | } 152 | } 153 | 154 | -------------------------------------------------------------------------------- /src/components/common/footer.vue: -------------------------------------------------------------------------------- 1 | 11 | 38 | -------------------------------------------------------------------------------- /src/components/common/list-bottom.vue: -------------------------------------------------------------------------------- 1 | 4 | 15 | 43 | -------------------------------------------------------------------------------- /src/components/common/search-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 13 | 24 | -------------------------------------------------------------------------------- /src/components/common/service-icon.vue: -------------------------------------------------------------------------------- 1 | 4 | 13 | 24 | -------------------------------------------------------------------------------- /src/components/home/home-banner.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | 16 | 18 | -------------------------------------------------------------------------------- /src/components/home/home-header.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 24 | 25 | 33 | -------------------------------------------------------------------------------- /src/components/home/home-topic.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 16 | 17 | 19 | -------------------------------------------------------------------------------- /src/components/my/images/back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/components/my/images/back.png -------------------------------------------------------------------------------- /src/components/my/images/message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/components/my/images/message.png -------------------------------------------------------------------------------- /src/components/my/images/search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/components/my/images/search.png -------------------------------------------------------------------------------- /src/components/my/images/setting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/components/my/images/setting.png -------------------------------------------------------------------------------- /src/views/center/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 27 | -------------------------------------------------------------------------------- /src/views/center/app.js: -------------------------------------------------------------------------------- 1 | import { Vue, VueRouter, i18n } from 'js/base' 2 | import myHeader from '../../components/my/my-header.vue' 3 | import store from '../../vuex/store' 4 | import app from './App.vue' 5 | const beComment = resolve => require(['./pages/becomment'], resolve) 6 | const my = resolve => require(['./pages/my'], resolve) 7 | const service = resolve => require(['./pages/service'], resolve) 8 | const setting = resolve => require(['./pages/setting'], resolve) 9 | const message = resolve => require(['./pages/message'], resolve) 10 | const collect = resolve => require(['./pages/collect'], resolve) 11 | import './scss/center.scss' 12 | // 个人中心router 13 | const router = new VueRouter({ 14 | routes: [ 15 | { 16 | path: '/', 17 | component: my 18 | }, 19 | { 20 | path: '/becomment', 21 | component: beComment, 22 | meta: { 23 | requireAuth: true // 进入路由需要登录 24 | } 25 | }, 26 | { 27 | path: '/service', 28 | component: service 29 | }, 30 | { 31 | path: '/setting', 32 | component: setting 33 | }, 34 | { 35 | path: '/message', 36 | component: message 37 | }, 38 | { 39 | path: '/collect', 40 | component: collect 41 | } 42 | ] 43 | }) 44 | // to do登录拦截 45 | router.beforeEach((to, from, next) => { 46 | if (to.meta.requireAuth) { 47 | console.log(store.state.common.token) 48 | if (store.state.common.token !== null) { 49 | next() 50 | } else { 51 | // token没有进入登录页面 52 | next({ 53 | path: '/login', 54 | query: {redirect: to.fullPath} // 将跳转的路由path作为参数,登录成功后跳转到该路由 55 | }) 56 | } 57 | } else { 58 | // 不需要登录, 一定要,否者进入不了路由 59 | next() 60 | } 61 | }) 62 | new Vue({ 63 | router, 64 | store, 65 | i18n, 66 | template: '
    ', 67 | components: { 68 | myHeader, 69 | app 70 | } 71 | }).$mount('#app') 72 | -------------------------------------------------------------------------------- /src/views/center/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 我的 7 | 8 | 9 |
    10 |
    11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/views/center/pages/becomment/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 83 | 111 | -------------------------------------------------------------------------------- /src/views/center/pages/collect/index.vue: -------------------------------------------------------------------------------- 1 | 25 | 90 | -------------------------------------------------------------------------------- /src/views/center/pages/message/index.vue: -------------------------------------------------------------------------------- 1 | 19 | 75 | 124 | -------------------------------------------------------------------------------- /src/views/center/pages/my/images/all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/all.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/collect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/collect.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/comment.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/hotel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/hotel.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/logined.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/logined.jpg -------------------------------------------------------------------------------- /src/views/center/pages/my/images/nologin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/nologin.jpg -------------------------------------------------------------------------------- /src/views/center/pages/my/images/paying.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/paying.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/service.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/taobao.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/taobao.png -------------------------------------------------------------------------------- /src/views/center/pages/my/images/traveller.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/images/traveller.png -------------------------------------------------------------------------------- /src/views/center/pages/my/index.vue: -------------------------------------------------------------------------------- 1 | 64 | 105 | -------------------------------------------------------------------------------- /src/views/center/pages/my/scss/my.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/my/scss/my.scss -------------------------------------------------------------------------------- /src/views/center/pages/service/images/tel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/center/pages/service/images/tel.png -------------------------------------------------------------------------------- /src/views/center/pages/service/index.vue: -------------------------------------------------------------------------------- 1 | 16 | 27 | 93 | -------------------------------------------------------------------------------- /src/views/center/pages/setting/index.vue: -------------------------------------------------------------------------------- 1 | 37 | 66 | -------------------------------------------------------------------------------- /src/views/center/scss/collect.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import "../../../assets/scss/base/necessary.scss"; 3 | $color_e1e9f0:#e1e9f0; 4 | .collect{ 5 | a{ 6 | color: $color_424242; 7 | } 8 | li{ 9 | @include px2px(font-size,30); 10 | border-bottom: solid 1px $color_E1E9F0; 11 | &:last-child{ 12 | border-bottom: none; 13 | } 14 | h1{ 15 | @include clamp(2); 16 | } 17 | } 18 | .itemInfo{ 19 | /* flex 纵向从上往下排列,用于上面是标题,底部是价格类似情况*/ 20 | justify-content: space-between; 21 | flex-direction: column; 22 | } 23 | .bottom{ 24 | align-items: baseline; 25 | @include px2px(font-size,24); 26 | .price{ 27 | @include px2px(font-size,32); 28 | color:$color_FC5D7B; 29 | &:before{ 30 | content: '¥'; 31 | display: inline-block; 32 | margin-right: px2rem(7); 33 | @include px2px(font-size,22); 34 | vertical-align: baseline; 35 | } 36 | } 37 | .num{ 38 | color:$color_9E9E9E; 39 | } 40 | } 41 | .bg_lazyload{ 42 | width:px2rem(184); 43 | height:px2rem(184); 44 | margin-right: px2rem(20); 45 | img{ 46 | width:100%; 47 | height: 100%; 48 | } 49 | } 50 | /*购物车列表样式*/ 51 | &.shoppingcart{ 52 | .bg{ 53 | width: px2rem(180); 54 | height: px2rem(180); 55 | } 56 | .sum{ 57 | margin-top: px2rem(4); 58 | color:$color_8FA0B1; 59 | @include px2px(font-size,24); 60 | } 61 | h1{ 62 | @include px2px(font-size,28); 63 | } 64 | .price{ 65 | line-height: 1.2; 66 | } 67 | .mr10{ 68 | margin-right: px2rem(18); 69 | } 70 | .num{ 71 | .mr10:last-child{ 72 | margin: 0; 73 | } 74 | } 75 | .action{ 76 | bottom: 0; 77 | padding: 0 0 0 px2rem(24); 78 | z-index: 9; 79 | .flex_v_center{ 80 | justify-content: space-between; 81 | } 82 | .price{ 83 | @extend %pink; 84 | @include px2px(font-size,30); 85 | margin-right: px2rem(40); 86 | } 87 | .btn{ 88 | background: $color_FC5D7B; 89 | &:disabled{ 90 | background: $color_E1E9F0; 91 | } 92 | @include px2px(font-size,32); 93 | color: $white; 94 | padding: px2rem(29) 0; 95 | width: px2rem(176); 96 | } 97 | .flex_item{ 98 | text-align: right; 99 | } 100 | } 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /src/views/destinationIndex/destinationIndex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 目的地 7 | 8 | 9 |
    10 | 11 |
    12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/views/destinationIndex/destinationIndex.js: -------------------------------------------------------------------------------- 1 | import { Vue, $, Common } from 'js/base' 2 | import store from '../../vuex/store' 3 | require('./scss/destinationIndex.scss') 4 | import myHeader from '../../components/my/my-header.vue' 5 | import destinationIndex from './destinationIndex.vue' 6 | var home = new Vue({ 7 | el: '#destinationIndex', 8 | store, 9 | template: '
    ', 10 | components: { 11 | 'destinationIndex': destinationIndex, 12 | 'my-header': myHeader 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /src/views/destinationIndex/destinationIndex.vue: -------------------------------------------------------------------------------- 1 | 29 | 76 | -------------------------------------------------------------------------------- /src/views/index/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 首页 7 | 8 | 9 |
    10 | 11 |
    12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/views/index/index.js: -------------------------------------------------------------------------------- 1 | import { Vue, $ } from 'js/base' 2 | import store from '../../vuex/store' 3 | import homeHeader from '../../components/home/home-header.vue' 4 | require('./scss/home.scss') 5 | import homeIndex from './index.vue' 6 | var homeVue = new Vue({ 7 | el: '#home', 8 | store, 9 | template: '
    ', 10 | components: { 11 | 'home-index': homeIndex, 12 | 'home-header': homeHeader 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /src/views/index/index.vue: -------------------------------------------------------------------------------- 1 | 52 | 128 | -------------------------------------------------------------------------------- /src/views/index/scss/home.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import "../../../assets/scss/base/necessary.scss"; 3 | html,body{ 4 | background: $white; 5 | } 6 | /*index*/ 7 | .title{ 8 | color:$color_424242; 9 | @include px2px(font-size,40); 10 | line-height: px2rem(40); 11 | padding:px2rem(60) 0 px2rem(34) px2rem(30); 12 | } 13 | .swiper-wrapper { 14 | height: 100%; 15 | } 16 | .item{ 17 | padding-bottom: px2rem(74); 18 | border-bottom: solid 1px $color_DBDBDB; 19 | &.boutique{ 20 | ul{ 21 | height: 100%; 22 | padding-bottom: 0; 23 | } 24 | a{ 25 | width: px2rem(334); 26 | } 27 | .scroll{ 28 | height: px2rem(257); 29 | } 30 | } 31 | &.surprise{ 32 | &.activity{ 33 | .scroll{ 34 | height: px2rem(436); 35 | ul{ 36 | height: px2rem(446); 37 | } 38 | } 39 | } 40 | &.list{ 41 | border-bottom: none; 42 | padding-bottom:0; 43 | .bottom_title{ 44 | .flex{ 45 | padding-bottom: px2rem(14); 46 | } 47 | } 48 | ul{ 49 | padding: 0; 50 | } 51 | .scroll,ul,a{ 52 | height: auto; 53 | width: auto; 54 | } 55 | .bg{ 56 | width: px2rem(690); 57 | height: px2rem(436); 58 | } 59 | li{ 60 | display: block; 61 | margin: 0 0 px2rem(30) 0; 62 | padding: 0 px2rem(30); 63 | &:last-child{ 64 | margin-bottom: 0; 65 | a{ 66 | border-bottom: 0; 67 | } 68 | } 69 | a{ 70 | border-bottom: solid 1px $color_DBDBDB; 71 | } 72 | } 73 | } 74 | .scroll{ 75 | height: px2rem(579); 76 | } 77 | ul{ 78 | height: px2rem(589); 79 | a{ 80 | width: px2rem(655); 81 | height: px2rem(436); 82 | } 83 | } 84 | } 85 | } 86 | .scroll{ 87 | height: px2rem(315); 88 | overflow-y:hidden; 89 | ul{ 90 | height: px2rem(325); 91 | padding:0 0 10px px2rem(7); 92 | white-space: nowrap; 93 | @extend .xoverflow_scroll; 94 | font-size:0; 95 | li{ 96 | display:inline-block; 97 | height: 100%; 98 | margin: 0 px2rem(11); 99 | &:first-child{ 100 | margin-left:px2rem(23); 101 | } 102 | &:last-child{ 103 | margin-right:px2rem(23); 104 | } 105 | a{ 106 | display: block; 107 | width: px2rem(315); 108 | height: 100%; 109 | text-decoration:none; 110 | position:relative; 111 | .bg{ 112 | height: 100%; 113 | } 114 | .text{ 115 | position: absolute; 116 | left:0; 117 | top:0; 118 | width: 100%; 119 | height: 100%; 120 | color: #fff; 121 | @include px2px(font-size,34); 122 | text-align: center; 123 | } 124 | } 125 | 126 | } 127 | } 128 | } 129 | .bottom_title{ 130 | color:$color_424242; 131 | h2{ 132 | line-height: px2rem(42); 133 | max-height: px2rem(84); 134 | @include clamp(2); 135 | padding: px2rem(34) 0 px2rem(11) 0; 136 | @include px2px(font-size,34); 137 | } 138 | .flex{ 139 | color:$color_9E9E9E; 140 | @include px2px(font-size,28); 141 | .flex_item{ 142 | line-height:2; 143 | } 144 | .right{ 145 | text-align: right; 146 | color:$color_FC5D7B; 147 | &:before{ 148 | content: '¥'; 149 | display: inline-block; 150 | margin-right: px2rem(7); 151 | @include px2px(font-size,22); 152 | vertical-align: top; 153 | 154 | } 155 | &:after{ 156 | content: '起'; 157 | display: inline-block; 158 | margin-left: px2rem(5); 159 | @include px2px(font-size,22); 160 | color:$color_9E9E9E; 161 | } 162 | } 163 | } 164 | } 165 | 166 | -------------------------------------------------------------------------------- /src/views/login/images/hr_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/login/images/hr_login.png -------------------------------------------------------------------------------- /src/views/login/images/qq_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/login/images/qq_login.png -------------------------------------------------------------------------------- /src/views/login/images/sina_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/login/images/sina_login.png -------------------------------------------------------------------------------- /src/views/login/images/wechat_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/src/views/login/images/wechat_login.png -------------------------------------------------------------------------------- /src/views/login/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 我的 6 | 7 | 8 |
    9 | 10 |
    11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/views/login/login.js: -------------------------------------------------------------------------------- 1 | import { Vue, $, Common } from 'js/base' 2 | import store from '../../vuex/store' 3 | import myHeader from '../../components/my/my-header.vue' 4 | require('./scss/login.scss') 5 | import login from './login.vue' 6 | var homeVue = new Vue({ 7 | el: '#login', 8 | store, 9 | template: '
    ', 10 | components: { 11 | 'my-header': myHeader, 12 | 'login': login 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /src/views/login/login.vue: -------------------------------------------------------------------------------- 1 | 26 | 87 | -------------------------------------------------------------------------------- /src/views/login/scss/login.scss: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | @import "../../../assets/scss/base/necessary.scss"; 3 | $color_02d1b1:#02d1b1; 4 | .login{ 5 | .tips{ 6 | @include px2px(font-size,30); 7 | color: $color_55C1DD; 8 | padding: 0 px2rem(24) px2rem(20) px2rem(24); 9 | } 10 | .form{ 11 | li{ 12 | border-bottom:solid 1px $color_E1E9F0; 13 | &:last-child{ 14 | border:none; 15 | } 16 | } 17 | } 18 | .text{ 19 | @include px2px(font-size,30); 20 | color:$color_424242; 21 | width: 100%; 22 | padding:px2rem(29) px2rem(24); 23 | } 24 | .link{ 25 | a{ 26 | @include px2px(font-size,26); 27 | @extend .block; 28 | padding: px2rem(24); 29 | color: $color_55C1DD; 30 | } 31 | } 32 | button{ 33 | @include px2px(font-size,34) 34 | width: 100%; 35 | @extend .block; 36 | color: $white; 37 | line-height: px2rem(80); 38 | background: $color_55C1DD; 39 | &:disabled{ 40 | background: $color_E1E9F0; 41 | } 42 | } 43 | .thirdLogin{ 44 | padding:px2rem(90) px2rem(24) 0; 45 | hr{ 46 | height:px2rem(24); 47 | border:none; 48 | background: url(../images/hr_login.png) scroll no-repeat center center; 49 | background-size:contain; 50 | } 51 | .line{ 52 | position:absolute; 53 | top:50%; 54 | height:px2rem(24); 55 | margin-top:px2rem(-12); 56 | width:100%; 57 | line-height: 1; 58 | } 59 | h1{ 60 | color:$color_9E9E9E; 61 | @include px2px(font-size,24); 62 | position:relative; 63 | text-align:center; 64 | span{ 65 | background:$color_F3F5F8; 66 | display:inline-block; 67 | } 68 | } 69 | } 70 | .loginIcon{ 71 | text-align: center; 72 | margin-top:px2rem(50); 73 | li{ 74 | @extend .inline_block; 75 | font-size: 0; 76 | margin-right:px2rem(90); 77 | &:last-child{ 78 | margin-right: 0; 79 | } 80 | } 81 | .icon{ 82 | display:inline-block; 83 | width:px2rem(100); 84 | height:px2rem(100); 85 | border:solid 1px #ccd6e0; 86 | border-radius:50%; 87 | background: url(../images/sina_login.png) scroll no-repeat center center; 88 | background-size:contain; 89 | &:active{ 90 | background-color: #e3eaf1 !important; 91 | } 92 | &:last-child{ 93 | margin-right:0; 94 | } 95 | &.qq{ 96 | background: url(../images/qq_login.png) scroll no-repeat center center; 97 | background-size:contain; 98 | } 99 | &.wechat{ 100 | background: url(../images/wechat_login.png) scroll no-repeat center center; 101 | background-size:contain; 102 | } 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/views/shoppingCart/shoppingCart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 购物车 7 | 8 | 9 |
    10 | 11 |
    12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/views/shoppingCart/shoppingCart.js: -------------------------------------------------------------------------------- 1 | import { Vue, $, Common } from 'js/base' 2 | import myHeader from '../../components/my/my-header.vue' 3 | import store from '../../vuex/store' 4 | require('../center/scss/collect.scss') 5 | import shoppingCart from './shoppingCart.vue' 6 | var homeVue = new Vue({ 7 | el: '#shoppingCart', 8 | store, 9 | template: '
    ', 10 | components: { 11 | 'my-header': myHeader, 12 | 'shopping-cart': shoppingCart 13 | } 14 | }) 15 | -------------------------------------------------------------------------------- /src/vuex/modules/center/becomment.js: -------------------------------------------------------------------------------- 1 | import * as types from '../../mutation-types' 2 | import {Common} from 'js/base' 3 | import api from '../../api' 4 | const state = { 5 | beCommentList: [], 6 | hasMore: true, 7 | currentPage: 0 8 | } 9 | 10 | const actions = { 11 | getBeCommentList: function ({commit}) { 12 | if (state.hasMore) { 13 | commit(types.BECOMMENT_LIST_CURRENTPAGE); 14 | return api.getBeCommentList(state.currentPage, function (res) { 15 | commit(types.BECOMMENT_GET_LIST, res) 16 | }) 17 | } 18 | } 19 | } 20 | const mutations = { 21 | [types.BECOMMENT_GET_LIST] (state, res) { 22 | console.log(res) 23 | state.beCommentList = state.beCommentList.concat(res.comment_list) 24 | state.hasMore = state.currentPage < Common.index2PageCount(res.total_index) === true 25 | }, 26 | [types.BECOMMENT_LIST_CURRENTPAGE] (state) { 27 | state.currentPage += 1 28 | state.hasMore = false 29 | } 30 | } 31 | 32 | export default { 33 | state, 34 | actions, 35 | mutations 36 | } 37 | -------------------------------------------------------------------------------- /src/vuex/modules/collect.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import {Common} from 'js/base' 3 | import api from '../api' 4 | const state = { 5 | showCheckbox: false, 6 | collectList: [], 7 | hasMore: true, 8 | currentPage: 0 9 | } 10 | 11 | const actions = { 12 | getCollectList: function ({commit}) { 13 | if (state.hasMore) { 14 | commit(types.COLLECT_LIST_CURRENTPAGE); 15 | return api.getCollectList(state.currentPage, function (res) { 16 | commit(types.COLLECT_GET_LIST, res) 17 | }) 18 | } 19 | } 20 | } 21 | const getters = { 22 | getCollectList: state => state.collectList, 23 | collectHasMore: state => state.hasMore, 24 | getCheckboxShow: state => state.showCheckbox 25 | } 26 | 27 | const mutations = { 28 | [types.COLLECT_GET_LIST] (state, res) { 29 | state.collectList = state.collectList.concat(res.favourite_list) 30 | state.hasMore = state.currentPage < Common.index2PageCount(res.total_index) === true 31 | }, 32 | [types.COLLECT_LIST_CURRENTPAGE] (state) { 33 | state.currentPage += 1 34 | state.hasMore = false 35 | }, 36 | [types.SHOW_CHECKBOX] (state) { 37 | if (state.showCheckbox) { 38 | state.showCheckbox = false 39 | } else { 40 | state.showCheckbox = true 41 | } 42 | } 43 | } 44 | 45 | export default { 46 | state, 47 | actions, 48 | getters, 49 | mutations 50 | } 51 | -------------------------------------------------------------------------------- /src/vuex/modules/common.js: -------------------------------------------------------------------------------- 1 | import { Indicator } from 'mint-ui'; 2 | import * as types from '../mutation-types' 3 | import api from '../api' 4 | const state = { 5 | globalLoadinng: true, 6 | headerTitle: '我的', 7 | left: '', 8 | right: '', 9 | type: '', 10 | shoppingCartNum: 0, 11 | token: null 12 | } 13 | 14 | const actions = { 15 | setPageInfo ({commit}, settings) { 16 | commit(types.PAGE_SET_INFO, settings) 17 | }, 18 | getShoppingCartNum ({commit}) { 19 | api.getShoppingCartNum(function (res) { 20 | commit(types.SHOPPING_GET_NUM, res); 21 | }) 22 | } 23 | } 24 | const getters = { 25 | getPageInfo: state => state, 26 | getShoppingCartNum: state => state.shoppingCartNum 27 | } 28 | 29 | const mutations = { 30 | [types.SET_TOKEN] (state, params) { 31 | state = Object.assign(state, params) 32 | }, 33 | [types.PAGE_SET_INFO] (state, settings) { 34 | state = Object.assign(state, settings) 35 | }, 36 | [types.SHOPPING_GET_NUM] (state, res) { 37 | state.shoppingCartNum = res.shop_cart_num 38 | }, 39 | [types.GLOBAL_SET_LOADINNG] (state, flag) { 40 | state.globalLoadinng = flag 41 | if (state.globalLoadinng) { 42 | Indicator.open() 43 | } else { 44 | Indicator.close() 45 | } 46 | }, 47 | [types.TOP_RIGHT_CLICK_FONT] (state, params) { 48 | if (state.right.font === params.afterFont) { 49 | state.right.font = '编辑' 50 | } else { 51 | state.right.font = '完成' 52 | } 53 | } 54 | } 55 | 56 | export default { 57 | state, 58 | actions, 59 | getters, 60 | mutations 61 | } 62 | -------------------------------------------------------------------------------- /src/vuex/modules/destinationIndex.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import api from '../api' 3 | const state = { 4 | getDestinationIndex: [] 5 | } 6 | 7 | const actions = { 8 | getDestinationIndex ({commit}) { 9 | api.getDestinationIndex(function (res) { 10 | commit(types.DESTINATION_GET_INDEX, res); 11 | }) 12 | } 13 | } 14 | const getters = { 15 | getDestinationIndex: state => { 16 | return state.getDestinationIndex 17 | } 18 | } 19 | const mutations = { 20 | [types.DESTINATION_GET_INDEX] (state, res) { 21 | state.getDestinationIndex = res.country_list 22 | } 23 | } 24 | 25 | export default { 26 | state, 27 | actions, 28 | getters, 29 | mutations 30 | } 31 | -------------------------------------------------------------------------------- /src/vuex/modules/index.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import api from '../api' 3 | const state = { 4 | indexData: [] 5 | } 6 | 7 | const actions = { 8 | getIndexData: function ({commit}) { 9 | return api.getIndexData(function (res) { 10 | commit(types.INDEX_GET_DATA, res); 11 | }) 12 | } 13 | } 14 | const getters = { 15 | getIndexData: state => state.indexData 16 | } 17 | 18 | const mutations = { 19 | [types.INDEX_GET_DATA] (state, res) { 20 | state.indexData = res 21 | } 22 | } 23 | 24 | export default { 25 | state, 26 | actions, 27 | getters, 28 | mutations 29 | } 30 | -------------------------------------------------------------------------------- /src/vuex/modules/login.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import api from '../api' 3 | const state = { 4 | loginSuccess: false, 5 | errorMessage: '' 6 | } 7 | 8 | const actions = { 9 | goLogin: function ({commit}, params) { 10 | return new Promise((resolve, reject) => { 11 | api.getLogin(params, function (res) { 12 | commit(types.LOGIN_IS_SUCCESS, res); 13 | resolve(res) 14 | }) 15 | }) 16 | } 17 | } 18 | const getters = { 19 | getLoginSuccess: state => state.loginSuccess, 20 | getLoginMessage: state => state.errorMessage 21 | } 22 | 23 | const mutations = { 24 | [types.LOGIN_IS_SUCCESS] (state, res) { 25 | state.loginSuccess = res.error_code === '0000' 26 | state.errorMessage = res.error_msg 27 | } 28 | } 29 | 30 | export default { 31 | state, 32 | actions, 33 | getters, 34 | mutations 35 | } 36 | -------------------------------------------------------------------------------- /src/vuex/modules/messageList.js: -------------------------------------------------------------------------------- 1 | import {Common} from 'js/base' 2 | import api from '../api' 3 | import * as types from '../mutation-types' 4 | // 主页 5 | const state = { 6 | listData: [], 7 | hasMore: true, 8 | currentPage: 0, 9 | totalPage: 0 10 | } 11 | 12 | const actions = { 13 | getMessageList: function ({commit}) { 14 | if (state.hasMore) { 15 | commit(types.MESSAGE_LIST_CURRENTPAGE); 16 | api.getMessageList(state.currentPage, function (res) { 17 | commit(types.MESSAGE_GET_LIST, res); 18 | }) 19 | } 20 | } 21 | } 22 | const getters = { 23 | getMessageListGet: state => state.listData, 24 | hasMore: state => state.hasMore 25 | } 26 | 27 | const mutations = { 28 | // es6使用变量作为方法名 29 | [types.MESSAGE_GET_LIST] (state, res) { 30 | state.listData = state.listData.concat(res.notification_list) 31 | state.hasMore = state.currentPage < Common.index2PageCount(res.total_index) === true 32 | }, 33 | [types.MESSAGE_LIST_CURRENTPAGE] (state) { 34 | state.currentPage += 1 35 | state.hasMore = false 36 | } 37 | } 38 | 39 | export default { 40 | state, 41 | actions, 42 | getters, 43 | mutations 44 | } 45 | -------------------------------------------------------------------------------- /src/vuex/modules/my.js: -------------------------------------------------------------------------------- 1 | import * as types from '../mutation-types' 2 | import api from '../api' 3 | const state = { 4 | messageCount: 0, 5 | centerData: [] 6 | } 7 | 8 | const actions = { 9 | getMessageCount: function ({commit}, number) { 10 | commit(types.MESSAGE_GET_COUNTER, number) 11 | }, 12 | gerCenterData: function ({commit}) { 13 | return api.getCenterData(function (res) { 14 | commit(types.CENTER_GET_DATA, res) 15 | }) 16 | } 17 | } 18 | const getters = { 19 | getMessageCount: state => state.messageCount, 20 | getCenterData: state => { 21 | return state.centerData 22 | } 23 | } 24 | 25 | const mutations = { 26 | [types.MESSAGE_GET_COUNTER] (state, number) { 27 | state.messageCount = number 28 | }, 29 | [types.CENTER_GET_DATA] (state, res) { 30 | state.centerData = res 31 | } 32 | } 33 | 34 | export default { 35 | state, 36 | actions, 37 | getters, 38 | mutations 39 | } 40 | -------------------------------------------------------------------------------- /src/vuex/mutation-types.js: -------------------------------------------------------------------------------- 1 | // common 2 | export const PAGE_SET_INFO = 'PAGE_SET_INFO' 3 | export const SHOPPING_GET_NUM = 'SHOPPING_GET_NUM' 4 | export const TOP_RIGHT_CLICK_FONT = 'TOP_RIGHT_CLICK_FONT' 5 | export const GLOBAL_SET_LOADINNG = 'GLOBAL_SET_LOADINNG' 6 | export const SET_TOKEN = 'SET_TOKEN' 7 | // 首页 8 | export const INDEX_GET_DATA = 'INDEX_GET_DATA' 9 | // 获取消息列表数据 10 | export const MESSAGE_GET_LIST = 'MESSAGE_GET_LIST' 11 | export const MESSAGE_LIST_CURRENTPAGE = 'MESSAGE_LIST_CURRENTPAGE' 12 | // 购物车列表 13 | export const SHOPPINGCART_GET_LIST = 'SHOPPINGCART_GET_LIST' 14 | export const SHOPPINGCART_LIST_CURRENTPAGE = 'SHOPPINGCART_LIST_CURRENTPAGE' 15 | export const SHOPPINGCART_SELECT_ALL = 'SHOPPINGCART_SELECT_ALL' 16 | export const SHOPPINGCART_SELECT_ITEM = 'SHOPPINGCART_SELECT_ITEM' 17 | export const SHOPPINGCART_DELETE_SELECT = 'SHOPPINGCART_DELETE_SELECT' 18 | export const SHOPPINGCART_DELETE_ARRAY = 'SHOPPINGCART_DELETE_ARRAY' 19 | export const CALCULATE_TOTAL_PRICE = 'CALCULATE_TOTAL_PRICE' 20 | // 我的 21 | export const MESSAGE_GET_COUNTER = 'MESSAGE_GET_COUNTER' 22 | export const CENTER_GET_DATA = 'CENTER_GET_DATA' 23 | // 我的收藏 24 | export const COLLECT_GET_LIST = 'COLLECT_GET_LIST' 25 | export const COLLECT_LIST_CURRENTPAGE = 'COLLECT_LIST_CURRENTPAGE' 26 | export const SHOW_CHECKBOX = 'SHOW_CHECKBOX' 27 | // user 28 | export const LOGIN_IS_SUCCESS = 'LOGIN_IS_SUCCESS' 29 | // 目的地 30 | export const DESTINATION_GET_INDEX = 'DESTINATION_GET_INDEX' 31 | // 待点评 32 | export const BECOMMENT_GET_LIST = 'BECOMMENT_GET_LIST' 33 | export const BECOMMENT_LIST_CURRENTPAGE = 'BECOMMENT_LIST_CURRENTPAGE' 34 | 35 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import messageList from './modules/messageList' 4 | import common from './modules/common' 5 | import my from './modules/my' 6 | import login from './modules/login' 7 | import index from './modules/index' 8 | import collect from './modules/collect' 9 | import destinationIndex from './modules/destinationIndex' 10 | import shoppingCart from './modules/shoppingCart' 11 | import beComment from './modules/center/becomment' 12 | 13 | Vue.use(Vuex) 14 | 15 | export default new Vuex.Store({ 16 | modules: { 17 | index, 18 | common, 19 | my, 20 | messageList, 21 | login, 22 | collect, 23 | destinationIndex, 24 | shoppingCart, 25 | beComment 26 | }, 27 | strict: process.env.NODE_ENV !== 'production'// 线上环境关掉 28 | }) 29 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/.gitkeep -------------------------------------------------------------------------------- /static/api/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/.gitkeep -------------------------------------------------------------------------------- /static/api/center/getCenter.json: -------------------------------------------------------------------------------- 1 | { 2 | "coupon_amount": "21", 3 | "point": "0", 4 | "comment_amount": "2", 5 | "need_comment_amount": "1", 6 | "need_pay_amount": "10", 7 | "notification_amount": "10", 8 | "taobao_order_amount": "2", 9 | "tb_need_pay_amount": "0", 10 | "tb_need_complete_amount": "2", 11 | "redis_time": "1482832317", 12 | "nickname": "无尽的故事(endless_story)", 13 | "username": "wechat_无尽的故事", 14 | "phone": "13800138000", 15 | "phone_verify": "2", 16 | "password": "e10adc3949ba59abbe56e05", 17 | "taobao_phone": "13800138001", 18 | "taobao_phone_verify": "1", 19 | "image": "http://wx.qlogo.cn/mmopen/Q3auHgzwzM6t2OsdUB7VNmOzuKYWzvbzsSWQXh4zUc6MjoN3ISpESMFVZAx5d8voM7niaOR1SNLlEjnZkS2yNMA/0", 20 | "shop_cart_num": "2", 21 | "error_code": "0000", 22 | "error_msg": "OK", 23 | "execute_time": 0.209 24 | } 25 | -------------------------------------------------------------------------------- /static/api/center/getFavourite.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": "0000", 3 | "error_msg": "OK", 4 | "favourite_list": [ 5 | { 6 | "name": "阿凡达号 专线攀牙湾豪华帆船一日游", 7 | "sale_amount": "211", 8 | "price": "0.00", 9 | "status": "2", 10 | "sale_id": "234", 11 | "image": "../static/api/center/images/collect1.jpg" 12 | }, 13 | { 14 | "name": "清迈人妖秀门票 酒店接送", 15 | "sale_amount": "176", 16 | "price": "95.00", 17 | "status": "1", 18 | "sale_id": "30", 19 | "image": "../static/api/center/images/collect2.jpg" 20 | }, 21 | { 22 | "name": "清迈 Let's Relax Spa泰式按摩", 23 | "sale_amount": "105", 24 | "price": "109.00", 25 | "status": "1", 26 | "sale_id": "39", 27 | "image": "../static/api/center/images/collect3.jpg" 28 | }, 29 | { 30 | "name": "泰国清迈到pai拜县往返包车一日游 酒店接送", 31 | "sale_amount": "0", 32 | "price": "0.00", 33 | "status": "2", 34 | "sale_id": "28", 35 | "image": "../static/api/center/images/collect45.jpg" 36 | } 37 | ], 38 | "last_index": 0, 39 | "total_index": "1", 40 | "execute_time": 0.287 41 | } 42 | -------------------------------------------------------------------------------- /static/api/center/getNotification.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": "0000", 3 | "error_msg": "OK", 4 | "last_index": 10, 5 | "total_index":32, 6 | "notification_list": [ 7 | { 8 | "id": "16581", 9 | "title": "优惠信息", 10 | "content": "您有1张3.00元的优惠券还有3天就过期啦,请记得使用哦!", 11 | "user_id": "2", 12 | "create_time": "1469695310", 13 | "update_time": "", 14 | "is_read": "", 15 | "url": "", 16 | "web_url": "", 17 | "app_url": "", 18 | "create_time_str": "1970-01-01 08:00:01" 19 | }, 20 | { 21 | "id": "13824", 22 | "title": "优惠信息", 23 | "content": "您有3张5.00元的优惠券还有3天就过期啦,请记得使用哦!", 24 | "user_id": "2", 25 | "create_time": "1469695284", 26 | "update_time": "", 27 | "is_read": "", 28 | "url": "", 29 | "web_url": "", 30 | "app_url": "", 31 | "create_time_str": "1970-01-01 08:00:01" 32 | }, 33 | { 34 | "id": "11063", 35 | "title": "优惠信息", 36 | "content": "您有3张10.00元的优惠券还有3天就过期啦,请记得使用哦!", 37 | "user_id": "2", 38 | "create_time": "1469695254", 39 | "update_time": "", 40 | "is_read": "", 41 | "url": "", 42 | "web_url": "", 43 | "app_url": "", 44 | "create_time_str": "1970-01-01 08:00:01" 45 | }, 46 | { 47 | "id": "8301", 48 | "title": "优惠信息", 49 | "content": "您有3张30.00元的优惠券还有3天就过期啦,请记得使用哦!", 50 | "user_id": "2", 51 | "create_time": "1469692854", 52 | "update_time": "", 53 | "is_read": "", 54 | "url": "", 55 | "web_url": "", 56 | "app_url": "", 57 | "create_time_str": "1970-01-01 08:00:01" 58 | }, 59 | { 60 | "id": "5535", 61 | "title": "优惠信息", 62 | "content": "您有3张50.00元的优惠券还有3天就过期啦,请记得使用哦!", 63 | "user_id": "2", 64 | "create_time": "1469688114", 65 | "update_time": "", 66 | "is_read": "", 67 | "url": "", 68 | "web_url": "", 69 | "app_url": "", 70 | "create_time_str": "1970-01-01 08:00:01" 71 | }, 72 | { 73 | "id": "2781", 74 | "title": "优惠信息", 75 | "content": "您有1张100.00元的优惠券还有3天就过期啦,请记得使用哦!", 76 | "user_id": "2", 77 | "create_time": "1469609514", 78 | "update_time": "", 79 | "is_read": "", 80 | "url": "", 81 | "web_url": "", 82 | "app_url": "", 83 | "create_time_str": "1970-01-01 08:00:01" 84 | }, 85 | { 86 | "id": "15", 87 | "title": "优惠信息", 88 | "content": "您有1张200.00元的优惠券还有3天就过期啦,请记得使用哦!", 89 | "user_id": "2", 90 | "create_time": "1469608854", 91 | "update_time": "", 92 | "is_read": "", 93 | "url": "", 94 | "web_url": "", 95 | "app_url": "", 96 | "create_time_str": "1970-01-01 08:00:01" 97 | }, 98 | { 99 | "id": "1", 100 | "title": "测试", 101 | "content": "测试内容", 102 | "user_id": "2", 103 | "create_time": "1469522454", 104 | "update_time": "", 105 | "is_read": "", 106 | "url": "", 107 | "web_url": "", 108 | "app_url": "" 109 | }, 110 | { 111 | "id": "2", 112 | "title": "测试1", 113 | "content": "测试内容1", 114 | "user_id": "2", 115 | "create_time": "1469176914", 116 | "update_time": "", 117 | "is_read": "", 118 | "url": "", 119 | "web_url": "", 120 | "app_url": "" 121 | }, 122 | { 123 | "id": "3", 124 | "title": "测试2", 125 | "content": "测试内容2", 126 | "user_id": "2", 127 | "create_time": "1468482114", 128 | "update_time": "", 129 | "is_read": "", 130 | "url": "", 131 | "web_url": "", 132 | "app_url": "" 133 | } 134 | ], 135 | "execute_time": 0.267 136 | } 137 | -------------------------------------------------------------------------------- /static/api/center/images/collect1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/center/images/collect1.jpg -------------------------------------------------------------------------------- /static/api/center/images/collect2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/center/images/collect2.jpg -------------------------------------------------------------------------------- /static/api/center/images/collect3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/center/images/collect3.jpg -------------------------------------------------------------------------------- /static/api/center/images/collect4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/center/images/collect4.jpg -------------------------------------------------------------------------------- /static/api/destination/images/d_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/destination/images/d_1.jpg -------------------------------------------------------------------------------- /static/api/destination/images/d_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/destination/images/d_2.jpg -------------------------------------------------------------------------------- /static/api/destination/images/d_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/destination/images/d_3.jpg -------------------------------------------------------------------------------- /static/api/destination/images/d_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/destination/images/d_4.jpg -------------------------------------------------------------------------------- /static/api/home/images/a1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/a1.jpg -------------------------------------------------------------------------------- /static/api/home/images/a2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/a2.jpg -------------------------------------------------------------------------------- /static/api/home/images/a3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/a3.jpg -------------------------------------------------------------------------------- /static/api/home/images/banner1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/banner1.jpg -------------------------------------------------------------------------------- /static/api/home/images/banner2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/banner2.jpg -------------------------------------------------------------------------------- /static/api/home/images/l1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/l1.jpg -------------------------------------------------------------------------------- /static/api/home/images/l2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/l2.jpg -------------------------------------------------------------------------------- /static/api/home/images/l3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/l3.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu1.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu2.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu3.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu4.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu5.jpg -------------------------------------------------------------------------------- /static/api/home/images/mu6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/mu6.jpg -------------------------------------------------------------------------------- /static/api/home/images/r1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/r1.jpg -------------------------------------------------------------------------------- /static/api/home/images/r2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/r2.jpg -------------------------------------------------------------------------------- /static/api/home/images/remai1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/remai1.jpg -------------------------------------------------------------------------------- /static/api/home/images/remai2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/remai2.jpg -------------------------------------------------------------------------------- /static/api/home/images/remai3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luchanan/vue2.0-multi-page/90bce0e6a6f24431733af17f24aba791f95b785e/static/api/home/images/remai3.jpg -------------------------------------------------------------------------------- /static/api/order/countShopCartNum.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": "0000", 3 | "error_msg": "OK", 4 | "shop_cart_num": 12, 5 | "execute_time": 0.057 6 | } -------------------------------------------------------------------------------- /static/api/order/deleteShopCart.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": "0000", 3 | "error_msg": "OK", 4 | "execute_time": 0.31 5 | } -------------------------------------------------------------------------------- /static/api/user/login.json: -------------------------------------------------------------------------------- 1 | { 2 | "error_code": "0000", 3 | "error_msg": "OK", 4 | "data": { 5 | "user_id": "1", 6 | "username": "phone_13800138000", 7 | "nickname": "phone_13800138000", 8 | "image": "", 9 | "phone": "13800138000", 10 | "phone_verify": "2", 11 | "email": "", 12 | "taobao_phone": "13800138000", 13 | "taobao_phone_verify": "1", 14 | "token": "112" 15 | }, 16 | "execute_time": 0.689 17 | } -------------------------------------------------------------------------------- /static/js/lib/flexible/flexible.js: -------------------------------------------------------------------------------- 1 | !function(a,b){function c(){var b=f.getBoundingClientRect().width;b/i>540&&(b=540*i);var c=b/10;f.style.fontSize=c+"px",k.rem=a.rem=c}var d,e=a.document,f=e.documentElement,g=e.querySelector('meta[name="viewport"]'),h=e.querySelector('meta[name="flexible"]'),i=0,j=0,k=b.flexible||(b.flexible={});if(g){console.warn("将根据已有的meta标签来设置缩放比例");var l=g.getAttribute("content").match(/initial\-scale=([\d\.]+)/);l&&(j=parseFloat(l[1]),i=parseInt(1/j))}else if(h){var m=h.getAttribute("content");if(m){var n=m.match(/initial\-dpr=([\d\.]+)/),o=m.match(/maximum\-dpr=([\d\.]+)/);n&&(i=parseFloat(n[1]),j=parseFloat((1/i).toFixed(2))),o&&(i=parseFloat(o[1]),j=parseFloat((1/i).toFixed(2)))}}if(!i&&!j){var p=a.navigator.userAgent,q=(!!p.match(/android/gi),!!p.match(/iphone/gi)),r=q&&!!p.match(/OS 9_3/),s=a.devicePixelRatio;i=q&&!r?s>=3&&(!i||i>=3)?3:s>=2&&(!i||i>=2)?2:1:1,j=1/i}if(f.setAttribute("data-dpr",i),!g)if(g=e.createElement("meta"),g.setAttribute("name","viewport"),g.setAttribute("content","initial-scale="+j+", maximum-scale="+j+", minimum-scale="+j+", user-scalable=no"),f.firstElementChild)f.firstElementChild.appendChild(g);else{var t=e.createElement("div");t.appendChild(g),e.write(t.innerHTML)}a.addEventListener("resize",function(){clearTimeout(d),d=setTimeout(c,300)},!1),a.addEventListener("pageshow",function(a){a.persisted&&(clearTimeout(d),d=setTimeout(c,300))},!1),"complete"===e.readyState?e.body.style.fontSize=12*i+"px":e.addEventListener("DOMContentLoaded",function(){e.body.style.fontSize=12*i+"px"},!1),c(),k.dpr=a.dpr=i,k.refreshRem=c,k.rem2px=function(a){var b=parseFloat(a)*this.rem;return"string"==typeof a&&a.match(/rem$/)&&(b+="px"),b},k.px2rem=function(a){var b=parseFloat(a)/this.rem;return"string"==typeof a&&a.match(/px$/)&&(b+="rem"),b}}(window,window.lib||(window.lib={})); -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | require('babel-register') 2 | var config = require('../../config') 3 | 4 | // http://nightwatchjs.org/guide#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": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.1.jar", 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 | var server = require('../../build/dev-server.js') 4 | 5 | // 2. run the nightwatch test suite against it 6 | // to run in additional browsers: 7 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 8 | // 2. add it to the --env flag below 9 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox` 10 | // For more information on Nightwatch's config file, see 11 | // http://nightwatchjs.org/guide#settings-file 12 | var opts = process.argv.slice(2) 13 | if (opts.indexOf('--config') === -1) { 14 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js']) 15 | } 16 | if (opts.indexOf('--env') === -1) { 17 | opts = opts.concat(['--env', 'chrome']) 18 | } 19 | 20 | var spawn = require('cross-spawn') 21 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' }) 22 | 23 | runner.on('exit', function (code) { 24 | server.close() 25 | process.exit(code) 26 | }) 27 | 28 | runner.on('error', function (err) { 29 | server.close() 30 | throw err 31 | }) 32 | -------------------------------------------------------------------------------- /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 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 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 path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var utils = require('../../build/utils') 10 | var webpack = require('webpack') 11 | var projectRoot = path.resolve(__dirname, '../../') 12 | 13 | var webpackConfig = merge(baseConfig, { 14 | // use inline sourcemap for karma-sourcemap-loader 15 | module: { 16 | loaders: utils.styleLoaders() 17 | }, 18 | devtool: '#inline-source-map', 19 | vue: { 20 | loaders: { 21 | js: 'isparta' 22 | } 23 | }, 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env': require('../../config/test.env') 27 | }) 28 | ] 29 | }) 30 | 31 | // no need for app entry during tests 32 | delete webpackConfig.entry 33 | 34 | // make sure isparta loader is applied before eslint 35 | webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] 36 | webpackConfig.module.preLoaders.unshift({ 37 | test: /\.js$/, 38 | loader: 'isparta', 39 | include: path.resolve(projectRoot, 'src') 40 | }) 41 | 42 | // only apply babel for test files when using isparta 43 | webpackConfig.module.loaders.some(function (loader, i) { 44 | if (loader.loader === 'babel') { 45 | loader.include = path.resolve(projectRoot, 'test/unit') 46 | return true 47 | } 48 | }) 49 | 50 | module.exports = function (config) { 51 | config.set({ 52 | // to run in additional browsers: 53 | // 1. install corresponding karma launcher 54 | // http://karma-runner.github.io/0.13/config/browsers.html 55 | // 2. add it to the `browsers` array below. 56 | browsers: ['PhantomJS'], 57 | frameworks: ['mocha', 'sinon-chai'], 58 | reporters: ['spec', 'coverage'], 59 | files: ['./index.js'], 60 | preprocessors: { 61 | './index.js': ['webpack', 'sourcemap'] 62 | }, 63 | webpack: webpackConfig, 64 | webpackMiddleware: { 65 | noInfo: true 66 | }, 67 | coverageReporter: { 68 | dir: './coverage', 69 | reporters: [ 70 | { type: 'lcov', subdir: '.' }, 71 | { type: 'text-summary' } 72 | ] 73 | } 74 | }) 75 | } 76 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | el: document.createElement('div'), 8 | render: (h) => h(Hello) 9 | }) 10 | expect(vm.$el.querySelector('.hello h1').textContent) 11 | .to.equal('Welcome to Your Vue.js App') 12 | }) 13 | }) 14 | --------------------------------------------------------------------------------