看了一个礼拜的 vue.js ,不得不说,入门是很容易的,学习曲线也相对平缓。数据的双向绑定也另开发顺畅,特别是一些交互比较复杂的项目。
来简单说一下利用 vue-cli 脚手架
进行项目开发,我个人的一些实战总结吧,项目是基于 vue2.0
做开发的。
vue-cli 脚手架项目的目录 build 下有 3个基础配置文件:
webpack.base.conf.js
webpack.dev.conf.js
webpack.prod.conf.js ,
用来构建 运行时项目,和构建发布时项目
基础配置文件
module: { loaders: [ { test: //.vue$/, loader: 'vue' }, { test: //.js$/, loader: 'babel', include: projectRoot, exclude: /node_modules/ }, { test: //.json$/, loader: 'json' }, { test: //.(png|jpe?g|gif|svg)(/?.*)?$/, loader: 'url', query: { limit: 10000, name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { test: //.(woff2?|eot|ttf|otf)(/?.*)?$/, loader: 'url', query: { limit: 10000, name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] },
module 下面的配置其中需要说明的一点是 配置中有对 10000b 的图片大小进行base64转换,折算一下就是 9.765625kb
,所以项目中对一下小的 icon 不必做图片精灵处理。
在 webpack.base.conf.js 文件的结尾处还有这么一段配置:
vue: { loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), postcss: [ require('autoprefixer')({ browsers: ['last 2 versions'] }) ] }
为什么单独拿出来说呢,因为在项目开发的时候遇到一点小坑 , autoprefixer
一个浏览器自动兼容插件, browsers: ['last 2 versions']
意思是只对主流浏览器的最新两个版本(其实也就是不做兼容了,现代最新的浏览器基本都不需要兼容了呀),所以我在写一个 css3 动画
的时候就发现较低版本的Android设备居然不运行。
配置如下就好了:意思是 对 主流浏览器的最新五个版本和对 Android4.0以上
的版本做兼容
vue: { loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), postcss: [ require('autoprefixer')({ browsers: ['last 5 versions', 'Android >= 4.0'] }) ] }
当我们在项目运行 npm run dev
就会执行这个脚本进行项目构建,值得一提的是配置文件中有个
html-webpack-plugin
插件,用于热刷新浏览器,当你编辑完 .vue文件
, command+s
保存一下浏览器就会自动刷新了。
当我们要上线项目可以用 npm run build
对咱们的项目进行构建,webpack 会帮我们压缩css 和js文件,并加上哈希值,还有生成对应文件的 SourceMap 文件
,因为压缩后的css或js文件你没办法看,调试的时候出了错误可以利用 SourceMap
来查看代码对应的位置。 那我项目确保没bug了怎么把 SourceMap
关掉呢,毕竟线上项目是不想让别人看到具体源代码的。
那就找到 项目中 config文件夹
下 index.js
文件对应下的配置:
module.exports = { build: { //... productionSourceMap: false,
将 productionSourceMap
置为 false
再次 npm run build
一样就不会构建出 .map 文件
了
希望你在看这篇博文的时候是有点 vue 基础的,对 vue开发有所了解,本篇文章不会介绍 vue 的基础内容, 因为 [vue.js官网][1] 已经很简单详细了。 本篇会讲一些实战开发的整体架构,和开发当中的一些实用的 知识点和技巧
虽然 vue 是对数据双向绑定,如何管理好你的数据就需要多费点心思考虑一下了,不然到实际项目中,独立出独立的组件,而组件之间又存在数据或交互,那么数据传递将会异常的繁琐。
这里我建议 在 App.vue (或超父组件) 里维护一套 全局 data
,如下图:
父组件 appVue.vue
<template> <div id="appVue"> <page1 v-bind:infodata="infodata"></page1> </div> </template> <script type="text/ecmascript-6"> import page1 from './components/page1/page1'; export default { name: 'appVue', data(){ return { infodata:{ ‘name’:’曾田生’, ‘age’:'24' } } }, components: { page1 } } </script> <style lang="scss"> </style>
子组件 page1
<template> <div id="page1"> <p>{{infodata.name}}</p> <p>{{infodata.age}}</p> </div> </template> <script type="text/ecmascript-6"> export default { props: { infodata: { type: Object, default: function () { return{ ‘name’:’xxx’, ‘age’:'111' } } } } } </script> <style lang="scss"> </style>
父组件 通过 v-bind
将组件的 data 数据
绑定在子组件上,子组件再利用 props对象
接收父组件传递过来的值,接着就可以像组件的 data 数据一样尽情的使用了。
有这么一个场景是:子组件拿到了父组件给过来的值,但随着用户对父组件的操作,数据要反馈到子组件上, 那么这个场景就可以使用 vue 的 watch对象
<template> <div id="page1"> <p>{{infodata.name}}</p> <p>{{infodata.age}}</p> </div> </template> <script type="text/ecmascript-6"> export default { props: { infodata: { type: Object, default: function () { return{ ‘name’:’xxx’, ‘age’:'111' } } } }, watch:{ ’infodata’:function(){ console.log('infodata 数据变化会触发我这个方法的执行' ); } } } </script> <style lang="scss"> </style>
利用 watch
对象 来监听 props对象中 infodata属性的变化 ,当然了,也可以用来监听 组件中 data数据的变化
有时候咱们需要在父组件里调用子组件的方法,利用强大的 vue 也是很容易做到的
父组件:
给子组件上注册引用信息 ref="page1"
,拿到改引用信息 this.$refs.page1
,其实也就是获取子组件的意思, 接着调用子组件的方法 this.$refs.page1.handleParentClick()
; handleParentClick
是方法名,
可以自定,只要子组件也有对应的方法名即可。
<template> <div id="appVue"> <div class='ddiv' @click="divClick" ></div> <page1 ref="page1" :infodata="infodata"></page1> </div> </template> <script type="text/ecmascript-6"> import page1 from './components/page1/page1'; export default { name: 'appVue', data(){ return { infodata:{ ‘name’:’曾田生’, ‘age’:'24' } } }, methods:{ divClick:function(){ //调用子组件 page1 的 handleParentClick 方法 this.$refs.page1.handleParentClick(); } }, components: { page1 } } </script> <style lang="scss"> </style>
子组件:
子组件在 methods 对象里声明 被父组件调用的方法 handleParentClick
<template> <div id="page1"> <p>{{infodata.name}}</p> <p>{{infodata.age}}</p> </div> </template> <script type="text/ecmascript-6"> export default { props: { infodata: { type: Object, default: function () { return{ ‘name’:’xxx’, ‘age’:'111' } } } }, watch:{ ’infodata’:function(){ console.log('infodata 数据变化会触发我这个方法的执行' ); } }, methods:{ handleParentClick: function () { console.log('父组件唤起了该方法的执行' ); } } } </script> <style lang="scss"> </style>
上面第4点讲了父组件可以调用子组件的方法,但是 子组件是不能调用父组件的方法的,为了保护父组件 数据不被污染或破坏。但 vue 也用了一套方法 来将子组件的数据回传给父组件。 组件除了可以给 div 加上 `v-on:click = 'doSomething'` 来对 div监听点击事件外,父组件还可以 用 `v-on:name='listenChild' `来监听子组件传递给父组件的数据。
父组件:
父组件可以在使用子组件的地方直接用 v-on
来监听子组件触发的事件。
<template> <div id="appVue"> <div class='ddiv' @click="divClick" ></div> <page1 v-on:page-to-appvue='listenChild' ref="page1" :infodata="infodata"></page1> </div> </template> <script type="text/ecmascript-6"> import page1 from './components/page1/page1'; export default { name: 'appVue', data(){ return { infodata:{ ‘name’:’曾田生’, ‘age’:'24' } } }, methods:{ listenChild: function (msg) { console.log('监听子组件传递过来的数据'+msg+‘并触发改方法的执行’ ); }, divClick:function(){ //调用子组件 page1 的 handleParentClick 方法 this.$refs.page1.handleParentClick(); } }, components: { page1 } } </script> <style lang="scss"> </style>
子组件:
使用 $emit(eventName)
触发事件
<template> <div id="page1"> <div @click="divClick" ></div> <p>{{infodata.name}}</p> <p>{{infodata.age}}</p> </div> </template> <script type="text/ecmascript-6"> export default { props: { infodata: { type: Object, default: function () { return{ ‘name’:’xxx’, ‘age’:'111' } } } }, watch:{ ’infodata’:function(){ console.log('infodata 数据变化会触发我这个方法的执行' ); } }, methods:{ divClick:function(){ // 给父组件发送消息 this.$emit('page-to-appvue',{‘name’:’xxx’,‘age’:'111'}); }, handleParentClick: function () { console.log('父组件唤起了该方法的执行' ); } } } </script> <style lang="scss"> </style>
做前端开发一般不会只做静态页面,特别是使用 vue 框架的时候,一般是具有复杂点的数据交互你才选择它。 那就免不了需后台数据的调试,咱们可以先写好接口,再模拟一下后台数据,到时候前后端数据联调 就会轻松多了
在项目的跟目录下模拟一份json数据:
data.json
{ "userData": { "id": 1, "openid": "oC_mwjjqkqwsjm9Yvoq-Zk06Nntsws", "nickname": "曾田生", "sex": 1, "language": "zh_CN", "city": "Zhangzhou", "province": "Fujian", "country": "China", "headimgurl": "http://wx.qlogo.cn/mmopen/H5nYy4sS0Dt1ChHtmOHwfTX86TjV1b28afBSIDsDoMVttaO213SlZUsmNGAX9h73mtJJvEcruOibbM0tSia6AfBgrqP4ibaXMJyTa/0", "privilege": "", "unionid": "oEexiuGFcp_4a1oPSsKLkMS938Tlg", "goTo": "23,43,12,34,34", "wantTo": "34", "createTime": 1483002136000 } }
当咱们执行 npm run dev
的时候会执行项目 build 目录下的 dev-server.js
的这个 server文件
,
咱们就在这个文件里头配置一些路由,模拟一些供页面访问的接口。
往 dev-server.js
脚本插入如下代码, 模拟监听来自 客户端的请求
var express = require('express') var bodyParser = require('body-parser'); var app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); // 获取模拟数据 var appData = require('../data.json'); var userData = appData.userData; // get请求 app.get('/process_get', function (req, res) { // 输出 JSON 格式 var response = { err:0, data:userData }; res.end(JSON.stringify(response)); }) // post 请求 app.post('/getUserData', function (req,res) { var response = { err:0, data:userData }; res.end(JSON.stringify(response)); });
在客户端组件里发起请求:
<template> <div id="appVue"> <div class='ddiv' @click="divClick" ></div> <page1 v-on:page-to-appvue='listenChild' ref="page1" :infodata="infodata"></page1> </div> </template> <script type="text/ecmascript-6"> import VueResource from 'vue-resource'; // 全局注册 ,将组件添加到 vue 里面 Vue.use(VueResource); import page1 from './components/page1/page1'; export default { name: 'appVue', data(){ return { infodata:{ ‘name’:’曾田生’, ‘age’:'24' } } }, created(){ // 客户端 post 请求 this.$http.post('/getUserData', {'openid': urlFrom.openid}).then((response) => { var resData = JSON.parse(response.body); if (resData.err === 0) { // 请求成功,返回数据 } else { console.log('---------ERR-----------'); } }); // 客户端 get 请求 this.$http.get('/getUserData').then((response) => { response = response.body; } }); } methods:{ listenChild: function (msg) { console.log('监听子组件传递过来的数据'+msg+‘并触发改方法的执行’ ); }, divClick:function(){ //调用子组件 page1 的 handleParentClick 方法 this.$refs.page1.handleParentClick(); } }, components: { page1 } } </script> <style lang="scss"> </style>
这里我用的是 node.js
来做后端开发 ,在项目的根目录建个 server.js
文件 :
var express = require('express'); var app = express(); var routar = express.Router(); // get请求 routar.get('/getUserData', function (req, res) { // 输出 JSON 格式 var response = { err:0, data:userData }; res.end(JSON.stringify(response)); }) // post 请求 routar.post('/getUserData', function (req,res) { var response = { err:0, data:userData }; res.end(JSON.stringify(response)); }); app.use(routar); var server = app.listen(8888, function () { var host = server.address().address; var port = server.address().port; console.log("应用实例,访问地址为 http://%s:%s", host, port) })
npm run build
咱们的项目 ,会打包编译完 .vue
文件 ,在项目的跟目录下回生成 dist 文件夹
,里面的
资源就是咱们要发布到线上的脚步和网页文件。
执行 node server.js
即可启动该执行文件,至此,前后端项目都编译启动完成,可以做线上调试了。
本篇稍微讲了一下利用 vue-cli 脚手架进行前端项目开发的大概流程,知识点讲的有粗有细,大家可以对大体流程有所了解,对细节知识点不妨去 google 百度 深入学习。
vue 项目
用微信扫一扫打开: