├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .gitignore ├── LICENSE ├── 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 ├── index.html ├── package.json ├── screenshot ├── charts.jpg └── progressbar.jpg ├── src ├── App.vue ├── assets │ ├── headerlogo-white.png │ ├── headerlogo.png │ ├── images │ │ ├── vueico.png │ │ └── vuelogo.png │ ├── logo.png │ └── photo.jpg ├── components │ ├── collapse │ │ ├── collapse.vue │ │ ├── collapseitem.vue │ │ └── index.vue │ ├── common │ │ ├── index.vue │ │ ├── pagination.vue │ │ └── progressbar.vue │ ├── header │ │ └── index.vue │ ├── mixins.less │ ├── modal │ │ ├── Modal.vue │ │ ├── Toast.vue │ │ ├── ToastItem.vue │ │ └── index.vue │ ├── page │ │ ├── content.vue │ │ ├── foot.vue │ │ ├── index.vue │ │ ├── link.vue │ │ ├── login.vue │ │ ├── navmenu.vue │ │ └── title.vue │ ├── stars │ │ ├── index.vue │ │ └── stars.less │ ├── timeline │ │ ├── index.vue │ │ ├── timeline.vue │ │ └── timelineitem.vue │ └── variables.less ├── demos │ ├── 404.vue │ ├── About.vue │ ├── Ajax.vue │ ├── Buttons.vue │ ├── Card.vue │ ├── Charts.vue │ ├── Collapse.vue │ ├── Content.vue │ ├── Form.vue │ ├── Icons.vue │ ├── Image.vue │ ├── Index.vue │ ├── Level.vue │ ├── MediaObject.vue │ ├── Message.vue │ ├── Modal.vue │ ├── Nav.vue │ ├── Notifications.vue │ ├── Pagination.vue │ ├── Panel.vue │ ├── Progress.vue │ ├── Rating.vue │ ├── Table.vue │ ├── Tabs.vue │ ├── Tags.vue │ ├── Timeline.vue │ ├── Title.vue │ └── Toast.vue ├── main.js └── store.js ├── static └── .gitkeep ├── test └── unit │ ├── .eslintrc │ ├── index.js │ ├── karma.conf.js │ └── specs │ └── Hello.spec.js └── web.manifest /.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 | # src/components/xscroll/*.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 7 | extends: 'standard', 8 | // required to lint *.vue files 9 | plugins: [ 10 | 'html' 11 | ], 12 | // add your custom rules here 13 | 'rules': { 14 | // allow paren-less arrow functions 15 | 'arrow-parens': 0, 16 | // allow debugger during development 17 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | selenium-debug.log 6 | test/unit/coverage 7 | test/e2e/reports 8 | .sass-cache/ 9 | _site/ 10 | *.swp 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 connors and other contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue-Bulma 2 | 3 | > 轻量级高性能MVVM Admin UI框架 4 | 5 | Demo网址:[https://admin-c79b5.firebaseapp.com/admin/index](https://admin-c79b5.firebaseapp.com/admin/index) 6 | 7 | 8 | # Screenshot 9 | 10 | 11 | 12 | 13 | ## Build Setup 14 | 15 | ``` bash 16 | # 安装依赖包 17 | npm install 18 | 19 | # 开发模式运行在 localhost:8080 20 | npm run dev 21 | 22 | # 打包项目 23 | npm run build 24 | 打包前注意将node_modules\moment\locale\目录下除zh-cn.js的文件全部删除,否则打包后文件将会很大 25 | 26 | # 运行测试 27 | npm run unit 28 | ``` 29 | 30 | ## manifest 缓存 31 | 32 | > 为了让前端飞,我们还需要进行manifest缓存。示例文件为web.manifest,通过设定甚至可以进行整站缓存,如果需要使用该设定,请记住每次代码更新的同时也需要修改一下该文件避免加载出错。 33 | 34 | ## 引入 35 | 36 | - [Bulma](https://github.com/jgthms/bulma) 37 | - [Vue](http://vuejs.org/) 38 | - [vuex](http://vuex.vuejs.org) 39 | - [vue-router](http://router.vuejs.org) 40 | - [vue-resource](https://github.com/vuejs/vue-resource) 41 | 42 | ## 特别提示 43 | 44 | > 本项目构建中已使用eslint,力求代码排版标准化方便阅读,建议不要在设置里取消该设定。 45 | > 本项目不含jQuery库,原因可参考pagination组件,通过vue仅使用一行代码即实现了复杂的分页页码处理,vue强大的数据驱动模型带来了全新的前端设计方式。 -------------------------------------------------------------------------------- /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 | rm('-rf', assetsPath) 22 | mkdir('-p', assetsPath) 23 | cp('-R', 'static/', assetsPath) 24 | 25 | webpack(webpackConfig, function (err, stats) { 26 | spinner.stop() 27 | if (err) throw err 28 | process.stdout.write(stats.toString({ 29 | colors: true, 30 | modules: false, 31 | children: false, 32 | chunks: false, 33 | chunkModules: false 34 | }) + '\n') 35 | }) 36 | -------------------------------------------------------------------------------- /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 path = require('path') 2 | var express = require('express') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var proxyMiddleware = require('http-proxy-middleware') 6 | var webpackConfig = process.env.NODE_ENV === 'testing' 7 | ? require('./webpack.prod.conf') 8 | : 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 | // force page reload when html-webpack-plugin template changes 29 | compiler.plugin('compilation', function (compilation) { 30 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 31 | hotMiddleware.publish({ action: 'reload' }) 32 | cb() 33 | }) 34 | }) 35 | 36 | // proxy api requests 37 | Object.keys(proxyTable).forEach(function (context) { 38 | var options = proxyTable[context] 39 | if (typeof options === 'string') { 40 | options = { target: options } 41 | } 42 | app.use(proxyMiddleware(context, options)) 43 | }) 44 | 45 | // handle fallback for HTML5 history API 46 | app.use(require('connect-history-api-fallback')()) 47 | 48 | // serve webpack bundle output 49 | app.use(devMiddleware) 50 | 51 | // enable hot-reload and state-preserving 52 | // compilation error display 53 | app.use(hotMiddleware) 54 | 55 | // serve pure static assets 56 | var staticPath = path.posix.join(config.build.assetsPublicPath, config.build.assetsSubDirectory) 57 | app.use(staticPath, express.static('./static')) 58 | 59 | module.exports = app.listen(port, function (err) { 60 | if (err) { 61 | console.log(err) 62 | return 63 | } 64 | console.log('Listening at http://localhost:' + port + '\n') 65 | }) 66 | -------------------------------------------------------------------------------- /build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | return path.posix.join(config.build.assetsSubDirectory, _path) 7 | } 8 | 9 | exports.cssLoaders = function (options) { 10 | options = options || {} 11 | // generate loader string to be used with extract text plugin 12 | function generateLoaders (loaders) { 13 | var sourceLoader = loaders.map(function (loader) { 14 | var extraParamChar 15 | if (/\?/.test(loader)) { 16 | loader = loader.replace(/\?/, '-loader?') 17 | extraParamChar = '&' 18 | } else { 19 | loader = loader + '-loader' 20 | extraParamChar = '?' 21 | } 22 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 23 | }).join('!') 24 | 25 | if (options.extract) { 26 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 27 | } else { 28 | return ['vue-style-loader', sourceLoader].join('!') 29 | } 30 | } 31 | 32 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 33 | return { 34 | css: generateLoaders(['css']), 35 | postcss: generateLoaders(['css']), 36 | less: generateLoaders(['css', 'less']), 37 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 38 | scss: generateLoaders(['css', 'sass']), 39 | stylus: generateLoaders(['css', 'stylus']), 40 | styl: generateLoaders(['css', 'stylus']) 41 | } 42 | } 43 | 44 | // Generate loaders for standalone style files (outside of .vue) 45 | exports.styleLoaders = function (options) { 46 | var output = [] 47 | var loaders = exports.cssLoaders(options) 48 | for (var extension in loaders) { 49 | var loader = loaders[extension] 50 | output.push({ 51 | test: new RegExp('\\.' + extension + '$'), 52 | loader: loader 53 | }) 54 | } 55 | return output 56 | } 57 | -------------------------------------------------------------------------------- /build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | module.exports = { 7 | entry: { 8 | app: './src/main.js' 9 | }, 10 | output: { 11 | path: config.build.assetsRoot, 12 | publicPath: config.build.assetsPublicPath, 13 | filename: '[name].js' 14 | }, 15 | resolve: { 16 | extensions: ['', '.js', '.vue'], 17 | fallback: [path.join(__dirname, '../node_modules')], 18 | alias: { 19 | 'src': path.resolve(__dirname, '../src'), 20 | 'assets': path.resolve(__dirname, '../src/assets'), 21 | 'components': path.resolve(__dirname, '../src/components') 22 | } 23 | }, 24 | resolveLoader: { 25 | fallback: [path.join(__dirname, '../node_modules')] 26 | }, 27 | module: { 28 | preLoaders: [ 29 | { 30 | test: /\.vue$/, 31 | loader: 'eslint', 32 | include: projectRoot, 33 | exclude: /node_modules/ 34 | }, 35 | { 36 | test: /\.js$/, 37 | loader: 'eslint', 38 | include: projectRoot, 39 | exclude: /node_modules/ 40 | } 41 | ], 42 | loaders: [ 43 | { 44 | test: /\.vue$/, 45 | loader: 'vue' 46 | }, 47 | { 48 | test: /\.js$/, 49 | loader: 'babel', 50 | include: projectRoot, 51 | exclude: /node_modules/ 52 | }, 53 | { 54 | test: /\.json$/, 55 | loader: 'json' 56 | }, 57 | { 58 | test: /\.html$/, 59 | loader: 'vue-html' 60 | }, 61 | { 62 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 63 | loader: 'url', 64 | query: { 65 | limit: 10000, 66 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 67 | } 68 | }, 69 | { 70 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 71 | loader: 'url', 72 | query: { 73 | limit: 10000, 74 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 75 | } 76 | } 77 | ] 78 | }, 79 | eslint: { 80 | formatter: require('eslint-friendly-formatter') 81 | }, 82 | vue: { 83 | loaders: utils.cssLoaders() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders() 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 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = process.env.NODE_ENV === 'testing' 10 | ? require('../config/test.env') 11 | : config.build.env 12 | 13 | var webpackConfig = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 16 | }, 17 | devtool: config.build.productionSourceMap ? '#source-map' : false, 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 | vue: { 24 | loaders: utils.cssLoaders({ 25 | sourceMap: config.build.productionSourceMap, 26 | extract: true 27 | }) 28 | }, 29 | plugins: [ 30 | // http://vuejs.github.io/vue-loader/workflow/production.html 31 | new webpack.DefinePlugin({ 32 | 'process.env': env 33 | }), 34 | new webpack.optimize.UglifyJsPlugin({ 35 | compress: { 36 | warnings: false 37 | } 38 | }), 39 | new webpack.optimize.OccurenceOrderPlugin(), 40 | // extract css into its own file 41 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 42 | // generate dist index.html with correct asset hash for caching. 43 | // you can customize output by editing /index.html 44 | // see https://github.com/ampedandwired/html-webpack-plugin 45 | new HtmlWebpackPlugin({ 46 | filename: process.env.NODE_ENV === 'testing' 47 | ? 'index.html' 48 | : config.build.index, 49 | template: 'index.html', 50 | inject: true, 51 | minify: { 52 | removeComments: true, 53 | collapseWhitespace: true, 54 | removeAttributeQuotes: true 55 | // more options: 56 | // https://github.com/kangax/html-minifier#options-quick-reference 57 | }, 58 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 59 | chunksSortMode: 'dependency' 60 | }), 61 | // split vendor js into its own file 62 | new webpack.optimize.CommonsChunkPlugin({ 63 | name: 'vendor', 64 | minChunks: function (module, count) { 65 | // any required modules inside node_modules are extracted to vendor 66 | return ( 67 | module.resource && 68 | /\.js$/.test(module.resource) && 69 | module.resource.indexOf( 70 | path.join(__dirname, '../node_modules') 71 | ) === 0 72 | ) 73 | } 74 | }), 75 | // extract webpack runtime and module manifest to its own file in order to 76 | // prevent vendor hash from being updated whenever app bundle is updated 77 | new webpack.optimize.CommonsChunkPlugin({ 78 | name: 'manifest', 79 | chunks: ['vendor'] 80 | }) 81 | ] 82 | }) 83 | 84 | if (config.build.productionGzip) { 85 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 86 | 87 | webpackConfig.plugins.push( 88 | new CompressionWebpackPlugin({ 89 | asset: '[path].gz[query]', 90 | algorithm: 'gzip', 91 | test: new RegExp( 92 | '\\.(' + 93 | config.build.productionGzipExtensions.join('|') + 94 | ')$' 95 | ), 96 | threshold: 10240, 97 | minRatio: 0.8 98 | }) 99 | ) 100 | } 101 | 102 | module.exports = webpackConfig 103 | -------------------------------------------------------------------------------- /config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | // 默认生成map,这里取消 12 | productionSourceMap: false, 13 | // Gzip off by default as many popular static hosts such as 14 | // Surge or Netlify already gzip all static assets for you. 15 | // Before setting to `true`, make sure to: 16 | // npm install --save-dev compression-webpack-plugin 17 | // 此处意义不大,web server自带了gzip压缩能力 18 | productionGzip: false, 19 | productionGzipExtensions: ['js', 'css'] 20 | }, 21 | dev: { 22 | env: require('./dev.env'), 23 | port: 8080, 24 | proxyTable: {} 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /config/test.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var devEnv = require('./dev.env') 3 | 4 | module.exports = merge(devEnv, { 5 | NODE_ENV: '"testing"' 6 | }) 7 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Vue-Bulma 16 | 17 | 18 |
19 | 20 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-bulma", 3 | "version": "0.0.1", 4 | "description": "webapp with Vue.js", 5 | "author": "wangxg <705459998@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 | "test": "npm run unit", 12 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs" 13 | }, 14 | "dependencies": { 15 | "vue": "^2.0.3", 16 | "babel-runtime": "^6.11.6" 17 | }, 18 | "devDependencies": { 19 | "babel-core": "^6.16.0", 20 | "babel-loader": "^6.2.5", 21 | "babel-plugin-transform-runtime": "^6.15.0", 22 | "babel-preset-es2015": "^6.16.0", 23 | "babel-preset-stage-2": "^6.16.0", 24 | "bulma": "0.2.1", 25 | "chai": "^3.5.0", 26 | "chart.js": "^2.3.0", 27 | "connect-history-api-fallback": "^1.3.0", 28 | "css-loader": "^0.25.0", 29 | "eslint": "^3.7.0", 30 | "eslint-config-standard": "^6.2.0", 31 | "eslint-friendly-formatter": "^2.0.6", 32 | "eslint-loader": "^1.5.0", 33 | "eslint-plugin-html": "^1.5.3", 34 | "eslint-plugin-promise": "^2.0.1", 35 | "eslint-plugin-standard": "^2.0.1", 36 | "eventsource-polyfill": "^0.9.6", 37 | "express": "^4.14.0", 38 | "extract-text-webpack-plugin": "^1.0.1", 39 | "fastclick": "^1.0.6", 40 | "file-loader": "^0.9.0", 41 | "function-bind": "^1.1.0", 42 | "html-webpack-plugin": "^2.22.0", 43 | "http-proxy-middleware": "^0.17.2", 44 | "inject-loader": "^2.0.1", 45 | "isparta-loader": "^2.0.0", 46 | "json-loader": "^0.5.4", 47 | "karma": "^1.3.0", 48 | "karma-coverage": "^1.1.1", 49 | "karma-mocha": "^1.2.0", 50 | "karma-phantomjs-launcher": "^1.0.2", 51 | "karma-sinon-chai": "^1.2.3", 52 | "karma-sourcemap-loader": "^0.3.7", 53 | "karma-spec-reporter": "0.0.26", 54 | "karma-webpack": "^1.8.0", 55 | "less": "^2.7.1", 56 | "less-loader": "^2.2.3", 57 | "lolex": "^1.5.1", 58 | "mocha": "^3.1.0", 59 | "moment": "^2.14.1", 60 | "ora": "^0.3.0", 61 | "phantomjs-prebuilt": "^2.1.12", 62 | "shelljs": "^0.7.4", 63 | "sinon": "^1.17.6", 64 | "sinon-chai": "^2.8.0", 65 | "swiper": "^3.3.1", 66 | "url-loader": "^0.5.7", 67 | "vue-hot-reload-api": "^2.0.6", 68 | "vue-html-loader": "^1.2.3", 69 | "vue-loader": "^9.7.0", 70 | "vue-resource": "^1.0.3", 71 | "vue-router": "^2.0.1", 72 | "vue-style-loader": "^1.0.0", 73 | "vuex": "^2.0.0", 74 | "webpack": "^1.13.2", 75 | "webpack-dev-middleware": "^1.8.4", 76 | "webpack-hot-middleware": "^2.13.0", 77 | "webpack-merge": "^0.14.1" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /screenshot/charts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/screenshot/charts.jpg -------------------------------------------------------------------------------- /screenshot/progressbar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/screenshot/progressbar.jpg -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 21 | 91 | -------------------------------------------------------------------------------- /src/assets/headerlogo-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/headerlogo-white.png -------------------------------------------------------------------------------- /src/assets/headerlogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/headerlogo.png -------------------------------------------------------------------------------- /src/assets/images/vueico.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/images/vueico.png -------------------------------------------------------------------------------- /src/assets/images/vuelogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/images/vuelogo.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/photo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/src/assets/photo.jpg -------------------------------------------------------------------------------- /src/components/collapse/collapse.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/collapse/collapseitem.vue: -------------------------------------------------------------------------------- 1 | 16 | 80 | -------------------------------------------------------------------------------- /src/components/collapse/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/common/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/common/pagination.vue: -------------------------------------------------------------------------------- 1 | 30 | -------------------------------------------------------------------------------- /src/components/header/index.vue: -------------------------------------------------------------------------------- 1 | 23 | 42 | 43 | -------------------------------------------------------------------------------- /src/components/modal/Modal.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 78 | 79 | 98 | -------------------------------------------------------------------------------- /src/components/modal/Toast.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /src/components/modal/ToastItem.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 38 | -------------------------------------------------------------------------------- /src/components/modal/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/page/content.vue: -------------------------------------------------------------------------------- 1 | 16 | 26 | -------------------------------------------------------------------------------- /src/components/page/foot.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/page/index.vue: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /src/components/page/link.vue: -------------------------------------------------------------------------------- 1 | 6 | 25 | -------------------------------------------------------------------------------- /src/components/page/login.vue: -------------------------------------------------------------------------------- 1 | 22 | 32 | -------------------------------------------------------------------------------- /src/components/page/navmenu.vue: -------------------------------------------------------------------------------- 1 | 56 | 128 | -------------------------------------------------------------------------------- /src/components/page/title.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/stars/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 66 | 67 | -------------------------------------------------------------------------------- /src/components/stars/stars.less: -------------------------------------------------------------------------------- 1 | @import '../variables.less'; 2 | .stars { 3 | display: flex; 4 | align-items: center; 5 | justify-content: flex-start; 6 | color: @color-primary; 7 | 8 | span { 9 | margin: 0 .2rem 0 0; 10 | line-height:1; 11 | position: relative; 12 | display:inline-block; 13 | } 14 | i { 15 | line-height:1; 16 | cursor: pointer; 17 | } 18 | .icon-copy{ 19 | position:absolute;bottom:0;margin-left:-100%; 20 | animation-duration: 1s; 21 | animation-fill-mode: forwards; 22 | } 23 | .effect-grow{ 24 | animation-name: grow; 25 | } 26 | .effect-rotate{ 27 | animation-name: grow-rotate; 28 | } 29 | .effect-fade{ 30 | animation-name: fade; 31 | } 32 | } 33 | @keyframes grow{0%{transform:scale(1)}99%{transform:scale(4);opacity:0;}to{transform:scale(1);opacity:0;}} 34 | @keyframes grow-rotate{0%{transform:scale(1) rotate(0deg)}99%{transform:scale(4) rotate(90deg);opacity:0}to{transform:scale(1) rotate(0deg);opacity:0;}} 35 | @keyframes fade{0%{transform:translate3d(0,0,0)}99%{transform:translate3d(0,-40px,0);opacity:0;}to{transform:scale(1) translate3d(0,0,0);opacity:0}} -------------------------------------------------------------------------------- /src/components/timeline/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/timeline/timeline.vue: -------------------------------------------------------------------------------- 1 | 6 | 85 | -------------------------------------------------------------------------------- /src/components/timeline/timelineitem.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | 18 | -------------------------------------------------------------------------------- /src/components/variables.less: -------------------------------------------------------------------------------- 1 | // 2 | // Variables 3 | // -------------------------------------------------- 4 | 5 | // Type 6 | // -------------------------------------------------- 7 | @font-family-default: "Helvetica Neue", Helvetica, "Microsoft Yahei", sans-serif; 8 | @font-size-default: 0.85rem; 9 | @font-weight: 500; 10 | @font-weight-light: 400; 11 | @line-height-default: 1.05rem; 12 | 13 | 14 | //img 15 | @imgBaseUrl: "../img"; 16 | 17 | // Colors 18 | // -------------------------------------------------- 19 | 20 | 21 | // 主色 22 | @color-primary: #04BE02; 23 | @color-danger: #f6383a; 24 | @color-warning: #f60; 25 | @color-success: #4cd964; 26 | 27 | @color-primary-active: darken(@color-primary, 10%); 28 | @color-danger-active: darken(@color-danger, 10%); 29 | @color-warning-active: darken(@color-warning, 10%); 30 | @color-success-active: darken(@color-success, 10%); 31 | 32 | @color-split: #e7e7e7; //分割线的颜色 33 | @color-bg: #eee; 34 | @color-text: #3d4145; //文案色 35 | @color-text-secondary: #5f646e; //次级文案 36 | @color-text-gray: #999; //灰色文案 37 | @color-text-gray-light: #ccc; //更灰色文案 38 | 39 | // 按钮色 40 | @color-btn-gray-light:#f7f7f7; 41 | @color-btn-gray-light-active:#dedede; 42 | 43 | 44 | //链接色 45 | @color-link: @color-primary; //链接色有可能不同于主色 46 | @color-link-active: @color-primary-active; //链接色有可能不同于主色 47 | 48 | @timing-fuction: cubic-bezier(.1,.5,.1,1); // Inspired by @c2prods 49 | 50 | 51 | // Borders 52 | // -------------------------------------------------- 53 | 54 | @border-default-width: 1px; 55 | @border-default-color: @color-split; 56 | @border-default: @border-default-width solid @border-default-color; 57 | @border-radius: 0.3rem; 58 | 59 | // timeline 60 | @timeline-item-bg-color: @color-primary; -------------------------------------------------------------------------------- /src/demos/404.vue: -------------------------------------------------------------------------------- 1 | 18 | 26 | -------------------------------------------------------------------------------- /src/demos/About.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/demos/Ajax.vue: -------------------------------------------------------------------------------- 1 | 30 | 53 | -------------------------------------------------------------------------------- /src/demos/Card.vue: -------------------------------------------------------------------------------- 1 | 125 | -------------------------------------------------------------------------------- /src/demos/Charts.vue: -------------------------------------------------------------------------------- 1 | 46 | 270 | -------------------------------------------------------------------------------- /src/demos/Collapse.vue: -------------------------------------------------------------------------------- 1 | 46 | -------------------------------------------------------------------------------- /src/demos/Content.vue: -------------------------------------------------------------------------------- 1 | 136 | -------------------------------------------------------------------------------- /src/demos/Icons.vue: -------------------------------------------------------------------------------- 1 | 64 | -------------------------------------------------------------------------------- /src/demos/Image.vue: -------------------------------------------------------------------------------- 1 | 138 | -------------------------------------------------------------------------------- /src/demos/Index.vue: -------------------------------------------------------------------------------- 1 | 129 | 148 | 156 | 157 | -------------------------------------------------------------------------------- /src/demos/Level.vue: -------------------------------------------------------------------------------- 1 | 249 | -------------------------------------------------------------------------------- /src/demos/Modal.vue: -------------------------------------------------------------------------------- 1 | 37 | 38 | 98 | -------------------------------------------------------------------------------- /src/demos/Nav.vue: -------------------------------------------------------------------------------- 1 | 153 | -------------------------------------------------------------------------------- /src/demos/Notifications.vue: -------------------------------------------------------------------------------- 1 | 86 | -------------------------------------------------------------------------------- /src/demos/Pagination.vue: -------------------------------------------------------------------------------- 1 | 13 | -------------------------------------------------------------------------------- /src/demos/Panel.vue: -------------------------------------------------------------------------------- 1 | 108 | -------------------------------------------------------------------------------- /src/demos/Progress.vue: -------------------------------------------------------------------------------- 1 | 51 | 79 | -------------------------------------------------------------------------------- /src/demos/Rating.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | -------------------------------------------------------------------------------- /src/demos/Table.vue: -------------------------------------------------------------------------------- 1 | 344 | -------------------------------------------------------------------------------- /src/demos/Tabs.vue: -------------------------------------------------------------------------------- 1 | 293 | 301 | 306 | -------------------------------------------------------------------------------- /src/demos/Tags.vue: -------------------------------------------------------------------------------- 1 | 151 | -------------------------------------------------------------------------------- /src/demos/Timeline.vue: -------------------------------------------------------------------------------- 1 | 113 | -------------------------------------------------------------------------------- /src/demos/Title.vue: -------------------------------------------------------------------------------- 1 | 98 | -------------------------------------------------------------------------------- /src/demos/Toast.vue: -------------------------------------------------------------------------------- 1 | 17 | 48 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | import Resource from 'vue-resource' 4 | import Moment from 'moment' // 时间处理插件 5 | 6 | // demos 7 | import App from './App' 8 | import Index from './demos/Index' 9 | import Form from './demos/Form' 10 | import About from './demos/About' 11 | import Rating from './demos/Rating' 12 | import Collapse from './demos/Collapse' 13 | import Toast from './demos/Toast' 14 | import Modal from './demos/Modal' 15 | import Pagination from './demos/Pagination' 16 | import Progress from './demos/Progress' 17 | import Notfound from './demos/404' 18 | import Timeline from './demos/Timeline' 19 | import Charts from './demos/Charts' 20 | 21 | // UI 22 | import Icons from './demos/Icons' 23 | import Nav from './demos/Nav' 24 | import Ajax from './demos/Ajax' 25 | import Panel from './demos/Panel' 26 | import Card from './demos/Card' 27 | import Level from './demos/Level' 28 | import MediaObject from './demos/MediaObject' 29 | import Message from './demos/Message' 30 | import Buttons from './demos/Buttons' 31 | import Content from './demos/Content' 32 | import Tags from './demos/Tags' 33 | import Title from './demos/Title' 34 | import Tabs from './demos/Tabs' 35 | import Table from './demos/Table' 36 | import Image from './demos/Image' 37 | import Notifications from './demos/notifications' 38 | 39 | // vuex store 40 | import store from './store' 41 | 42 | Vue.use(Router) 43 | Vue.use(Resource) 44 | Vue.http.options.emulateHTTP = true 45 | Vue.http.options.emulateJSON = true 46 | 47 | Moment.locale('zh-cn') 48 | 49 | // txt转码html 50 | Vue.filter('text2html', function (str) { 51 | return global.$fn.t2h(str) 52 | }) 53 | 54 | // 全局闭包,公用函数库,也可以放置到vuex2.0中 55 | global.$fn = { 56 | // ajax默认api地址,一般为API接口地址 57 | ajaxhost: '//。。。/api', 58 | // 获取url中的参数,允许默认值的设定 59 | getparam (name, defaultValue) { 60 | let reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)') 61 | let r = window.location.search.substr(1).match(reg) 62 | return (!r) ? ((!defaultValue) ? '' : defaultValue) : unescape(r[2]) 63 | }, 64 | moment: Moment, 65 | init () { 66 | // 登录或注销后需要清空cache 67 | store.commit('isAuth', false) 68 | store.commit('authToken', '') 69 | }, 70 | // 随机字符串 71 | getCode (n) { 72 | let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' 73 | let res = '' 74 | for (let i = 0; i < n; i++) { 75 | res += chars[Math.floor(Math.random() * chars.length)] 76 | } 77 | return res 78 | }, 79 | // text2html 80 | t2h (str) { 81 | let converter = document.createElement('DIV') 82 | converter.innerText = str 83 | let html = converter.innerHTML 84 | converter = null 85 | return html 86 | }, 87 | // cache 机制 88 | cache: [], 89 | // 默认300秒数据缓存时间 90 | exp: 300, 91 | getCache (url) { 92 | let json = this.cache[url] 93 | return (json && (json.exp >= this.timestamp())) ? json.data : null 94 | }, 95 | setCache (url, data, exp) { 96 | // 默认300秒,{data,exp} 97 | this.cache[url] = {data: data, exp: this.timestamp() + ((!exp) ? this.exp : exp)} 98 | // console.log(this.cache) 99 | }, 100 | // get方式 不鉴权,可进行数据缓存 101 | $get (ajaxurl, callback, callerr, exp) { 102 | // callback _self:this,data,ajax 103 | let url = ajaxurl 104 | let data = this.getCache(url) 105 | if (!data) { 106 | Vue.http.get(url, {}, { 107 | }).then((response) => { 108 | callback(response.data, true) 109 | if (!(exp && exp < 0)) this.setCache(url, response.data, exp) 110 | }, (response) => { 111 | this.ajaxerr(response) 112 | }) 113 | } else { 114 | callback(data, false) 115 | } 116 | }, 117 | // post带鉴权,不使用缓存 118 | $post (ajaxurl, param, callback, _self, exp) { 119 | let url = this.ajaxhost + ajaxurl 120 | _self.$http.post(url, param, { 121 | headers: { 122 | // 加入授权验证算法 123 | 'Authorization': 'test' 124 | } 125 | }).then(function (response) { 126 | callback(_self, response.data) 127 | }, function (response) { 128 | this.ajaxerr(response) 129 | }) 130 | }, 131 | // ajax错误处理 132 | ajaxerr (response) { 133 | // 此处需配合后端进行自定义的错误设置 134 | // console.log(response) 135 | switch (response.status) { 136 | case 0: // 网络不通 137 | this.toast('warning', '网络暂时未能连通') 138 | break 139 | case 401: // 未登录 140 | case 521: // 超时 141 | case 522: // 错误 142 | this.init() 143 | break 144 | case 523: 145 | this.toast('danger', '当前时间存在较大偏差') 146 | break 147 | case 524: 148 | this.toast('danger', '未找到相关数据') 149 | break 150 | default: 151 | // 其它错误,暂不处理 152 | break 153 | } 154 | }, 155 | toast (mode, title) { 156 | store.commit('toast', {id: new Date().getTime(), title: (title && title.length) > 0 ? title : '操作完成', mode: mode}) 157 | }, 158 | // 时间戳 159 | timestamp () { 160 | return Math.floor(new Date().getTime() / 1000) 161 | } 162 | } 163 | 164 | const routes = [ 165 | { 166 | path: '/', 167 | component: Index 168 | }, 169 | { 170 | path: '/index', 171 | component: Index 172 | }, 173 | { 174 | path: '/about', 175 | component: About 176 | }, 177 | { 178 | path: '/icons', 179 | component: Icons 180 | }, 181 | { 182 | path: '/buttons', 183 | component: Buttons 184 | }, 185 | { 186 | path: '/content', 187 | component: Content 188 | }, 189 | { 190 | path: '/tabs', 191 | component: Tabs 192 | }, 193 | { 194 | path: '/table', 195 | component: Table 196 | }, 197 | { 198 | path: '/title', 199 | component: Title 200 | }, 201 | { 202 | path: '/charts', 203 | component: Charts 204 | }, 205 | { 206 | path: '/tags', 207 | component: Tags 208 | }, 209 | { 210 | path: '/progress', 211 | component: Progress 212 | }, 213 | { 214 | path: '/image', 215 | component: Image 216 | }, 217 | { 218 | path: '/timeline', 219 | component: Timeline 220 | }, 221 | { 222 | path: '/collapse', 223 | component: Collapse 224 | }, 225 | { 226 | path: '/toast', 227 | component: Toast 228 | }, 229 | { 230 | path: '/modal', 231 | component: Modal 232 | }, 233 | { 234 | path: '/card', 235 | component: Card 236 | }, 237 | { 238 | path: '/level', 239 | component: Level 240 | }, 241 | { 242 | path: '/panel', 243 | component: Panel 244 | }, 245 | { 246 | path: '/message', 247 | component: Message 248 | }, 249 | { 250 | path: '/mediaobject', 251 | component: MediaObject 252 | }, 253 | { 254 | path: '/rating', 255 | component: Rating 256 | }, 257 | { 258 | path: '/pagination', 259 | component: Pagination 260 | }, 261 | { 262 | path: '/form', 263 | component: Form 264 | }, 265 | { 266 | path: '/ajax', 267 | component: Ajax 268 | }, 269 | { 270 | path: '/nav', 271 | component: Nav 272 | }, 273 | { 274 | path: '/notifications', 275 | component: Notifications 276 | }, 277 | { 278 | /* 279 | meta: { 280 | auth: true 281 | }, 282 | */ 283 | path: '/404', 284 | component: Notfound 285 | }, 286 | { 287 | path: '*', 288 | redirect: '/404' 289 | } 290 | ] 291 | const router = new Router({ 292 | base: '/admin/', 293 | mode: 'history', 294 | linkActiveClass: 'is-active', // router-link active样式 295 | /* 296 | 由于本项目采用内滚动布局,此处代码无效,需要自行hack vue-router获得此能力 297 | saveScrollPosition: true, 298 | scrollBehavior (to, from, savedPosition) { 299 | }, 300 | */ 301 | routes // short for routes: routes 302 | }) 303 | 304 | router.beforeEach((to, from, next) => { 305 | if (store.getters.getIsAuth || !to.meta.auth) { 306 | next() 307 | } else { 308 | // 判断是否登录,(可以通过接口,Vuex状态 token) 309 | // 没有登录走下面逻辑 310 | global.$fn.init() 311 | next() 312 | } 313 | }) 314 | 315 | new Vue({ 316 | router, 317 | render: h => h(App) 318 | }).$mount('#app') 319 | -------------------------------------------------------------------------------- /src/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | // 告诉 vue “使用” vuex 5 | Vue.use(Vuex) 6 | 7 | // 创建一个对象来保存应用启动时的初始状态 8 | const state = { 9 | // TODO: 放置初始状态 10 | isAuth: true, // 是否登录 11 | authToken: '', // ajax token 12 | account: {}, // 账户信息 13 | toastList: [], // 系统提示 14 | modal: false, // 全局modal 15 | preloader: false // preloader 16 | } 17 | 18 | // 创建一个对象存储一系列我们接下来要写的 mutation 函数 19 | const mutations = { 20 | // TODO: 放置我们的状态变更函数 21 | isAuth (state, status) { 22 | state.isAuth = status 23 | }, 24 | authToken (state, token) { 25 | state.authToken = token 26 | }, 27 | preloader (state, status) { 28 | state.preloader = status 29 | }, 30 | modal (state, status) { 31 | state.modal = status 32 | }, 33 | toast (state, json) { 34 | state.toastList.push(json) 35 | setTimeout(() => { 36 | state.toastList.shift() 37 | }, 2000) 38 | } 39 | } 40 | 41 | const getters = { 42 | getIsAuth: state => { return state.isAuth }, 43 | getAuthToken: state => { return state.authToken }, 44 | getToast: state => { return state.toastList }, 45 | getModal: state => { return state.modal }, 46 | getPreloader: state => { return state.preloader } 47 | } 48 | 49 | // 整合初始状态和变更函数,我们就得到了我们所需的 store 50 | // 至此,这个 store 就可以连接到我们的应用中 51 | export default new Vuex.Store({ 52 | state, 53 | getters, 54 | mutations 55 | }) 56 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wangxg2016/vue-bulma/24f4c30134cda1059d7444160a3f8e92450ff69c/static/.gitkeep -------------------------------------------------------------------------------- /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 | var 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 | var 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 | template: '
', 8 | components: { Hello } 9 | }).$mount() 10 | expect(vm.$el.querySelector('.hello h1').textContent).to.contain('Hello World!') 11 | }) 12 | }) 13 | -------------------------------------------------------------------------------- /web.manifest: -------------------------------------------------------------------------------- 1 | CACHE MANIFEST 2 | # 2016101103 3 | 4 | CACHE: 5 | //cdn.bootcss.com/font-awesome/4.6.3/css/font-awesome.min.css 6 | //cdn.bootcss.com/bulma/0.2.1/css/bulma.min.css 7 | //cdn.bootcss.com/font-awesome/4.6.3/fonts/fontawesome-webfont.woff2?v=4.6.3 8 | 9 | NETWORK: 10 | * 11 | --------------------------------------------------------------------------------