zoukankan      html  css  js  c++  java
  • Vue(day3)

    一、Vue中的ajax:vue-resource和axios

    vue-resource是Vue实现异步加载的官方库,即Vue中的ajax。在Vue2.js之后vue-resource将不再更新维护,所以推荐尽量使用第三方库axios实现异步加载。

    下面将对两种库分别进行使用说明,参考:

    vue-resource

    axios

    1、vue-resource的使用

    首先我们需要引入库文件:

    <script src="https://cdn.jsdelivr.net/npm/vue-resource@1.5.1"></script>
    

    vue-resourcejquery封装的Ajax一样,提供了简易的api实现异步访问。提供了 7 种请求 API(REST 风格):

    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 方法。

    具体的参数说明请参考:Vue.js-菜鸟

    在Vue中,你可以基于全局或组建进行异步访问:

    // 基于全局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);
    

    下面我们使用具体的案例来体验一下。

    2、vue-resoure案例:获取商品列表

    我们现在的需求是,使用vue-resource提供的api获取服务端发送来的数据,并显示出来。然后可以添加和删除页面上的商品数据,并发送请求更新服务端的数据。

    分析
    • 首先我们需要从服务端获取商品信息,所以我们需要自己模拟一个服务端,使用Node.js来快速搭建即可。
    • 异步加载可能出现跨域的问题,我们可以使用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>
      
    • 启动服务器查看效果

      1550548994468

    获取信息列表
    • 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();
      },
      

      完整的文件最后会给出。

    • 显示效果

      1550555730676

    添加信息

    信息的添加功能为add函数,同样的,我们需要发送post请求(其他方式也可),将新的数据更新到list.json文件中。

    • 页面提交post请求

      add(){
      	if(this.id.trim() == '' || this.name.trim() == ''){
      		this.message = "输入不能为空";
      		return;
      	}
      	//1、读取表单信息,将信息存制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()});
      	//2、将新的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;
      					}
      					//1、读取表单信息,将信息存制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()});
      					//2、将新的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>
      

    3、axios的使用

    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

    二、过滤和动画

    1、css3过渡和动画简介

    过渡

    看下面的例子:

    <!DOCTYPE html>
    <html>
    <head>
    	<meta charset="utf-8">
    	<title></title>
    	<style type="text/css">
    		div{
    			 100px;
    			height: 100px;
    			background-color: #999111;
    		}
    		div:hover{
    			 200px;
    			height: 200px;
    		}
    	</style>
    </head>
    <body>
    	<div></div>
    </body>
    </html>
    

    当我们的鼠标悬浮在div元素上时,元素的样式发生了变化,但是这是瞬时变化的,在CSS3加入过渡和动画之前,元素属性(样式)变化都是没有时间轴的。

    为了提高用户体验,CSS3实现了元素的过渡和动画效果。在上面的例子中,我们使用为元素加上过渡属性:transition

    div{
    	 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

    2、Vue中的过滤和动画

    详情请参考官方文档:https://cn.vuejs.org/v2/guide/transitions.html

    概述

    在Vue中,可以在插入、更新或移除DOM时提供不同方式的过渡效果:

    • 使用class类
    • 配合使用第三方css动画插件,如Animated.css
    • 使用js
    • 配合使用第三方js动画插件,如Velocity.js

    这些本质上都是CSS过渡和动画的封装实现,只是可以让我们使用更少的代码实现更多的功能(需求)

    过渡的类

    Vue把过渡分为两个阶段来实现过渡效果,分别是进入阶段、离开阶段。而这两个阶段又再细分为前和后两个阶段,具体如图所示:

    Transition Diagram

    下面是一个简单的例子:

    由于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等。

    自定义过渡的类名:使用第三方css库

    Vue提供了自定义过渡类名的特性:

    • enter-class
    • enter-active-class
    • enter-active-to(2.1.8+)
    • leave-class
    • leave-active-class
    • leave-to-class(2.1.8+)

    这样我们就可以使用自定义的类名来定义不同的过渡效果,下面我们结合第三方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。只需要放在适合的类中即可自动加载触发。

    Vue动画

    CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。

    js钩子

    上面我们可以通过类名来控制过渡效果,下面我们还可以使用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', {/*...*/});
    

    Prop

    1、prop的命名

    在html中特性名称prop是大小写不敏感的,浏览器会将大写当做小写来处理,所以驼峰式(camelCase)的写法可以换成连字符的写法(kebab-case)。

    2、props的类型

    有两种写法:

    • 字符串数组形式:

      props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
      
    • 对象形式:

      props: {
        title: String,
        likes: Number,
        isPublished: Boolean,
        commentIds: Array,
        author: Object
      }
      

    推荐使用对象形式,因为这种不但清晰地标明了数据类型,还能在js报错的时候发出相应的信息提示。

    3、静态赋值和动态赋值

    所谓的静态赋值就是将一个不变的数据传给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>
      
    4、单向流数据

    所有的prop都使得其父子之间的prop形成一个单向下行绑定:父级更新将会更新子组件的prop,但反过来却不行,所以Vue不允许在子组件中出现修改prop的情况。

    5、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
          }
        }
      }
    })
    
    6、禁用特性继承

    如果你不希望组件的根元素继承特性,那么你可以在注册是加上这个特性:inheritAttrs: false

  • 相关阅读:
    随笔(二十三)
    随笔(二十二)
    随笔(二十一)
    Python3——2019年全国大学生计算二级考试
    IP组播-PIM协议
    PIM-DM实验
    组播基础原理——IGMP
    路由器反射与联盟
    路由过滤&路由引入实验练习
    有道云免会员更换背景图
  • 原文地址:https://www.cnblogs.com/fzz9/p/10556375.html
Copyright © 2011-2022 走看看