vue-resource
是Vue实现异步加载的官方库,即Vue中的ajax。在Vue2.js以后vue-resource
将再也不更新维护,因此推荐尽可能使用第三方库axios
实现异步加载。javascript
下面将对两种库分别进行使用说明,参考:css
vue-resourcehtml
axiosvue
首先咱们须要引入库文件:java
<script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>
vue-resource
同jquery
封装的Ajax同样,提供了简易的api实现异步访问。提供了 7 种请求 API(REST 风格):node
get(url, [options]) head(url, [options]) delete(url, [options]) jsonp(url, [options]) post(url, [body], [options]) put(url, [body], [options]) patch(url, [body], [options])
除了 jsonp 之外,另外 6 种的 API 名称是标准的 HTTP 方法。jquery
具体的参数说明请参考:Vue.js-菜鸟ios
在Vue中,你能够基于全局或组建进行异步访问:css3
// 基于全局Vue对象使用http Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback); Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback); // 在一个Vue实例内使用$http this.$http.get('/someUrl', [options]).then(successCallback, errorCallback); this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
下面咱们使用具体的案例来体验一下。git
咱们如今的需求是,使用vue-resource
提供的api获取服务端发送来的数据,并显示出来。而后能够添加和删除页面上的商品数据,并发送请求更新服务端的数据。
jsonp
方法进行数据的访问,也能够将页面放到在Node服务器上访问,这里咱们使用第二种方法。使用node搭建服务器
首先咱们须要安装第三方模块:express、body-parser。
npm install express body-parser
书写app.js文件:
//加载须要的模块 var express = require('express'); var app = express(); var fs = require('fs'); var path = require('path'); var bodyParser = require('body-parser'); //启动服务器 app.listen(8080, function(){ console.log('server running at 8080'); }); //相关配置 app.use('/views', express.static(path.join(__dirname, './views')));//静态资源 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); //相关请求 app.get('/', (req, res) => { res.redirect(302, '/views/index.html'); });
页面文件index.html
咱们把这个文件放在node文件夹的views下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>添加信息</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script> </head> <body> <div id="app"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">{{title}}</h3> </div> </div> <div class="panel-body form-inline"> <label> Id: <input type="text" v-model="id" class="form-control" required="true" @keyup.enter="add"> </label> <label> Name: <input type="text" v-model="name" class="form-control" required="true" @keyup.enter="add"> </label> <input type="button" class="btn btn-primary" @click="add" value="添加"> <label style="color: red;cursor: pointer;" @click="clearMessage"> {{message}} </label> </div> <table class="table table-hover table-striped table-bordered"> <thead> <tr> <td>Id</td> <td>Name</td> <td>Date</td> <td>Control</td> </tr> </thead> <tbody> <tr v-for="item in list" :key="item.id"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td><span title="删除" @click="deleteItem(item.id)" style="cursor: pointer;color: red;" class="glyphicon glyphicon-remove"></span></td> </tr> </tbody> </table> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { list : [], id:'', name:'', title: '添加信息', message: '' }, methods: { add(){ console.log("添加"); }, clearMessage(){ this.message = ''; }, deleteItem(id){ console.log("删除"); } } }); </script> </body> </html>
启动服务器查看效果
Node.js返回数据
咱们使用list.json
这个文件来充当数据库。
app.get('/getlist', (req, res) => { fs.readFile('./list.json', 'utf8', (err, data) => { if(err){ res.json(err); }else{ res.json(JSON.parse(data.toString())); } }); });
{ "list":[ {"id":"1","name":"宝马","date":"2019/2/18"}, {"id":"2","name":"众泰","date":"2019/2/18"}, {"id":"3","name":"梅赛德斯","date":"2019/2/19"}, {"id":"4","name":"奥迪","date":"2019/2/19"} ] }
使用get请求获取信息
getList(){ this.$http.get('http://localhost:8080/getlist').then((res) => { if(!res.body){ this.message = '信息获取失败' }else{ this.list = res.body.list; } }); }
这个方法目前没有被调用,咱们但愿在页面加载时渲染到页面,根据Vue的生命周期,咱们可使用钩子函数created
来调用:
created(){ this.getList(); },
完整的文件最后会给出。
显示效果
信息的添加功能为add
函数,一样的,咱们须要发送post请求(其余方式也可),将新的数据更新到list.json文件中。
页面提交post请求
add(){ if(this.id.trim() == '' || this.name.trim() == ''){ this.message = "输入不能为空"; return; } //一、读取表单信息,将信息存制list for(var i = 0;i < this.list.length;i++){ if(this.list[i].id === this.id){ this.message = "id不能重复"; return; } } this.list.push({"id": this.id, "name":this.name, "date": new Date().toLocaleDateString()}); //二、将新的list更新到json文件中 this.setList(); }
setList(){ var listObj = { list: this.list }; this.$http.post('http://localhost:8080/setlist', {list: listObj}).then(function(result){ if(result && +result.status === 200){ this.message = "更新成功"; }else{ this.message = "更新失败"; this.getList(); } }); }
服务器接收post请求
app.post('/setlist', function(req, res){ var dataStr = JSON.stringify(req.body.list); fs.writeFile('./list.json', dataStr, 'utf8', function(err){ if(err){ res.json({status: 200, message: 'ok'}); }else{ res.json({status: 500, message: 'failed'}); } }); });
删除和添加时同样的逻辑。
页面发送请求
deleteItem(id){ for(var i = 0;i < this.list.length;i++){ if(id === this.list[i].id){ this.list.splice(i, 1); i = this.list.length; } } this.setList(); }
Vue.http.options.root = '/root';//域名 Vue.http.headers.common['Authorization'] = 'Basic YXBpOnBhc3N3b3Jk'; Vue.http.options.emulateJSON = true;//服务器没法编码时使用 //若是您的Web服务器没法处理PUT,PATCH和DELETE等REST / HTTP请求,则能够启用emulateHTTP选项。 这将使用实际的HTTP方法设置X-HTTP-Method-Override标头并使用普通的POST请求。 Vue.http.options.emulateHTTP = true;
app.js
//加载须要的模块 var express = require('express'); var app = express(); var fs = require('fs'); var path = require('path'); var bodyParser = require('body-parser'); //启动服务器 app.listen(8080, function(){ console.log('server running at 8080'); }); //相关配置 app.use('/views', express.static(path.join(__dirname, './views')));//配置静态资源 app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); //相关请求 app.get('/', (req, res) => { res.redirect(302, '/views/index.html'); }); app.get('/getlist', (req, res) => { fs.readFile('./list.json', 'utf8', (err, data) => { if(err){ res.json(err); }else{ res.json(JSON.parse(data.toString())); } }); }); app.post('/setlist', function(req, res){ var dataStr = JSON.stringify(req.body.list); fs.writeFile('./list.json', dataStr, 'utf8', function(err){ if(err){ res.json({status: 200, message: 'ok'}); }else{ res.json({status: 500, message: 'failed'}); } }); });
index.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>添加信息</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.17/dist/vue.js"></script> <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script> </head> <body> <div id="app"> <div class="panel panel-primary"> <div class="panel-heading"> <h3 class="panel-title">{{title}}</h3> </div> </div> <div class="panel-body form-inline"> <label> Id: <input type="text" v-model="id" class="form-control" required="true" @keyup.enter="add"> </label> <label> Name: <input type="text" v-model="name" class="form-control" required="true" @keyup.enter="add"> </label> <input type="button" class="btn btn-primary" @click="add" value="添加"> <label style="color: red;cursor: pointer;" @click="clearMessage"> {{message}} </label> </div> <table class="table table-hover table-striped table-bordered"> <thead> <tr> <td>Id</td> <td>Name</td> <td>Date</td> <td>Control</td> </tr> </thead> <tbody> <tr v-for="item in list" :key="item.id"> <td>{{item.id}}</td> <td>{{item.name}}</td> <td>{{item.date}}</td> <td><span title="删除" @click="deleteItem(item.id)" style="cursor: pointer;color: red;" class="glyphicon glyphicon-remove"></span></td> </tr> </tbody> </table> </div> <script type="text/javascript"> var vm = new Vue({ el: '#app', data: { list : [], id:'', name:'', title: '添加信息', message: '' }, created(){ this.getList(); }, methods: { add(){ if(this.id.trim() == '' || this.name.trim() == ''){ this.message = "输入不能为空"; return; } //一、读取表单信息,将信息存制list for(var i = 0;i < this.list.length;i++){ if(this.list[i].id === this.id){ this.message = "id不能重复"; return; } } this.list.push({"id": this.id, "name":this.name, "date": new Date().toLocaleDateString()}); //二、将新的list更新到json文件中 this.setList(); }, setList(){ var listObj = { list: this.list }; this.$http.post('http://localhost:8080/setlist', {list: listObj}).then(function(result){ if(result && +result.status === 200){ this.message = "更新成功"; }else{ this.message = "更新失败"; this.getList(); } }); }, clearMessage(){ this.message = ''; }, deleteItem(id){ for(var i = 0;i < this.list.length;i++){ if(id === this.list[i].id){ this.list.splice(i, 1); i = this.list.length; } } this.setList(); }, getList(){ this.$http.get('http://localhost:8080/getlist').then((res) => { if(!res.body){ this.message = '信息获取失败' }else{ this.list = res.body.list; } }); } } }); </script> </body> </html>
axios
的使用同vue-resource
基本一致。咱们使用axios
重写上面获取信息列表的方法就一目了然了:
导入库文件
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
重写getList
getList(){ axios.get('http://localhost:8080/getlist').then((res) => { if(!res.data){ this.message = '信息获取失败' }else{ this.list = res.data.list; } }); }
能够发现,this.$http.get() 变成了 axios.get(),而response返回的数据存在data中而不是body中。
更多细节请参考:axios
看下面的例子:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style type="text/css"> div{ width: 100px; height: 100px; background-color: #999111; } div:hover{ width: 200px; height: 200px; } </style> </head> <body> <div></div> </body> </html>
当咱们的鼠标悬浮在div
元素上时,元素的样式发生了变化,可是这是瞬时变化的,在CSS3加入过渡和动画以前,元素属性(样式)变化都是没有时间轴的。
为了提升用户体验,CSS3实现了元素的过渡和动画效果。在上面的例子中,咱们使用为元素加上过渡属性:transition
。
div{ width: 100px; height: 100px; background-color: #999111; transition: all 1s ease; }
这样,咱们就能看到元素在样式变化过程当中的过渡效果。
关于transition
的更多用法请自行查阅。
对于过渡来讲,咱们须要事件触发才能看到效果,即存在状态变化,且过渡只在元素的两个状态之间变化。不少时候咱们不须要事件触发也能实现状态变化,且能控制变化状态。这就是更复杂的动画功能,使用animation
属性。
动画比过渡多了状态控制的过程,因此css动画须要结合keyframes(关键帧)
来结合animation
属性使用。
更多相关属性可自行查阅学习。
这里有一个css动画案例:行星运动
参考:
http://www.runoob.com/css3/css3-animations.html
http://www.ruanyifeng.com/blog/2014/02/css_transition_and_animation.html
详情请参考官方文档:https://cn.vuejs.org/v2/guide/transitions.html
在Vue中,能够在插入、更新或移除DOM时提供不一样方式的过渡效果:
Animated.css
Velocity.js
这些本质上都是CSS过渡和动画的封装实现,只是可让咱们使用更少的代码实现更多的功能(需求)。
Vue把过渡分为两个阶段来实现过渡效果,分别是进入阶段、离开阶段。而这两个阶段又再细分为前和后两个阶段,具体如图所示:
下面是一个简单的例子:
因为Vue能在适当的时机添加类,因此不须要咱们手动绑定类名,可是咱们须要使用Vue提供的Transition
组件来包裹须要过渡的元素。
<div id="app"> <button @click="show = !show">Toggle</button> <transition> <h3 v-show="show">This is a message.</h3> </transition> </div>
.v-enter-active, .v-leave-active{ transition: all 0.8s ease; } .v-enter, .v-leave-to{ transform: translateX(10px); opacity: 0; }
var app = new Vue({ el: '#app', data: { show: true, } });
transition
的name属性能够自定义类名的前缀,如name="my-transition"
,那么类名就变成my-transition-enter
等。
Vue提供了自定义过渡类名的特性:
这样咱们就可使用自定义的类名来定义不一样的过渡效果,下面咱们结合第三方css库来使用:
<button @click="show = !show">Toggle</button> <transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut"> <h3 v-show="show">This is a message.</h3> </transition>
<link href="https://cdn.jsdelivr.net/npm/animate.css@3.5.1" rel="stylesheet" type="text/css">
咱们使用了Animation.css
提供的类样式:animated、bounceIn和bounceOut。只须要放在适合的类中便可自动加载触发。
CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter
类名在节点插入 DOM 后不会当即删除,而是在 animationend
事件触发时删除。
上面咱们能够经过类名来控制过渡效果,下面咱们还可使用js钩子函数来控制:
<transition v-on:before-enter="beforeEnter" v-on:enter="enter" v-on:after-enter="afterEnter" v-on:enter-cancelled="enterCancelled" v-on:before-leave="beforeLeave" v-on:leave="leave" v-on:after-leave="afterLeave" v-on:leave-cancelled="leaveCancelled" > <!-- ... --> </transition>
还有不少的Vue动画特性,这样再也不赘述,可自行到官网查阅学习。
给一个组件注册一个符合其用途的名称是咱们应当考虑的,且尽可能遵循W3C规范,即名称全小写,必要的单词以以字符分隔开。例如:
Vue.component('show-number', {/*...*/});
在html中特性名称prop是大小写不敏感的,浏览器会将大写当作小写来处理,因此驼峰式(camelCase)的写法能够换成连字符的写法(kebab-case)。
有两种写法:
字符串数组形式:
js props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
对象形式:
props: { title: String, likes: Number, isPublished: Boolean, commentIds: Array, author: Object }
推荐使用对象形式,由于这种不但清晰地标明了数据类型,还能在js报错的时候发出相应的信息提示。
所谓的静态赋值就是将一个不变的数据传给prop,而动态赋值就是将一个变量传给prop,以此来达到动态赋值的效果。
静态
<my-component titile="Boom"></my-component>
动态
<my-component :title="data.title"></my-component> <my-component :title="'this is' + data.title"></my-component>
虽然咱们都是在传递一个字符串,但理论是支持任意类型的数据。须要注意的是,若是咱们但愿传递一个数字就不能单纯的使用静态赋值,由于这样会变被当成字符串来处理。一样的道理,对于Boolean值、数组、对象,咱们都须要使用动态赋值来保证数据的类型。
一次性赋值
若是你但愿将全部的prop做为整个对象传入,可使用不带名称的v-bind
进行赋值。例如:假定有一个对象
props = { id: 1, title: 'hiahia' }
一次性赋值:
<my-component v-bind="props"></my-component>
等价于:
<my-component :id="props.id" :title="props.title"></my-component>
全部的prop都使得其父子之间的prop造成一个单向下行绑定:父级更新将会更新子组件的prop,但反过来却不行,因此Vue不容许在子组件中出现修改prop的状况。
上面提到的推荐的prop类型是对象类型,咱们能够对组件进行验证性信息传入,当不符合注册规则是发出错误信息。如:
Vue.component('my-component', { props: { // 基础的类型检查 (`null` 和 `undefined` 会经过任何类型验证) propA: Number, // 多个可能的类型 propB: [String, Number], // 必填的字符串 propC: { type: String, required: true }, // 带有默认值的数字 propD: { type: Number, default: 100 }, // 带有默认值的对象 propE: { type: Object, // 对象或数组默认值必须从一个工厂函数获取 default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { // 这个值必须匹配下列字符串中的一个 return ['success', 'warning', 'danger'].indexOf(value) !== -1 } } } })
若是你不但愿组件的根元素继承特性,那么你能够在注册是加上这个特性:inheritAttrs: false
。