Vue2.0 踩坑、填坑指南

vue-cli + webpack + babel + es6 + vue路由 + vue交互 + vue2.0开发spa单页应用demo

Vue2.0 推荐开发环境

  • git(主要使用git Bash书写命令)
  • NodeJs(不只是一门后台语言,还是优秀的构建工具)
  • npm (NodeJs默认的包管理器,当然还有别的:Yarn)
  • webpack (Vue的组件是.vue,像微信小程序的.wxml、wxss,浏览器不能直接解析,需要编译和打包成.js文件)
  • vue-cli(为Vue生成固定工程模板的,就像Express生成的文件结构)

安装Git(按顺序安装即可)

  • Git-1.8.5.2-preview20131230.exe
  • TortoiseGit-1.8.7.0-64bit.msi
  • TortoiseGit-LanguagePack-1.8.7.0-64bit-zh_CN.msi

安装NodeJs(推荐6.9.1LTS)

NPM(NodeJs安装完自带npm)

  • 安装到本地包命令:npm install xxx 简写:npm i xxx
  • 安装到全局的命令:npm install xxx -g 简写:npm i xxx -g
  • 安装到依赖:npm install xxx –save 简写:npm i xxx -S
  • 安装开发时的依赖:npm install xxx –dev 简写:npm i xxx -D
  • 卸载本地包:npm uninstall xxx
  • 卸载全局包:npm uninstall xxx -g
  • 更新本地包:npm update xxx
  • 更新全局包:npm update xxx -g
  • 查看全局安装的包:npm ls -g
  • 清空npm本地缓存:npm cache clear
  • 创建工程文件(package.json):npm init –yes
  • 查看npm版本:npm -v
  • 查看npm所有命令:npm help
  • 安装淘宝npm镜像:npm install -g cnpm –registry=https://registry.npm.taobao.org
  • 使用淘宝npm镜像包:cnpm install xxx
  • 使用淘宝npm镜像包:cnpm install xxx -g

安装webpack

  • npm install webpack -g 或者 cnpm install webpack -g

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #配置文件:webpack.config.js
    var path = require('path')
    var webpack = require('webpack')
    module.exports = {
    entry: './src/app.js',
    output: {
    path: path.resolve(__dirname, './dist'),
    publicPath: './dist/',
    filename: 'build.js'
    },
    module: {
    rules: [
    {
    test: /\.vue$/,
    loader: 'vue-loader'
    },
    {
    test: /\.css$/,
    loader: 'style|css',
    exclude: /node_modules/
    },
    {
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: /node_modules/
    }
    ]
    }
    }
  • entry:文件入口,webpack会从入口点设置的js文件开始对项目进行构建
  • output:文件出口,打包好的js文件输出的路径和文件名
  • module:主要是loaders,这是webpack打包的解析器:vue、scss都要用npm安装相应的loader才能进行解析
  • plugins:指定webpack的插件,跟解析的语言无关,经常用来辅助构建,提供丰富的附加功能。
  • 根据实际的项目需要,结合一些webpack插件,可以实现很强大的功能,不需要另外使用gulp或者grunt。
  • 生成hash指纹:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    #hash:根据编译时资源对应的编译进程计算hash值
    #chunkhash:根据模块内容计算hash值
    #contenthash:根据文件的内容计算hash值
    output:{
    filename:'[name].[hash:8].js',
    filename:'[name].[chunkhash:8].js',
    filename:'[name].[contenthash:8].js'
    }
  • webpack提供了hash/chunkhash/contenthash三种生成生成规则,[hash:8]中的8是hash的位数

安装vue脚手架(类似express-generator)

  • 安装到全局:npm install vue-cli -g
  • 使用vue-cli init webpack xxx
  • 使用vue-cli init webpack-simple xxx
  • 使用vue-cli init browserify xxx
  • 使用vue-cli init browserify-simple xxx
  • 使用vue-cli init simple xxx
  • 我常用的:vue-cli init webpack-simple xxx
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    Administrator@VMTO /F/test
    $ vue init webpack-simple aaa
    A newer version of vue-cli is available.
    latest: 2.5.1
    installed: 2.4.0
    This will install Vue 2.x version of template.
    For Vue 1.x use: vue init webpack-simple#1.0 aaa
    ? Project name (aaa) #回车,项目名默认aaa
    ? Project description (A Vue.js project) #回车,项目描述默认A Vue.js project
    ? Author vmto <vmto@qq.com> #回车,默认作者和邮箱
    vue-cli · Generated "aaa".
    To get started:
    cd aaa
    npm install
    npm run dev
    #aaa文件结构:
    src #项目源文件
    .babelrc #babel转译规则(es6转es5、es7转es5)
    .gitignore #指定哪些文件不用提交到git仓库
    index.html #项目预览入口
    package.json #项目管理文件
    README.md #项目描述文件
    webpack.config.js #webpack配置文件

安装项目依赖(vue-cli用不到了)

  • npm install 或者 cnpm install
  • 启动项目:npm run dev
  • 如果有问题,试试把npm升级到最新:npm update -g
  • 如果有问题,试试把vue-cli升级到最新:npm update vue-cli
  • 遇到Module build failed: Error: Cannot find module ‘模块名’,那就安装
  • npm run dev,之后,浏览器会自动打开http://localhost:8080/

开始踩坑之旅

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#打开 src目录下的 App.vue
#template 写 html
#script写 js
#style 写样式
<template>
<div id="app">
<p>{{msg}}</p>
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
msg: 'hello App'
}
}
}
</script>
<style>
p{color:red;}
</style>

第一个坑:每个组件的template里面只能有一个并列的 div

1
2
3
4
5
6
7
8
9
10
<template>
<div id="app">
<p>{{msg}}</p>
</div>
<div id="app-in">
<p>{{msg}}</p>
</div>
</template>
#报错
#template syntax error Component template should contain exactly one root element

第二个坑:组件里的data不能直接return数据,要把数据放在json对象里面

1
2
3
4
5
6
7
8
9
10
<script>
export default {
name: 'app',
data () {
return msg: 'hello App'
}
}
#报错
#Module build failed: SyntaxError:/aaa/src/App.vue: Unexpected token, expected ;
</script>

踩坑之[组件间css冲突]

改造App.vue,增加子组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#src/App.vue
<template>
<div id="app">
<div id="app-in">
<p>{{msg}}</p>
</div>
<vbox>3.使用组件</vbox>
</div>
</template>
<script scoped>
//1.引入组件
import box from './component/Box.vue'
export default {
name: 'app',
data () {
return {
msg: 'hello App'
}
},
components:{//2.注册组件
vbox:box
//标签和组件同名,可以简写成box,而非vbox:box
}
}
</script>
<style scoped>
p{color:red;}
</style>

新建component目录,新建Box.vue组件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#src/component/Box.vue
<template>
<div class="box">
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: 'box',
data () {
return {
msg: 'hello Box'
}
}
}
</script>
<style>
p{color:blue;}
</style>

显示效果:

  • hello App
  • hello Box

一个小坑:
颜色被子组件覆盖,组件化不是能解决命名冲突吗?那说的是js变量名、函数名
css需在style标签上加上scoped,这是H5的新特性,其实不怪vue

1
2
3
4
5
6
7
8
9
#src/App.vue
<style scoped>
p{color:red;}
</style>
#src/component/Box.vue
<style scoped>
p{color:blue;}
</style>

修正后的颜色:

  • hello App
  • hello Box

踩坑之[vue-router]

首先用npm下载vue-router

1
2
$ npm i vue-router -S
#vue-router@2.0.3 node_modules\vue-router

新增 router.js ,并配置路由规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#src/router.js
import Foo from './component/Foo.vue'
import Bar from './component/Bar.vue'
// 配置路由规则
//vue1.x router.map 方法在 vue-router 2.x 已被废弃
export default{
mode: 'hash',//history|hash
base: __dirname,
routes:[
{path:'/foo',component:Foo},
{path:'/bar',component:Bar},
{path: '*',redirect:'/foo'},
]
}

router.js中用到的组件,foo和bar内容差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#src/component/Foo.vue
#src/component/Bar.vue
<template>
<div class="foo">
<p>{{msg}}</p>
</div>
</template>
<script>
export default {
name: 'foo',
data () {
return {
msg: 'hello Router Foo'
}
}
}
</script>
<style scoped>
p{
color:#555;
padding:10px;
border:1px solid blue;
}
</style>

修改 src/App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<template>
<div id="app">
<div id="app-in">
<p>{{msg}}</p>
</div>
<ul>
<li><router-link to="foo">foo</router-link></li>
<li><router-link to="bar">bar</router-link></li>
</ul>
<router-view></router-view>
<vbox>3.使用组件</vbox>
</div>
</template>
<script scoped>
//1.引入组件
import box from './component/Box.vue'
export default {
name: 'app',
data () {
return {
msg: 'hello App'
}
},
components:{//2.注册组件
vbox:box
//标签和组件同名,可以简写成box,而非vbox:box
}
}
</script>
<style scoped>
p{color:red;}
ul{
padding:10px;
border:1px solid red;
overflow:hidden;
}
ul li{
list-style:none;
float:left;
padding:0 10px;
color:#555;
}
.router-link-active{
color:red;
}
</style>

修改 src/main.js 引入并使用vue-router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#src/main.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
// 开启debug
Vue.config.debug = true;
// 引入组件
import App from './App.vue'
// 引入路由
import routes from './router'
// 配置路由规则
var router = new VueRouter(routes);
new Vue({
router,
render: h => h(App)
}).$mount('#app');

坑太多太多了,集中列出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#新增的API
router.back();
router.forward();
#废弃的API
hashbang
suppressTransitionError
#替换的API
router.map() (被 routes[] 取代了)
history (被 mode 取代)
abstract (被 mode 取代)
mode ("abstract"|"hash"|"history")默认:hash
root (被 base 取代)
v-link (被 router-link 取代)
router.redirect (被{path: '*',redirect:'/'}取代)

踩坑之[vue-resource]

首先用npm下载vue-resource

1
2
$ npm i vue-resource -S
#vue-resource@1.0.3 node_modules\vue-resource

修改 main.js ,引入并使用vue-resource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import Vue from 'vue'
import VueRouter from 'vue-router'
import vueResource from 'vue-resource';
Vue.config.debug = true;
Vue.use(VueRouter);
Vue.use(vueResource);
//无比关键
Vue.http.options.emulateJSON = true;
import App from './App.vue'
import routes from './router'
var router = new VueRouter(routes);
new Vue({
router,
render: h => h(App)
}).$mount('#app');

foo和bar组件内容差不多

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#src/component/Foo.vue
#src/component/Box.vue
<template>
<div class="bar">
<p>{{msg}}</p>
<ul>
<li v-for="(item,index) in items">{{index}}:{{item.title}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'bar',
data () {
return {
msg: 'hello Router Bar',
items:[]
}
},
mounted(){//等同1.x ready()
this.getList();
},
methods:{
getList(){
this.$http.jsonp('http://blog.totter.cn/',{
params:{
json:1,
count:5
}
}).then(function(res){
this.$data.items=res.data.posts;
console.log(res.data);
},function(err){
console.log(err);
});
}
}
}
</script>
<style scoped>
p{color:#555;padding:10px;border:1px solid blue;}
</style>

坑太多太多了,集中列出来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#$http请求和jquery的ajax有点区别,post请求的data默认不是以form data的形式,而是request payload
#解决办法一:
Vue.http.options.emulateJSON = true;
#解决办法二:
http: {
headers:{
'Content-Type':'application/x-www-form-urlencoded'
}
}
#vue-resource把ajax返回的数据做了包装
#数据在result.data上面
this.$http.get('http://www.xx.com/api.php',function(result) {
console.log(result);
console.log(result.data);
});
this.$http.post('http://www.xx.com/api.php',function(result) {
console.log(result);
console.log(result.data);
});
#参数需要写在params这个json对象里面
Vue.$http.jsonp('http://blog.totter.cn/',{
params:{
json:1,
count:5
}
}).then(function(result){
//success
},function(err){
//error
});
#NodeJs开发的api能让VueJs的使用者直接疯掉。
#这是个终极大坑(就算不写在params对象上,Vue会自动给你加上^_^)
app.post(url('get-all'), function(req, res) {
var body = req.body;
utils.sendData(res, body);
});
#解决办法(需要NodeJs后台开发者修改接口)
app.post(url('get-all'), function(req, res) {
var body = req.body.params || req.body;
utils.sendData(res, body);
});

此致敬礼(End)

坚持原创技术分享,您的支持将鼓励我继续创作!