vue2.0+vue3.0资料(六)

简介: vue2.0+vue3.0资料(六)

11、消息订阅与发布pubsub


11-1、消息订阅与发布


网络异常,图片无法展示
|


一种组件间通信的方式,适用于任意组件间通信


11-2、使用方法


1、调用pubsub.js库命令,安装pubsub:npm i pubsub-js


2、在所用的地方引入库: import pubsub from 'pubsub-js'


  1. 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
methods(){
  demo(data){......}
}
......
mounted() {
  this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}
  1. 提供数据:pubsub.publish('xxx',数据)
  2. 最好在beforeDestroy钩子中,用PubSub.unsubscribe(this.pid)取消订阅。


11-3、TodoList案例pubsub


12、$nextTick(视图渲染完,操作DOM)


12-1、nextTick使用


  1. 语法:this.$nextTick(回调函数)
  2. 作用:在下一次 DOM 更新结束后执行其指定的回调。
  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。


13、vue封装的过度和动画


13-1、Vue封装的过度与动画


  1. 作用:在插入、更新或移除 DOM元素时,在合适的时候给元素添加样式类名。
  2. 图示:
    网络异常,图片无法展示
    |
  3. 写法:
    3-1、准备好样式:

- 元素进入的样式:

 1. v-enter:进入的起点

 2. v-enter-active:进入过程中

 3. v-enter-to:进入的终点

- 元素离开的样式:

 1. v-leave:离开的起点

 2. v-leave-active:离开过程中

 3. v-leave-to:离开的终点

3-2、使用<transition>包裹要过度元素,并配置name属性:

3-3、备注:若有多个元素需要过度,则需要使用:<transition-group>,且每个元素都要指定key值。
3-4、可以使用第三方动画库来实现动画效果


13-2、animate.css(开箱即用的动画库)


官网:  https://animate.style/


图片:

网络异常,图片无法展示
|


//安装animate.css库
npm install animate.css
//引入样式库
import 'animate.css'
//存放库里面的样式属性(animate__animated animate__bounce),
//然后放置属性(enter-active-class)
//和效果动画(animate__swing)
<transition-group 
 appear
 name="animate__animated animate__bounce" 
 enter-active-class="animate__swing"
 leave-active-class="animate__backOutUp"
>
 <h1 v-show="!isShow" key="1">你好啊!</h1>
 <h1 v-show="isShow" key="2">你好!</h1>
</transition-group>

14、配置代理


14-1、用脚手架去解决Ajax跨域的问题


解压文件中的test_proxy_server.zip


网络异常,图片无法展示
|


在文件页面打开cmd 输入node server1,然后复制(http://localhost:5000/students)网址,打开浏览器,输入页面发现是Ajax发出的get请求,端口也显示出来了


网络异常,图片无法展示
|


在文件页面打开cmd 输入node server1,然后复制(http://localhost:5000/students)网址,打开浏览器,输入页面发现是Ajax发出的get请求,端口也显示出来了


网络异常,图片无法展示
|


网络异常,图片无法展示
|


网络异常,图片无法展示
|


14-2、常用的发送一个Ajax请求的方式有哪些:(4种)


  • xhr(不常用)   new XMLHttpRequest()
    常用apixhr.open()   、 xhr.send()等
  • jQuery(不常用,经常使用DOM操作)
    常用api $get  、  $post
  • axios(promise风格)
  • vue-resource(不常用,在vue1.0流行)
  • fetch(promise风格,但会包装两次promise)
    最致密的是他IE中的兼容性极差


14-3、axios的使用与问题解决


安装axios


//axios的安装
npm i axios

网络异常,图片无法展示
|


引入axios
//引入axios
import axios from 'axios.js'
设置一个按钮
<button @click="getStudents">获取学生信息</button>
在methods中写请求
methods: {
   getStudents(){
    axios.get('http://localhost:5000/students').then(
     response => {
      console.log('请求成功了',response.data)
     },
     error => {
      console.log('请求失败了',error.message)
     }
    )
   },
}

发生跨域问题


网络异常,图片无法展示
|


解决跨域问题的方式:


1、cors


2、jsonp script src(只能解决get请求post无法解决)


3、使用代理服务器(类似于生活中的房屋中介)


开启代理服务器方式{    1、nginx    2、vue-cli }


网络异常,图片无法展示
|


14-4、用脚手架的方式配置一个代理服务器


14-4A、方式一


14-4A-1、配置方法


①在vue的脚手架官网搜索devServer.proxy(英文意思为开发中如何配置代理),②在vue.config.js中输入(这里的5000是你获取axios服务器的端口),③把methods中的axios请求的地址改成8080端口的(因为数据要发送到8080端口实现跨域)


devServer: {
    proxy: 'http://localhost:5000'
  }


网络异常,图片无法展示
|


//修改端口号5000,改成8080端口
axios.get('http://localhost:8080/students').then(
     response => {
      console.log('请求成功了',response.data)
     },
     error => {
      console.log('请求失败了',error.message)
     }
    )
   },
14-4A-2、工作方式:


若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)


当你请求的内容代理服务器中原本就有则不会发送给5000的目标服务器public中有students,(即实现不了下面图片黄色箭头)


网络异常,图片无法展示
|


网络异常,图片无法展示
|


14-4A-3、方式一配置代理缺点


这种情况下只能配置一个单独的代理,并且不能灵活的控制走不走代理服务器。


14-4B、方式二


14-4B-1、配置方法


下图两个颜色为配置的两套代理(分别为红色和绿色,且红色是精简版),并且这里'/api'的意思是当你发送请求到代理服务器时,它会判断代理是否是 /api 形式如果是走代理,否则不走。target 为请求跳转的目标地址,pathRewrite:{'^/api':''}这里是请求后发给目标地址是把/api  替换成空字符串


网络异常,图片无法展示
|


此时请求完还得改axios跳转代理服务器的路径为


//原本
axios.get('http://localhost:8080/students')
//修改后添加了个/api
axios.get('http://localhost:8080/api/students')
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/
14-4B-2、配置优缺点:


  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
  2. 缺点:配置略微繁琐,请求资源时必须加前缀。


14-5、github案例


网络异常,图片无法展示
|


1、先在index.html中引入bootstrap样式


2、main.js代码


//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false
//创建vm
new Vue({
 el:'#app',
 render: h => h(App),
 beforeCreate() {
  Vue.prototype.$bus = this
 },
})

3、App.vue


<template>
 <div class="container">
  <Search/>
  <List/>
 </div>
</template>
<script>
 import Search from './components/Search'
 import List from './components/List'
 export default {
  name:'App',
  components:{Search,List}
 }
</script>


4、Search.vue


<template>
 <section class="jumbotron">
  <h3 class="jumbotron-heading">Search Github Users</h3>
  <div>
   <input type="text" placeholder="enter the name you search" v-model="keyWord"/>&nbsp;
   <button @click="searchUsers">Search</button>
  </div>
 </section>
</template>
<script>
 import axios from 'axios'
 export default {
  name:'Search',
  data() {
   return {
    keyWord:''
   }
  },
  methods: {
   searchUsers(){
    //请求前更新List的数据
    this.$bus.$emit('updateListData',{isLoading:true,errMsg:'',users:[],isFirst:false})
    axios.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
     response => {
      console.log('请求成功了')
      //请求成功后更新List的数据
      this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
     },
     error => {
      //请求后更新List的数据
      this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
     }
    )
   }
  },
 }
</script>

5、List.vue


<template>
 <div class="row">
  <!-- 展示用户列表 -->
  <div v-show="info.users.length" class="card" v-for="user in info.users" :key="user.login">
   <a :href="user.html_url" target="_blank">
    <img :src="user.avatar_url" style='width: 100px'/>
   </a>
   <p class="card-text">{{user.login}}</p>
  </div>
  <!-- 展示欢迎词 -->
  <h1 v-show="info.isFirst">欢迎使用!</h1>
  <!-- 展示加载中 -->
  <h1 v-show="info.isLoading">加载中....</h1>
  <!-- 展示错误信息 -->
  <h1 v-show="info.errMsg">{{info.errMsg}}</h1>
 </div>
</template>
<script>
 export default {
  name:'List',
  data() {
   return {
    info:{
     isFirst:true,
     isLoading:false,
     errMsg:'',
     users:[]
    }
   }
  },
  mounted() {
   this.$bus.$on('updateListData',(dataObj)=>{
    this.info = {...this.info,...dataObj}
   })
  },
 }
</script>
<style scoped>
 .album {
  min-height: 50rem; /* Can be removed; just added for demo purposes */
  padding-top: 3rem;
  padding-bottom: 3rem;
  background-color: #f7f7f7;
 }
 .card {
  float: left;
  width: 33.333%;
  padding: .75rem;
  margin-bottom: 2rem;
  border: 1px solid #efefef;
  text-align: center;
 }
 .card > img {
  margin-bottom: .75rem;
  border-radius: 100px;
 }
 .card-text {
  font-size: 85%;
 }
</style>

效果图


网络异常,图片无法展示
|


15、vue-resource(不常用)


15-1、使用方法


安装vue-resource
npm i vue-resource
在main.js中引入vue-resource插件
import vueResource from 'vue-resource'
在main.js中使用插件
vue.use(vueResource)
在一个vue实例内使用this.$http代替axios
// 在一个Vue实例内使用$http
this.$http.get(`https://api.github.com/search/users?q=${this.keyWord}`).then(
 response => {
  console.log('请求成功了')
  //请求成功后更新List的数据
  this.$bus.$emit('updateListData',{isLoading:false,errMsg:'',users:response.data.items})
 },
 error => {
  //请求失败后更新List的数据
  this.$bus.$emit('updateListData',{isLoading:false,errMsg:error.message,users:[]})
 }
)


16、插槽


  1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件
  2. 分类:默认插槽、具名插槽、作用域插槽
  3. 使用方式:
  1. 默认插槽:

父组件中:

   

<Category>
           <div>html结构1</div>
        </Category>

子组件中:

   

<template>
            <div>
               <!-- 定义插槽 -->
               <slot>插槽默认内容...</slot>
            </div>
        </template>
a.  具名插槽:

父组件中:

     

<Category>
            <template slot="center">
              <div>html结构1</div>
            </template>
            <template v-slot:footer>
               <div>html结构2</div>
            </template>
        </Category>

子组件中:

     

<template>
            <div>
               <!-- 定义插槽 -->
               <slot name="center">插槽默认内容...</slot>
               <slot name="footer">插槽默认内容...</slot>
            </div>
        </template>
  1. 作用域插槽:
  1. 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
  2. 具体编码:

父组件中:

<Category>
   <template scope="scopeData">
    <!-- 生成的是ul列表 -->
    <ul>
     <li v-for="g in scopeData.games" :key="g">{{g}}</li>
    </ul>
   </template>
  </Category>
  <Category>
   <template slot-scope="scopeData">
    <!-- 生成的是h4标题 -->
    <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
   </template>
  </Category>

子组件中:

     

<template>
            <div>
                <slot :games="games"></slot>
            </div>
        </template>
        <script>
            export default {
                name:'Category',
                props:['title'],
                //数据在子组件自身
                data() {
                    return {
                        games:['红色警戒','穿越火线','劲舞团','超级玛丽']
                    }
                },
            }
        </script>



17、动态组件


17-1、动态组件的is


  • 动态组件就是几个组件放在一个挂载点下,然后根据父组件的某个变量来决定显示哪个,或者都不显示。
  • 在挂载点使用 component 标签,然后使用 is =“组件名”,它会自动去找匹配的组件名,如果有,则显示;


看例子:


<!-- html部分 -->
<div id="app">
    <component is="one"></component>
</div>
// js 部分
new Vue({
    el: '#app',
    components: {
        one: {template: '<div>我是线路一</div>'},
        two: {template: '<div>我是线路二</div>'},
        thr: {template: '<div>我是线路三</div>'}
    }
})

上面代码注册了三个组件,在 component 标签里有个属性 is,is=one,所以页面会渲染名字叫 one 的组件,显示结果如下:


我是线路一


如果给 is 属性绑定动态值,那么就可以实现组件的动态切换,例子如下:


<!-- html 部分 -->
<div id="app">
    <button v-for="item in tabs" @click="change = item.id">
     {{ item.text }}
    </button>
    <component :is="change"></component>
</div>
// js 部分
new Vue({
  el: '#app',
  data: {
   change: 'one' // 默认显示组件 one
    tabs: [
     {id: 'one', text: '线路一'},
        {id: 'two', text: '线路二'},
        {id: 'thr', text: '线路三'}
    ]
  },
  components: {
   one: {template: '<div>我是线路一</div>'},
    two: {template: '<div>我是线路二</div>'},
    thr: {template: '<div>我是线路三</div>'}
  }
})


上面代码用 v-bind 给属性 is 动态传递了值,实现了组件的动态切换,效果如下:


网络异常,图片无法展示
|


17-2、动态组件的keep-alive


在面试的时候,很多面试官再问vue的时候可能就会提一嘴,你知道keep-alive有什么作用吗?


keep-alive是vue内置的一个组件,而这个组件的作用就是能够缓存不活动的组件,我们能够知道,一般情况下,组件进行切换的时候,默认会进行销毁,如果有需求,某个组件切换后不进行销毁,而是保存之前的状态,那么就可以利用keep-alive来实现


我这里利用脚手架创建项目后会生成home和about两个组件,并且通过路由进行切换


home组件


<template>
  <div class="home">
    <input type="text">
  </div>
</template>
<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'
export default {
  name: 'home',
  components: {
    HelloWorld
  }
}
</script>

我在home组件中写了一个input输入框


about组件


<template>
  <div class="about">
    <input type="text">
  </div>
</template>
<script>
export default {
  name:"about"
}
</script>

同样的about组件也放了一个输入框


网络异常,图片无法展示
|


当我们在home组件的输入框输入一些内容的时候,然后切换到about组件,在切换回home组件,我们会发现之前输入的内容被清空了,其实也容易理解,就是当切换到about组建的时候,home组件就被销毁了,输入框的值自然被清空了


网络异常,图片无法展示
|


当切换到about组件的时候home组件的destroyed就触发了,所以home组件被销毁了


那么此时我们就可以利用keep-alive组件进行包裹router-view组件,将不活动的组件缓存起来


App组件


<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link> |
      <router-link to="/about">About</router-link>
    </div>
    <keep-alive>
      <router-view />
    </keep-alive>
  </div>
</template>


写完之后会发现当切换到about组件时,home组件中的destroyed并没有触发,并且home组件的值也保存了下来


网络异常,图片无法展示
|


但是这样也肯定不好,我们会发现,about组件的值也被缓存了,就是所有的路由组件都被缓存了,严重浪费性能,而且也不符合需求,我们现在只想缓存home组件


在keep-alive上有两个属性


字符串或正则表达式。只有匹配的组件会被缓存。


  • include 值为字符串或者正则表达式匹配的组件name会被缓存。
  • exclude 值为字符串或正则表达式匹配的组件name不会被缓存。


首先利用include实现,匹配到组件中定义的name,将进行缓存


<keep-alive include="home">
   <router-view />
</keep-alive>

网络异常,图片无法展示
|


我们会发现home已经被缓存了,但是about没有被缓存


而exclude就是排除了,这个就不在演示了,很简单,除了这个我们还可以利用路由中的meta属性来控制


{
      path: '/',
      name: 'home',
      meta:{
        keepAlive:true
      },
      component: Home
    }

将home的路由规则钟的meta添加keepAlive属性为true,也就是当前路由组件要进行缓存


keep-alive代码可以结合v-if进行包裹,如果meta中的keepAlive为true进行缓存,否侧不进行缓存,这样可以更灵活一些


<keep-alive>
      <router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />


这样组件的缓存是实现了,但是还是会有一些问题,就是因为组件被缓存,并没有被销毁,所以组件在切换的时候也就不会被重新创建,自然也就不会调用created等生命周期函数,所以此时要使用activated与deactivated来获取当前组件是否处于活动状态


我在home组件里面写入了activated与deactivated生命周期函数


activated(){
    console.log("哎呀看见我了")
    console.log("----------activated--------")
  },
  deactivated(){
    console.log("讨厌!!你又走了")
    console.log("----------deactivated--------")
  }


网络异常,图片无法展示
|


通过上面的gif图相信已经看得很清楚了,此时keep-Alive也就差不多了

目录
相关文章
|
1月前
|
JavaScript
vue3高雅的使用useDialog
vue3高雅的使用useDialog
94 0
|
9月前
|
JavaScript API UED
vue3(二)
vue3(二)
73 0
|
1月前
|
JavaScript 前端开发 算法
< 在Vue中,为什么 v-if 和 v-for 不建议一起使用 ? >
在Vue指令中,最经常被用于做逻辑操作的指令,莫过于 `v-if` 和 `v-for`。但是它们之间的能否一起使用呢? 这个问题有时候会被面试官问起,用于测试应试者对这两个指令的了解。 接下来,对 “ `为什么 v-if 和 v-for 不建议一起使用 ?` ” 问题进行讲解!
< 在Vue中,为什么 v-if 和 v-for 不建议一起使用 ? >
|
1月前
|
JavaScript 前端开发 网络架构
Vue3 五天速成(中)
Vue3 五天速成(中)
30 1
|
1月前
|
JavaScript 前端开发 API
使用Vue
使用Vue
20 0
|
10月前
|
JavaScript 前端开发 算法
Vue day01
Vue day01
49 0
|
8月前
|
监控 JavaScript 前端开发
vue v-for
vue v-for
36 0
|
10月前
|
存储 数据处理
Vue3中shallowRef和shallowReactive的使用?
Vue3中shallowRef和shallowReactive的使用?
|
10月前
|
JavaScript
vue为什么避免v-if和v-for一起使用?
vue为什么避免v-if和v-for一起使用?
|
10月前
|
存储 缓存 JavaScript
每天vue一下
每天vue一下
82 0