当前位置: 首页 > news >正文

Vue(十) 过渡动画、配置代理服务器,解决请求跨域的问题

文章目录

  • 一、Vue封装的过渡与动画
    • 1. 案例展示
    • 2. Vue动画
    • 3. 过渡
    • 4. 第三方动画库
  • 二、Todo案例应用动画
  • 三、配置代理服务器
    • 1.总结发送请求的方式
    • 2. 发送请求、跨域问题
    • 3. 开启代理服务器
  • 四、Vue-resource(了解)
  • 五、github搜索案例
    • 1、拆分静态组件
    • 2、动态数据
      • (1) 给Search组件的按钮添加点击事件
      • (2) 数据展示在List组件里
    • 3、完善页面
      • List和Search的完整代码

一、Vue封装的过渡与动画

作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。

1. 案例展示

需求:实现这样的效果:点击显示与隐藏,会呈现滑动的效果
在这里插入图片描述
原来的写法:

<!-- isShow在data里设为true -->
<button @click="isShow = !isShow">显示/隐藏</button>
<h1 class="come" v-show="isShow">你好</h1>
<style>
.come {animation: move 0.5s linear;
}
.go {animation: move 0.5s linear reverse;
}
@keyframes move {from {transform: translateX(-300px);}to {transform: translateX(0px);}
}
</style>

但是这样只能手动更改h1的class类,使其有不同的动画效果;

2. Vue动画

添加transition标签。点击按钮,isShow为false, h1隐藏之前,会先执行一个离开的动画。isShow为true时,会先执行一个进入的动画,然后展示h1。

<button @click="isShow = !isShow">显示/隐藏</button>
<transition appear><h1 v-show="isShow">你好</h1>
</transition>
<style>/* 进入的动画 */.v-enter-active {animation: move 0.5s linear;}/* 离开的动画 */.v-leave-active {animation: move 0.5s linear reverse;}@keyframes move {from {transform: translateX(-300px);}to {transform: translateX(0px);}}
</style>
  • 谁要加动画效果,transition标签就包裹谁。
  • transition会自动把v-enter-activev-leave-active加在标签上。
  • name属性。transition如果加上name属性,指定了名称,就不能用默认的v-...
  • appear属性。让页面一打开就有进入的动画效果。值为布尔值。:appear="true",如果不加冒号,true就是一个字符串,加上冒号才是表达式,表示一个布尔值。简单写法就是写一个appear即可。
<transition appear name="hello"><h1 v-show="isShow">你好</h1>
</transition>
<style>
/* 进入的动画 */
.hello-enter-active {animation: move 0.5s linear;
}
/* 离开的动画 */
.hello-leave-active {animation: move 0.5s linear reverse;
}
</style>

3. 过渡

<transition name="hello"><h1 v-show="isShow">你好</h1>
</transition>
<style>
/* 进入的起点,离开的终点 */
.hello-enter,
.hello-leave-to {transform: translateX(-300px);
}
/* 中间过程 */
.hello-enter-active,
.hello-leave-active {transition: 0.5s linear;
}
/* 进入的终点,离开的起点 */
.hello-enter-to,
.hello-leave {transform: translateX(0px);
}
</style>

进入或隐藏时,都会给h1添加对应的三个类;起点+终点+中间过程的类
比如隐藏时:
在这里插入图片描述
可以看出有离开的过程和离开的终点这两个类。离开的起点这个类也添加了,但是变化的太快,截不上图。效果执行完之后。h1的样式变为:
在这里插入图片描述
备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。

   <transition-group appear name="hello"><h1 class="come" v-show="isShow" key="1">你好</h1><!-- 多个元素过度 transition-group--><h1 class="come" v-show="isShow" key="2">你好</h1></transition-group>

4. 第三方动画库

  • https://animate.style/

(1) 安装: npm install animate.css
(2) 引入:import 'animate.css'
(3) 使用:添加这三个属性,在网站上选择合适的效果,点击后边的复制,粘贴即可
在这里插入图片描述

二、Todo案例应用动画

在添加和删除时,添加一个柔和的效果。
在这里插入图片描述

给哪个组件加动画,这部分css代码就写在哪个组件里

.todo-enter-active {animation: move 0.3s linear;
}
.todo-leave-active {animation: move 0.3s linear reverse;
}@keyframes move {from {transform: translateX(100%);}to {transform: translateX(0px);}
}

方式一:MyItem

在这里插入图片描述
方式二:MyList里

在这里插入图片描述

三、配置代理服务器

现有两台服务器
server1: http://localhost:5000/students
server2: http://localhost:5001/cars

1.总结发送请求的方式

  1. xhr (XMLHTTPRequest)。 比如有方法xhr.open(),xhr.send();这是原生的发送请求的方式。

    jquery和axios都是对xhr进行二次封装的第三方库。

  2. Jquery,比如$.get,$.post。但是jquery中80%的内容是操作dom,而使用vue和react就是为了不直接操作dom,因为发送请求并不常用jquery。

  3. axios,与jquery相比体积更小,支持请求拦截器和响应拦截器,是Promise风格的。更常用。

  4. fetch,与xhr是平级的,也是Promise风格。但是返回的数据包了两层Primose,得两个then才能获取数据,主要问题是兼容性较差。

2. 发送请求、跨域问题

采用axios发送请求:

// App.vue文件
showStu () {axios.get('http://localhost:5000/students').then(response => {console.log('请求成功', response.data)},error => {console.log('请求失败', error);})
}

出现跨域错误,跨域即违背同源策略(同源策略是指协议名(http)、主机名(localhost)、端口号(8080)要一致)
在这里插入图片描述
出现跨域错误时,5000收到了8080的请求,并返回了请求结果。但是本地服务器8080收到结果后并未传递给前端,所以出错了。
在这里插入图片描述
跨域的时候,请求发了,服务器收到请求并返回了,且本地服务器也收到了,但是本地服务器并没给我们,所以出错了。

解决跨域的方式:

  • cors,需要配置响应头(但不能轻易配置响应头)
  • jsonp(利用script标签里的src属性,在引入外部资源时不受同源策略的限制)但开发中用的很少,只能解决get请求的跨域,且需要前后端都进行操作。
  • 配置代理服务器,代理服务器的位置(协议号、主机号、端口号)与前端一致。
    在这里插入图片描述
    同源策略是浏览器的一个安全机制,本地服务器8080和5000之间需要ajax进行交流,所以受同源策略的影响。代理服务器和5000服务器都是服务器,服务器与服务器之间用http即可互相发送请求,不受同源策略的限制。
    (打交道不用ajax.有浏览器才有window,才有xhr。)

3. 开启代理服务器

开启代理服务器的方式有两种:nginx,vue-cli。本文只看vue脚手架如何开启代理服务器

方式一:

  // vue.config.jsdevServer: {proxy: 'http://localhost:5000' // 发送请求的地址}// App.vueshowStu () {// 这里如果写5000,则代理服务器不起任何作用。// 写8080是向代理服务器发请求,由代理服务器再去将请求转交给后台服务器 axios.get('http://localhost:8080/students').then(response => {console.log('请求成功', response.data)},error => {console.log('请求失败', error);})}

在这里插入图片描述
缺点:

  1. 只能配置一个代理,也就是只能向5000服务器发送请求。
  2. 不能控制发送的请求是否走代理。当请求了前端不存在的资源时,那么该请求会转发给服务器 。当本身(public文件夹里的资源)就有请求的资源时,代理服务器就不会把请求转发给5000服务器,即不走代理。(优先匹配前端资源)

比如当public文件夹里有一个students文件,发送请求时,获取到的是该students文件里的内容。如果仍旧想要5000的students数据,这种方式行不通
在这里插入图片描述

方式二:

// vue.config.jsdevServer: {proxy: {//向server1发送请求'/school': {target: 'http://localhost:5000',pathRewrite: { '^/school': '' }, // 键值对,正则表达式。意思是将所有/school改为空字符串ws: true, // 用于支持websocketchangeOrigin: false // 用于控制请求头中的host值},//向server2发送请求'/demo': {target: 'http://localhost:5001',pathRewrite: { '^/demo': '' },changeOrigin: false}}}
// App.vue
axios.get('http://localhost:8080/school/students').then(...
)
  • 配置请求前缀
    假设规定 /school是请求前缀,想走代理就加上这个请求前缀,不走代理就不加请求前缀。 加上请求前缀后,请求路径是:http://localhost:8080/school/students

  • pathRewrite:重写路径。
    加上请求前缀之后,发送的请求是…/school/students,5000服务器收到的也是这个路径,但是5000服务器并没有这个路径下的资源。所以代理服务器接收到本地8080的请求后,需要将前缀去掉。否则会报404Not Found错误
    在这里插入图片描述

  • ws:用于支持websocket,默认值是true

  • changeOrigin:
    changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
    changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
    changeOrigin默认值为true
    更详细的说明见博客:原来我误会了 changeOrigin 这么多年-CSDN博客

在这里插入图片描述
说明:
1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
2. 缺点:配置略微繁琐,请求资源时必须加前缀。

四、Vue-resource(了解)

vue-resource是vue中的插件,用来发送请求。vue-resource也是对xhr的封装。
安装: npm install vue-resource
引入:import VueResource from 'vue-resource',Vue.use(VueResource)
引入之后vm和vc上就多了个$http。vue-resource的用法与axios十分类似,唯一的区别就是axios…改成了this.$http。

this.$http.get('http://localhost:8080/students').then(response => {console.log('请求成功', response.data)},error => {console.log('请求失败', error);}
)

五、github搜索案例

需求:输入关键词,点击Search按钮,搜索用户名里有这个关键词的用户,展示在页面上。

1、拆分静态组件

拆为App、Search、List。(也可以把每一项拆为item组件,这个案例简单写一下,就不拆了)
在这里插入图片描述
引入外部css文件

这个案例里引入需要bootstrap样式
1、方式一:在src下创建一个assets文件夹(分析脚手架里),创建css文件夹,粘贴第三方css,然后在app.vue里引入

在这里插入图片描述
报错,提示这个字体文件找不到:
在这里插入图片描述
但是我们在使用过程中,并未用到这个字体。这个错误是因为bootstrap源码里用到了这个字体。
通过import的方式引入样式,vue会对assets文件夹里的资源进行严格的检查,确保所有提到的资源都要有。有不存在的资源就会报错。但是第三方的字体在实际应用中并没有用到,所以此处不推荐这种方式。

2、方式二:在public文件里创建css文件,将第三方css粘贴进来,然后在index.html里引入css
在这里插入图片描述

2、动态数据

(1) 给Search组件的按钮添加点击事件

 <div><input type="text" placeholder="enter the name you search" v-model="keyword" />&nbsp;<button @click="searchUsers">Search</button></div><script>data () {return {keyword: ''}},methods: {searchUsers () {// 这个接口github设计的免费接口,github已经通过cors的方式解决了跨域问题axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(response => {console.log('请求成功了', response.data.items);},error => {console.log('请求失败', error.message);})}}
</script>

成功获取到数据:
在这里插入图片描述

(2) 数据展示在List组件里

组件间通信,此处采用全局事件总线。(二连问:谁提供数据,谁接收数据)
1、安装全局事件总线

// 创建vm实例
new Vue({// 将App组件放入容器中render: h => h(App),beforeCreate () {Vue.prototype.$bus = this}
}).$mount('#app') // 挂载容器

2、组件发送数据与接收数据,渲染页面

List.vue接收数据:

// 页面html结构就不写了data () {return {users: [],}},mounted () {this.$bus.$on('getUsers', (users) => {this.users = users})},beforeDestroy () {this.$bus.$off('getUsers')}

Serch.vue发送数据

  methods: {searchUsers () {axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(response => {this.$bus.$emit('getUsers', response.data.items)},error => {console.log('请求失败', error.message);})}}

页面渲染成功:

在这里插入图片描述

3、完善页面

List组件不应只展示用户数据。总的来说,List组件应该包括
(1)、刚进入界面时—欢迎
(2)、获取数据时----加载中
(3)、数据获取完—展示数据
(4)、数据加载失败----数据获取失败

数据驱动页面展示,页面有不同的变化,所以最好是创建新的数据。

List.vue
在这里插入图片描述
这样写的问题是 ,一个属性一个属性的写太麻烦。且Search.vue触发该事件时

// 不够语义化,但看false,true,不明白是什么含义
this.$bus.$emit('updateListData',  false,  true,  '', [] })

应该将这些属于用一个对象包装起来。

改进

Search.vue

 methods: {searchUsers () {// 请求前更新List的数据this.$bus.$emit('updateListData', { isFirst: false, isLoading: true, errMsg: '', users: [] })axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(response => {// 这里不需要再强调isFirst的值了,也不需要改变,所以就不写了this.$bus.$emit('updateListData', { isLoading: false, errMsg: '', users: response.data.items })},error => {this.$bus.$emit('updateListData', { isLoading: false, errMsg: error, users: [] })})}
}

List.vue
在这里插入图片描述
这个地方需要注意,如果用38行代码的方式给info赋值,则会出现这样的情况:
在未发送请求之前,info包含四个属性
在这里插入图片描述
但是搜索之后,属性变成三个了,破坏数据结构(但是对功能没啥影响):
在这里插入图片描述
解决办法:
一、List组件中采用解构赋值的方式,即40行代码
二、Search组件传递数据时,四个属性的数据都写全。不省略isFirst

List和Search的完整代码

CSS样式不贴了
List:

<template><div><!-- 展示欢迎词 --><h1 v-show="info.isFirst">欢迎!</h1><!-- 展示加载中 --><h1 v-show="info.isLoading">加载中</h1><!-- 展示用户列表 用v-show控制 --><div class="row" v-show="info.users.length"><div class="card" v-for="user in info.users" :key="user.id"><!-- 冒号动态绑定,动态绑定后,“js表达式” --><a :href="user.html_url" target="_blank"><img :src="user.avatar_url" style="width: 100px" /></a><p class="card-text">{{ user.login }}</p></div></div><!-- 展示错误信息 --><div v-show="info.errMsg">{{ info.errMsg }}</div></div>
</template><script>
export default {name: 'List',data () {return {info: {users: [],isFirst: true, // 是否为初次加载isLoading: false, // 是否正在加载errMsg: '' // 请求页面错误}}},mounted () {// 绑定事件this.$bus.$on('updateListData', (data) => {this.info = { ...this.info, ...data }})},beforeDestroy () {this.$bus.$off('updateListData')}
}
</script>

Search组件:

<template><div><section class="jumbotron"><h3 class="jumbotron-heading">Search Github Users</h3><div><inputtype="text"placeholder="enter the name you search"v-model="keyword"/>&nbsp;<button @click="searchUsers">Search</button></div></section></div>
</template><script>
import axios from 'axios'
export default {name: 'Search',data () {return {keyword: ''}},methods: {searchUsers () {// 请求前更新List的数据this.$bus.$emit('updateListData', { isFirst: false, isLoading: true, errMsg: '', users: [] })axios.get(`https://api.github.com/search/users?q=${this.keyword}`).then(response => {// 这里不需要再强调isFirst的值了,也不需要改变,所以就不写了this.$bus.$emit('updateListData', { isLoading: false, errMsg: '', users: response.data.items })},error => {this.$bus.$emit('updateListData', { isLoading: false, errMsg: error, users: [] })})}}
}
</script>

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 一体化智能电动窗帘:开启智能生活新时尚
  • 大二必做项目贪吃蛇超详解之下篇游戏核心逻辑实现
  • 各业务领域相关方案
  • 华为云征文|Flexus云服务X实例使用,宝塔的安装,利用宝塔安装Java、NGINX,Redis,Python,快速搭建开发环境
  • 遗传算法与深度学习实战(8)——使用遗传算法解决旅行商问题
  • 2025中国(西安)国际雷达技术及设备展览会
  • java【day03】---(Vue-Element)
  • Fastjson1.2.24(CVE-2017-18349)分析
  • Mybatis分页查询主从表
  • macos MacPort 包管理工具安装和使用
  • Java-树形图工具类TreeUtil
  • [论文笔记]Rethink Training of BERT Rerankers in Multi-Stage Retrieval Pipeline
  • 自动生成对话视频!如何使用Captions的AI视频生成与编辑API工具?
  • LeetCode90 子集 II
  • C++ 设计模式——备忘录模式
  • ES6指北【2】—— 箭头函数
  • hexo+github搭建个人博客
  • 4月23日世界读书日 网络营销论坛推荐《正在爆发的营销革命》
  • Bytom交易说明(账户管理模式)
  • Nacos系列:Nacos的Java SDK使用
  • PAT A1050
  • Python3爬取英雄联盟英雄皮肤大图
  • 如何优雅地使用 Sublime Text
  • 如何在 Tornado 中实现 Middleware
  • 设计模式走一遍---观察者模式
  • 详解移动APP与web APP的区别
  • 责任链模式的两种实现
  • scrapy中间件源码分析及常用中间件大全
  • 回归生活:清理微信公众号
  • ​软考-高级-系统架构设计师教程(清华第2版)【第12章 信息系统架构设计理论与实践(P420~465)-思维导图】​
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (bean配置类的注解开发)学习Spring的第十三天
  • (C语言)fread与fwrite详解
  • (DenseNet)Densely Connected Convolutional Networks--Gao Huang
  • (精确度,召回率,真阳性,假阳性)ACC、敏感性、特异性等 ROC指标
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (南京观海微电子)——示波器使用介绍
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (三)Kafka离线安装 - ZooKeeper开机自启
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (一)python发送HTTP 请求的两种方式(get和post )
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转)3D模板阴影原理
  • (转)shell中括号的特殊用法 linux if多条件判断
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • ./和../以及/和~之间的区别
  • .net php 通信,flash与asp/php/asp.net通信的方法
  • .net 程序发生了一个不可捕获的异常
  • .Net中的设计模式——Factory Method模式
  • .secret勒索病毒数据恢复|金蝶、用友、管家婆、OA、速达、ERP等软件数据库恢复
  • /var/lib/dpkg/lock 锁定问题
  • @PreAuthorize注解