Repository: vingojw/vue-vueRouter-webpack Branch: master Commit: 725b57409206 Files: 41 Total size: 75.2 KB Directory structure: gitextract_j0pr3bwt/ ├── .gitignore ├── Vue教程.md ├── index.html ├── index.tpl ├── package.json ├── readme.md ├── src/ │ ├── app.js │ ├── app.vue │ ├── components/ │ │ ├── aside.vue │ │ ├── globalmodal.vue │ │ ├── modal.vue │ │ ├── radio.vue │ │ ├── select.vue │ │ ├── tab.vue │ │ ├── tabset.vue │ │ └── toast.vue │ ├── css/ │ │ ├── a.css │ │ ├── animate.css │ │ ├── b.css │ │ └── common.css │ ├── filters.js │ ├── routers.js │ ├── views/ │ │ ├── about.vue │ │ ├── async.vue │ │ ├── async_loading.vue │ │ ├── forbidden.vue │ │ ├── home.vue │ │ ├── modal_view.vue │ │ ├── my_views.vue │ │ ├── my_views_detail.vue │ │ ├── not_found.vue │ │ ├── radio_view.vue │ │ ├── select_view.vue │ │ ├── slider_view.vue │ │ ├── tab_view.vue │ │ ├── test.vue │ │ └── touch.vue │ └── vtouch.js ├── vueComponent.sublime-snippet ├── webpack.config.js └── 约定.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ node_modules/ build/ d.html npm-debug.log ================================================ FILE: Vue教程.md ================================================ #Vue教程 [细节与最佳实践](http://vuejs.org/guide/best-practices.html) [Vue1.0.x文档](http://vuejs.org/) [Vue1.0.x绑定语法参考](https://github.com/vuejs/vue/issues/1325) [每次更新的变化](https://github.com/vuejs/vue/releases) 与webpack 一起使用所需插件 [vue-loader-example](https://github.com/vuejs/vue-loader-example) [vue-html-loader](https://github.com/vuejs/vue-html-loader) ####文章 `尤小右` [Vue.js:轻量高效的前端组件化方案](http://www.csdn.net/article/1970-01-01/2825439) `勾三股四` [Vue + webpack 项目实践](http://jiongks.name/blog/just-vue/) [Vue.js 源码学习笔记](http://jiongks.name/blog/vue-code-review/) `稀土掘金` [Vue 组件化开发实践](http://ftandy.github.io/2015/09/05/vue/) `Randy` [Vue.js 和 Webpack(一)为什么使用Vue](http://djyde.github.io/2015/08/29/vuejs-and-webpack-1.html) [Vue.js 和 Webpack(二)使用webpack](http://djyde.github.io/2015/08/30/vuejs-and-webpack-2.html) [Vue.js 和 Webpack(三)Vue.js + Webpack](http://djyde.github.io/2015/08/31/vuejs-and-webpack-3.html) #webpack教程 [learn-webpack](http://vingojw.github.io/2015/08/19/learn-webpack/) #Vue-router教程 [中文文档](http://vuejs.github.io/vue-router/zh-cn/index.html) - [英文文档](http://vuejs.github.io/vue-router/en/index.html) [学习笔记](https://github.com/vingojw/learn-vue-router) #技术交流 [Vue技术论坛](http://forum.vuejs.org/) [Vue的聊天室,很多人在里面讨论并解决问题](https://gitter.im/vuejs/vue) #demo [qingcheng](https://github.com/zerqu/qingcheng) [vue-strap 用vue实现bootstrap](https://github.com/yuche/vue-strap) [vue-mui](https://github.com/mennghao/vue-mui) [通过学习(copy)以上两个demo,使用 Vue1.0 + VueRouter + webpack](https://github.com/vingojw/vue-vueRoute-webpack) [Chat by Vue + Webpack](https://github.com/Coffcer/vue-chat) [用Vue实现的拖拽效果](http://jsfiddle.net/lain8dono/mrnyf79e/) ================================================ FILE: index.html ================================================
================================================ FILE: index.tpl ================================================
================================================ FILE: package.json ================================================ { "name": "learn-webpack", "version": "1.0.0", "main": "index.js", "dependencies": { "extract-text-webpack-plugin": "^0.8.2" }, "devDependencies": { "babel-core": "^6.3.17", "babel-loader": "^6.2.0", "babel-plugin-transform-runtime": "^6.3.13", "babel-preset-es2015": "^6.3.13", "babel-runtime": "^5.8.34", "css-loader": "^0.23.0", "cssnext-loader": "^1.0.1", "fastclick": "^1.0.6", "file-loader": "^0.8.4", "hammerjs": "^2.0.6", "html-loader": "^0.3.0", "html-webpack-plugin": "^1.6.2", "jshint-loader": "^0.8.3", "style-loader": "^0.13.0", "swiper": "^3.2.0", "url-loader": "^0.5.6", "vue": "^1.0.20", "vue-hot-reload-api": "^1.2.2", "vue-html-loader": "^1.1.0", "vue-loader": "^8.2.0", "vue-router": "^0.7.11", "vue-style-loader": "^1.0.0", "webpack": "^1.12.9", "webpack-dev-server": "^1.14.0", "webpack-zepto": "0.0.1" }, "scripts": { "mb": "export PRODUCTION=1 && webpack --progress --hide-modules", "wb": "set PRODUCTION=1 && webpack --progress --hide-modules", "dev": "webpack-dev-server --progress --profile --colors --inline ", "port": "webpack-dev-server --progress --colors --inline --port 9090 ", "hot": "webpack-dev-server --progress --colors --inline --hot", "cp": "cp -r index.html ./build/ d:/wamp/www/vue", "ip": "webpack-dev-server --progress --colors --hot --host=0.0.0.0 --port 9000" }, "author": "", "license": "ISC" } ================================================ FILE: readme.md ================================================ ## Setup ``` bash npm install npm run dev ``` 访问 localhost:8080 如果想在手机上查看 ``` npm run ip ``` 访问 你本地的ip:9000 ## 版本控制,打包压缩 MAC ``` npm run mb ``` windows ``` npm run wb ``` ## 目录结构
│  .gitignore          # 忽略无需git控制的文件  比如 node_modules
│  package.json        # 项目配置
│  readme.md           # 项目说明
│  index.html          # 首页
│  index.tpl           # 首页模板  在发布的时候 执行 PRODUCTION=1 webpack 会生成一个d.html并注入脚本,样式,达到版本控制的目的
│  webpack.config.js   # webpack 配置文件
│
├─node_modules
└─src
    │  app.js          # 启动配置,配置路由,过滤器
    │  app.vue         # 主vue
    │  filters.js      # 过滤器
    │  routers.js      # 路由
    │
    ├─components       # 组件
    │      my-component.vue
    │
    ├─css              # 公用样式
    │      common.css
    │
    └─views            # 页面
            about.vue
            home.vue
            not-found.vue
##学习参考: [qingcheng](https://github.com/zerqu/qingcheng) [vue-strap](https://github.com/yuche/vue-strap) ##项目 [m.yaomaiche.com](http://m.yaomaiche.com) ================================================ FILE: src/app.js ================================================ require('./css/common.css');//加载公共样式 require('./css/animate.css');//加载公共样式 var Vue = require('vue'); var VueTouch = require('./vtouch'); var VueRouter = require('vue-router'); var fastclick = require('fastclick'); fastclick.attach(document.body); // register filters 自定义过滤器 金额格式化, var filters = require('./filters'); Object.keys(filters).forEach(function(k) { Vue.filter(k, filters[k]); }); var App = Vue.extend(require('./app.vue')); /* 如果还想声明一个vue实例 要放在 Vue.use(VueRouter); 之前 因为当使用了 Vue.use(VueRouter)后,改写了 Vue 的实例化方法。 */ //var newV = new Vue();//注意看上面说明 Vue.use(VueTouch); Vue.use(VueRouter); var router = new VueRouter( { hashbang: true, //为true的时候 example.com/#!/foo/bar , false的时候 example.com/#/foo/bar //abstract:true, //地址栏不会有变化 //以下设置需要服务端设置 //history: false, //当使用 HTML5 history 模式时,服务器需要被正确配置 以防用户在直接访问链接时会遇到404页面。 //saveScrollPosition: false linkActiveClass:'custom-active-class' //全局设置连接匹配时的类名 参考http://vuejs.github.io/vue-router/en/link.html } ); require('./routers')(router); router.start(App,'#app'); ================================================ FILE: src/app.vue ================================================ ================================================ FILE: src/components/aside.vue ================================================ ================================================ FILE: src/components/globalmodal.vue ================================================ ================================================ FILE: src/components/modal.vue ================================================ ================================================ FILE: src/components/radio.vue ================================================ ================================================ FILE: src/components/select.vue ================================================ ================================================ FILE: src/components/tab.vue ================================================ ================================================ FILE: src/components/tabset.vue ================================================ ================================================ FILE: src/components/toast.vue ================================================ ================================================ FILE: src/css/a.css ================================================ .aaa{ background:red; } ================================================ FILE: src/css/animate.css ================================================ /*所有的动画*/ .slideleft-enter { animation:slideleft-in .3s; } .slideleft-leave { animation:slideleft-out .3s; } .slideright-enter { animation:slideright-in .3s; } .slideright-leave { animation:slideright-out .3s; } .slidetop-enter { animation:slidetop-in .3s; } .slidetop-leave { animation:slidetop-out .3s; } .slidebottom-enter { animation:slidebottom-in .3s; } .slidebottom-leave { animation:slidebottom-out .3s; } @keyframes slideleft-in { 0% { transform: translateX(-100%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes slideleft-out { 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(-100%); opacity: 0; } } @keyframes slideright-in { 0% { transform: translateX(100%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes slideright-out { 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(100%); opacity: 0; } } @keyframes slidetop-in { 0% { transform: translateY(-100%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes slidetop-out { 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateY(-100%); opacity: 0; } } @keyframes slidebottom-in { 0% { transform: translateY(100%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes slidebottom-out { 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateY(100%); opacity: 0; } } /*切换效果 -- 渐隐*/ .fadein-enter{ animation:fadein-in 0.3s ease; } .fadein-leave{ animation:fadein-out 0.3s ease; } /*切换效果 -- 从右渐入*/ .fadeInRight-enter { animation:fadeInRight-in 0.3s ease; } .fadeInRight-leave{ animation:fadeInRight-out 0.3s ease; } @keyframes fadein-in { 0% { opacity: 0; } 100% { opacity: 1; } } @keyframes fadein-out { 0% { opacity: 1; } 100% { opacity: 0; } } @keyframes fadeInRight-in { 0% { opacity: 0; transform: translate3d(2000px,0,0) } 100% { opacity: 1; transform: none } } @keyframes fadeInRight-out { 0% { opacity: 1; transform: none } 100% { opacity: 0; transform: translate3d(-2000px,0,0) } } ================================================ FILE: src/css/b.css ================================================ .bbb{ background:black; } ================================================ FILE: src/css/common.css ================================================ @charset "utf-8"; @font-face {font-family: "iconfont"; src: require('iconfont.woff') format('woff'), require('iconfont.ttf') format('truetype'), require('iconfont.svg#iconfont') format('svg'); } .iconfont { font-family:"iconfont" !important; font-style:normal; -webkit-font-smoothing: antialiased; -webkit-text-stroke-width: 0.2px; -moz-osx-font-smoothing: grayscale; } .icf-user:before { content: "\e61b"; } .icf-arrow-right:before { content: "\e61c"; } .icf-change:before { content: "\e626"; } .icf-male:before { content: "\e616"; } .icf-sales:before { content: "\e600"; } .icf-stars:before { content: "\e624"; } .icf-brand:before { content: "\e602"; } .icf-shop:before { content: "\e612"; } .icf-time:before { content: "\e603"; } .icf-pay:before { content: "\e604"; } .icf-path:before { content: "\e61d"; } .icf-gengduo:before { content: "\e61e"; } .icf-like:before { content: "\e605"; } .icf-area:before { content: "\e606"; } .icf-addr:before { content: "\e607"; } .icf-add:before { content: "\e60d"; } .icf-checked:before { content: "\e609"; } .icf-home:before { content: "\e60a"; } .icf-add1:before { content: "\e601"; } .icf-repair:before { content: "\e608"; } .icf-share:before { content: "\e629"; } .icf-calendar:before { content: "\e60b"; } .icf-star:before { content: "\e614"; } .icf-weixin:before { content: "\e618"; } .icf-message:before { content: "\e60c"; } .icf-edit:before { content: "\e615"; } .icf-mianfeibaojia:before { content: "\e62a"; } .icf-xie:before { content: "\e62b"; } .icf-shield:before { content: "\e619"; } .icf-change1:before { content: "\e627"; } .icf-pengyouquan:before { content: "\e62e"; } .icf-sad:before { content: "\e620"; } .icf-tel:before { content: "\e60e"; } .icf-gift:before { content: "\e625"; } .icf-radio-active:before { content: "\e621"; } .icf-info:before { content: "\e60f"; } .icf-female:before { content: "\e617"; } .icf-radio:before { content: "\e622"; } .icf-location:before { content: "\e61f"; } .icf-filter:before { content: "\e610"; } .icf-coupon:before { content: "\e61a"; } .icf-complete:before { content: "\e611"; } .icf-scan:before { content: "\e628"; } .icf-map:before { content: "\e613"; } .icf-right:before { content: "\e623"; } .icf-xphoto:before { content: "\e62c"; } .icf-add2:before { content: "\e62d"; } body{ margin:0; } ================================================ FILE: src/filters.js ================================================ function timeago(time) { time = new Date(time); var delta = parseInt((new Date() - time) / 1000, 10); if (delta <= 0) return 'just now'; var minutes = delta / 60; if (minutes < 1) return 'less than a minute ago'; if (minutes < 2) return 'about a minute ago'; var hours = minutes / 60; if (hours < 1) return parseInt(minutes, 10) + ' minutes ago'; if (hours < 1.5) return 'about an hour ago'; var days = hours / 24; if (days < 1) return Math.round(hours) + ' hours ago'; if (days < 7) return parseInt(days, 10) + ' days ago'; var month = time.getMonth(); if (month < 10) month = '0' + month; var date = time.getDate(); if (date < 10) date = '0' + date; return [time.getFullYear(), month, date].join('-'); } function urlize(text) { if (!text) return ''; var pattern = /https?:\/\/[^\s<]+[^<.,:;"')\]\s]/g; return text.replace(pattern, function(u) { var t = u.replace('http://', ''); return '' + t + ''; }); } //获取图片地址,如果地址带有 http://那么就认为是绝对地址,然后直接返回 function imgUrl(url){ if(url.match(/http:\/\//)){ return url; } //全站统一配置,页面首先会引用 if(window.abp){ return window.abp.imageDomain + url; } var testUrl = 'http://img.yaomaiche.com'; //此url到时候走配置 if(this.isTest){ testUrl = 'http://img.test.yaomaiche.com'; } return testUrl + url; } //显示价格 function price(value,currency){ var digitsRE = /(\d{3})(?=\d)/g value = parseFloat(value) if (!isFinite(value) || (!value && value !== 0)) return '' currency = currency != null ? currency : '¥' var stringified = Math.abs(value).toFixed(2) var _int = stringified.slice(0, -3) var i = _int.length % 3 var head = i > 0 ? (_int.slice(0, i) + (_int.length > 3 ? ',' : '')) : '' var _float = stringified.slice(-3) var sign = value < 0 ? '-' : '' return currency + sign + head + _int.slice(i).replace(digitsRE, '$1,') + _float } exports.imgUrl = imgUrl; exports.price = price; exports.timeago = timeago; exports.urlize = urlize; ================================================ FILE: src/routers.js ================================================ module.exports = function(router){ router.map({ '/':{ name:'home', component: require('./views/home.vue') }, '/about':{ name:'about', component: function(reslove){ return require(['./views/about.vue'],reslove) } }, '/my_views': { name:'my_views', component: require('./views/my_views.vue') }, '/my_views/:viewId': { name:'my_views_detail', component: require('./views/my_views_detail.vue'), auth: true // 此页面需要用户登录 }, '/modal_view': { name:'modal_view', component: require('./views/modal_view.vue') }, '/select_view': { name:'select_view', component: require('./views/select_view.vue') }, '/radio_view': { name:'radio_view', component: require('./views/radio_view.vue') }, '/tab_view': { name:'tab_view', component: require('./views/tab_view.vue') }, '/slider_view': { name:'slider_view', component: require('./views/slider_view.vue') }, '/forbidden':{ name:'forbidden', component: require('./views/forbidden.vue') }, '/test':{ name:'test_view', component: require('./views/test.vue') }, 'async':{ //http://forum.vuejs.org/topic/114/vue-router-异步加载的例子 //http://vuejs.github.io/vue-router/zh-cn/lazy.html name:'async', component: function(reslove){ //异步加载, //例子 return require(['./views/async.vue'],reslove) } }, 'async_loading':{ //http://forum.vuejs.org/topic/114/vue-router-异步加载的例子 name:'async_loading', component: function(reslove){ //异步加载, //例子 return require(['./views/async_loading.vue'],reslove) } }, //触摸事件 'touch':{ name:'touch', component:function(reslove){ return require(['./views/touch.vue'],reslove) } }, // not found handler '*': { component: require('./views/not_found.vue') } }); window.routeList=[]; router.beforeEach(function(transition){ console.log('before---------------'); //可以通过在路由中的自定义字段来验证用户是否需要登陆 // if(transition.to.auth){ // console.log('通过配置路由中自定义的字段验证是否需要登陆'); // } // //如果是中止,这里可以判断用户登录 // //if(transition.to.path === '/forbidden'){ if(transition.to.name == 'forbidden'){ router.app.authenticating = true setTimeout(function(){ router.app.authenticating = false alert('此路由在全局中设置为中止'); transition.abort(); },1500); } if(routeList.length > 1 && transition.to.name==routeList[routeList.length-2]['name']){ router.app.effect='back'; routeList.splice(routeList.length-1,1); console.log(routeList); } else { router.app.effect='fade'; routeList.push({ name : transition.to.name, path : transition.to.path, query : transition.to.query, params : transition.to.params, timer: +new Date }); } //setTimeout(function(){ transition.next(); //},1000); }); //可以记录访问路径 router.afterEach(function(transition){ console.log('-----------------after'); for (var i = 0; i < routeList.length; i++) { console.log(routeList[i].name); }; }); } ================================================ FILE: src/views/about.vue ================================================ ================================================ FILE: src/views/async.vue ================================================ ================================================ FILE: src/views/async_loading.vue ================================================ ================================================ FILE: src/views/forbidden.vue ================================================ ================================================ FILE: src/views/home.vue ================================================ ================================================ FILE: src/views/modal_view.vue ================================================ ================================================ FILE: src/views/my_views.vue ================================================ ================================================ FILE: src/views/my_views_detail.vue ================================================ ================================================ FILE: src/views/not_found.vue ================================================ ================================================ FILE: src/views/radio_view.vue ================================================ ================================================ FILE: src/views/select_view.vue ================================================ ================================================ FILE: src/views/slider_view.vue ================================================ ================================================ FILE: src/views/tab_view.vue ================================================ ================================================ FILE: src/views/test.vue ================================================ ================================================ FILE: src/views/touch.vue ================================================ ================================================ FILE: src/vtouch.js ================================================ var vueTouch = {} var Hammer = typeof require === 'function' ? require('hammerjs') : window.Hammer var gestures = ['tap', 'pan', 'pinch', 'press', 'rotate', 'swipe'] var customeEvents = {} vueTouch.install = function (Vue) { Vue.directive('touch', { isFn: true, acceptStatement: true, bind: function () { if (!this.el.hammer) { this.el.hammer = new Hammer.Manager(this.el) } var mc = this.mc = this.el.hammer // determine event type var event = this.arg var recognizerType, recognizer if (customeEvents[event]) { // custom event var custom = customeEvents[event] recognizerType = custom.type recognizer = new Hammer[capitalize(recognizerType)](custom) recognizer.recognizeWith(mc.recognizers) mc.add(recognizer) } else { // built-in event for (var i = 0; i < gestures.length; i++) { if (event.indexOf(gestures[i]) === 0) { recognizerType = gestures[i] break } } if (!recognizerType) { console.warn('Invalid v-touch event: ' + event) return } recognizer = mc.get(recognizerType) if (!recognizer) { // add recognizer recognizer = new Hammer[capitalize(recognizerType)]() // make sure multiple recognizers work together... recognizer.recognizeWith(mc.recognizers) mc.add(recognizer) } } }, update: function (fn) { var mc = this.mc var vm = this.vm var event = this.arg // teardown old handler if (this.handler) { mc.off(event, this.handler) } // define new handler this.handler = function (e) { e.targetVM = vm fn.call(vm, e); } mc.on(event, this.handler) }, unbind: function () { this.mc.off(this.arg, this.handler) if (!Object.keys(this.mc.handlers).length) { this.mc.destroy() this.el.hammer = null } } }) } /** * Register a custom event. * * @param {String} event * @param {Object} options - a Hammer.js recognizer option object. * required fields: * - type: the base recognizer to use for this event */ vueTouch.registerCustomEvent = function (event, options) { options.event = event customeEvents[event] = options } function capitalize (str) { return str.charAt(0).toUpperCase() + str.slice(1) } module.exports = vueTouch; ================================================ FILE: vueComponent.sublime-snippet ================================================ ]]> vueComponent ================================================ FILE: webpack.config.js ================================================ //先清空 n-build 文件夹下的文件 var fs = require('fs'),buildPath='./build/'; var folder_exists = fs.existsSync(buildPath); if(folder_exists == true) { var dirList = fs.readdirSync(buildPath); dirList.forEach(function(fileName) { fs.unlinkSync(buildPath + fileName); }); console.log("clearing " + buildPath); }; //readfile //先把index.html里面关于style和js的hash值都删除掉,避免在使用 npm run dev 的时候,路径还是压缩后的路劲 fs.readFile("index.html",'utf-8',function(err,data){ if(err){ console.log("error"); }else{ //将index.html里面的hash值清除掉 var devhtml = data.replace(/((?:href|src)="[^"]+\.)(\w{20}\.)(js|css)/g, '$1$3'); fs.writeFileSync('index.html', devhtml); } }); var webpack = require('webpack'); //var vue = require("vue-loader"); //混淆压缩 var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin; //检测重用模块 var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin; //独立样式文件 var ExtractTextPlugin = require("extract-text-webpack-plugin"); // 在命令行 输入 “PRODUCTION=1 webpack --progress” 就会打包压缩,并且注入md5戳 到 index.html里面 var production = process.env.PRODUCTION; var plugins = [ //会将所有的样式文件打包成一个单独的style.css new ExtractTextPlugin( production ? "style.[hash].css" : "style.css" , { disable: false//, //allChunks: true //所有独立样式打包成一个css文件 }), //new ExtractTextPlugin("[name].css" ) //自动分析重用的模块并且打包成单独的文件 new CommonsChunkPlugin(production ? "vendor.[hash].js" : "vendor.js" ), function(){ return this.plugin('done', function(stats) { var content; //这里可以拿到hash值 参考:http://webpack.github.io/docs/long-term-caching.html content = JSON.stringify(stats.toJson().assetsByChunkName, null, 2); console.log('版本是:'+JSON.stringify(stats.toJson().hash)); //return fs.writeFileSync('build/assets.json', content); }); } ]; //发布编译时,压缩,版本控制 if (process.env.PRODUCTION) { //压缩 plugins.push(new webpack.optimize.UglifyJsPlugin({compress: {warnings: false } })); } /* 版本控制 package.json中的 "html-webpack-plugin": "^1.6.2", 模块是把生成的带有md5戳的文件,插入到index.html中。 通过index.tpl模板,生成 index.html */ var HtmlWebpackPlugin = require("html-webpack-plugin"); //HtmlWebpackPlugin文档 https://www.npmjs.com/package/html-webpack-plugin //https://github.com/ampedandwired/html-webpack-plugin/issues/52 plugins.push( new HtmlWebpackPlugin({ filename:'../index.html',//会生成index.html在根目录下,并注入脚本 template:'index.tpl', inject:true //此参数必须加上,不加不注入 })); module.exports = { entry: ["./src/app.js"], output: { path: "./build", /* publicPath路径就是你发布之后的路径, 比如你想发布到你站点的/util/vue/build 目录下, 那么设置 publicPath: "/util/vue/build/", 此字段配置如果不正确,发布后资源定位不对,比如:css里面的精灵图路径错误 */ publicPath: "/build/", filename: production ? "build.[hash].js" : "build.js"//"build.[hash].js"//[hash]MD5戳 解决html的资源的定位可以使用 webpack提供的HtmlWebpackPlugin插件来解决这个问题 见:http://segmentfault.com/a/1190000003499526 资源路径切换 }, module: { preLoaders:[ // { // //代码检查 // test:/\.js$/,exclude:/node_modules/,loader:'jshint-loader' // } ], loaders: [ // 加载vue组件,并将css全部整合到一个style.css里面 // 但是使用这种方式后 原先可以在vue组件中 在style里面加入 scoped 就不能用了, // 好处是使用了cssnext,那么样式按照标准的来写就行了,会自动生成兼容代码 http://cssnext.io/playground/ { test: /\.vue$/, loader: 'vue' }, {test: /\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader?sourceMap!cssnext-loader")}, {test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192'}, // 内联 base64 URLs, 限定 <=8k 的图片, 其他的用 URL {test: /\.woff$/, loader: "url?limit=10000&minetype=application/font-woff"}, {test: /\.ttf$/, loader: "file"}, {test: /\.eot$/, loader: "file"}, {test: /\.svg$/, loader: "file"} ] }, vue:{ css:ExtractTextPlugin.extract("style-loader", "css-loader?sourceMap!cssnext-loader") }, plugins : plugins, devtool: 'source-map'//, // resolve: { // // 现在可以写 require('file') 代替 require('file.coffee') // extensions: ['', '.js', '.json', '.coffee','vue'] // } }; ================================================ FILE: 约定.md ================================================ #### 使用具名路径 ``` User ``` #### 组件传值的时候单个单词小写,如果有多个单词用"-"连接 [API说明](http://rc.vuejs.org/guide/components.html#camelCase_vs-_kebab-case) ``` ``` 然后在组件props中用驼峰的方式访问['mutilCheck']。 #### 组件传值得时候尽量不要使用表达式,可以在computed中定义 比如: ``` ``` 修改为 ``` ``` 然后定义computed ``` ... computed:{ singleCheck:function(){ return false; } }, ... ``` #### 在绑定属性的时候 ```
此处的 transition="transiton" 代表的是 transition 这个类名 ``` 而如果前面加个`:`则代表的是动态属性,: 是 v-bind的简写 参考 [Vue1.0.0绑定语法参考](https://github.com/vuejs/vue/issues/1325) ```
``` #### 绑定属性用双引号 #### 关于 vueComponent.sublime-snippet 文件 ``` 功能:sublime中编写vue组件的片段提示 使用: sublime中 菜单栏 - >Preferences - > 浏览插件 将文件复制到 User目录下 项目中新建 `组件名字.vue` 文件 ctrl+shift+p 输入 vuecomponent 回车 ``` #### 在vue组件 template 中不能出现 `<` 字符, 如果有此字符,那么在使用webpack.optimize.UglifyJsPlugin压缩的时候,编译会报错 #### DOM属性定义用""包起来,否则不正确的字符可能会导致在 使用webpack.optimize.UglifyJsPlugin压缩的时候,控制台卡死。 #### vue文件的,template模版中,注释的html里面如果有img标签,相关资源也会被打包。 ``` ``` #### 在data属性里面不要定义以下划线开头的字段。 ``` data:{ _k:'v' // this._k 获取不到 } ``` #### vue-router路由配置的时候,不要写下划线 ``` '/loan':{ name:'loan', component: require('./views/loan.vue') }, '/loan_old':{ name:'xxx', component: require('./views/loan_old.vue') }, 下面的会覆盖上面的,原来本应该跳转到loan的可能现在都跳到了loan_old ``` #### 关于版本控制 参考: [http://webpack.github.io/docs/long-term-caching.html](http://webpack.github.io/docs/long-term-caching.html) [https://github.com/teambition/coffee-webpack-starter/blob/92082085d96f6c5003711e042da38bfa140d8dd6/webpack.min.coffee#L21](https://github.com/teambition/coffee-webpack-starter/blob/92082085d96f6c5003711e042da38bfa140d8dd6/webpack.min.coffee#L21) ``` plugins: [ new webpack.optimize.CommonsChunkPlugin('vendor', 'vendor.[chunkhash:8].js'), new webpack.optimize.UglifyJsPlugin({sourceMap: false}), new ExtractTextPlugin("style.[chunkhash:8].css"), function() { return this.plugin('done', function(stats) { var content; content = JSON.stringify(stats.toJson().assetsByChunkName, null, 2); return fs.writeFileSync('build/assets.json', content); }); } ] ``` #### 禁止在层上滑动(比如:背景层,不想让用户滚动) ``` @touchstart.stop.prevent ``` #### 如果要阻止默认事件,一定要写在前面,否则会影响其他事件绑定 ``` @touchmove.stop.prevent @click.stop="show=false" ``` #### 尽量少用