第四部分:Vue高级应用

4.1 脚手架的使用

4.1.1 关于不同版本Vue的区别

  • vue.js 与 vue.runtime.xxx.js的区别

    • vue.js是完整版的Vue,包含:核心功能 + 模板解析器

    • vue.runtime.xxx.js是运行版本的Vue,包含:核心功能,没有模板解析器

  • 因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项

  • 需要使用render函数接收到的creatElement函数,去指定具体内容

4.1.2 脚手架文件结构

|----node_modules

|----public

| |----favicon.ico:页签图标

| |----index.html:主页面

|----src

| |----assets:存放静态文件

| | |----logo.png

| |----component:存放组件

| | |----HelloWorld.vue

| |----App.vue:汇总所有组件

| |----main.js:入口文件

|----.gitignorre:git版本控制忽略文件配置

|----babel.config.js:babel配置

|----package.json:应用包配置文件

|----package-lock.json:包版本控制文件

|----README.md:应用描述文件

4.1.3 vue.config.js配置文件

  • 使用 vue inspect > out.putjs 可以查看脚手架默认配置

  • 使用vue.config.js可以对Vue进行定制化配置,官网有实例教程

4.2 常用的属性及配置项

4.2.1 ref 属性

  • 用来给元素或者子组件注册引用信息(id的替代者)

  • 应用在html标签上获取真是的DOM元素,应用在组件标签上获取组件对象(vc)

  • 使用方式:

    • 打标识:<h1 ref="xxx" >...</h1> 或者 <HelloWorld ref="xxx"/>

    • 获取:this.$refs.xxx

4.2.2 props 配置项

  • 功能:让组件接收外部传入数据

  • 传递数据:<demo name="xxx"/>

  • 接收数据:

    • 第一种:props:['name'] 只接收

    • 第二种:props:{ name:String } 限制类型

    • 第三种:props:{ name:{ type: String, required: true, default: 'cs' }} } 限制类型、必要性、默认值

  • 备注:

    • props是只读的,vue底层会监视你对props的修改,如果进行了修改,会发出警告

    • 如果需要修改,复制props中的数据到data中,修改data中的数据

4.2.3 mixins 配置项

混入基础概念

  • mixin 是一个js对象,将多个组件共同代码抽取出来,进行复用

  • 是一种分发 Vue 组件中可复用功能的非常灵活的方式

  • 它可以包含我们组件中的任意功能选项,如data、components、methods 、created、computed等

  • 当组件使用 mixins 对象时,所有mixin对象的选项都将被混入该组件本身的选项中来

什么时候使用mixins?

  • 当我们存在多个组件中的数据或者功能很相近时,我们就可以利用mixin将公共部分提取出来

  • 通过 mixin 封装的函数,组件调用他们是不会改变函数作用域外部的

// myMixins.js
export default {
   data () {
     return {
          num:1
      }
   },
   mounted() {
      this.speak();
   },
   methods: {
      speak() {
          console.log(this.num);
      },
   }
}

mixins的特点

  • 方法和参数在各组件中不共享:

    • 虽然组件调用了mixins并将其属性合并到自身组件中来了,但是其属性只会被当前组件所识别

    • 不会被共享,也就是其他组件无法从当前组件中获取到mixins中的数据和方法。

  • 引入mixins后组件会对其进行合并:

    • 将mixins中的数据和方法拓展到当前组件中来,在合并的过程中会出现冲突【如下】

  • 异步请求的情况

    • 混入包含异步请求函数,而我们又需要在组件中使用异步请求函数的返回值时,会取不到此返回值

    • 解决方案:不要返回结果,而是直接返回异步函数

关于mixins合并冲突

  • 值为对象(components、methods 、computed、data):

    • 混入组件时选项会被合并,键冲突时优先组件,组件中的键会覆盖混入对象

  • 值为函数(created、mounted):

    • 混入组件时选项会被合并调用,混合对象里的钩子函数在组件里的钩子函数之前调用

4.2.4 插件

  • 功能:用于增强Vue

  • 本质:包含一个install方法的对象,install方法的第一个参数是Vue,后续参数为插件使用者传递的数据

  • 插件使用:

    • 定义插件:myPlugin.install = function(Vue,options){ 添加的方法 }

    • 使用插件:Vue.use( myPlugin )

4.2.5 scoped 样式

  • 将样式作用域指定为当前

  • 使用方法:<style scoped></style>

4.3 webStorage

  • 存储大小一般为5M,不同浏览器可能不一样

  • 浏览器通过 Windows.locaStorage 或者 Windows.sessionStorage 属性来实现本地存储机制

  • 相关API:

    • xxxxStorage.setItem( 'key', 'value' ): 将键值添加到存储中,存在则会更新(默认保存字符串)

    • xxxxStorage.getItem( 'key' ): 获取一个键的存储值,不存在返回null

    • xxxxStorage.removeItem( 'key' ): 移除一个键的存储值

    • xxxxStorage.clear(): 移除所有存储数据

  • 备注:

    • locaStorage:需要手动清除才会消失

    • sessionStorage:浏览器关闭即会消失

    • getItem( 'key' ):获取不到值,将会返回null,JSON.parse( 'value' ) 返回也是null

4.4 组件间的通讯

4.4.1 组件自定义事件

  • 一种组件间的通讯方式,适用于 子组件 ===> 父组件

  • 使用场景:A父组件、B子组件,B想传数据给A,那么就要在A中给B绑定自定义事件(事件的回调在A中)

  • 绑定自定义事件方式:

    • 第一种方式:在父组件中 <Hello @myEvent="test" />

    • 第二种方式:在父组件中mounted函数中绑定,this.$refs.xxx.$on('myEvent', this.test)

    • 若想让事件只执行一次,可以使用 once 修饰符或者使用$once 方法

  • 触发自定义事件:子组件中使用 this.$emit('myEvent', '数据')

  • 解绑自定义事件:this.$off('myEvent')

  • 组件上也可以使用原生的事件,使用 .native修饰符

  • 注意:

    • 通过this.$refs.xxx.$on('myEvent', 回调)绑定自定义事件时

    • 回调要么配置在methods中,要么使用箭头函数,否则this指向会出错

4.4.2 全局事件总线

  • 一种组件间的通讯方式,适用于 任意组件间的通讯 ---【Vue中推荐使用】

  • 安装全局事件总线:

    new Vue({
        el:"app",
        render: (h) => h(App),
        beforeCreate(){
            Vue.prototype.$bus = this,  // 安装全局事件总线,$bus就是当前应用的vm
        }
    });

  • 使用全局事件总线:

    • 接收数据:A组件想接收数据,就在A组件中给$bus绑定自定义事件事件的回调留在A组件自身

      {
          methods() {
              demo(){
                  ......
              }
          },
          mounted(){
              this.$bus.$on('xxxx', 数据),
          }
      }

    • 提供数据:this.$bus.$emit('xxxx', 数据) 在任意组件中触发事件

  • 注意:最好在beforDestroy钩子函数中,用$off('key')解绑当前组件所有使用到的事件

4.4.3 消息发布与订阅

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

  • 使用步骤:

    • 安装pubsub:npm intasll pubsub-js

    • 引入:import pubsub from 'pubsub-js'

    • 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身

      {
          methods(){
              demo(data){
                  ......
              }
          },
          mounted(){
              this.pubId = pubsub.subscribe('xxxx',this.demo);  // 订阅消息
          }
      }

    • 提供数据:pubsub.publish('xxxx', 数据)

    • 最好在beforeDestroy钩子函数中,使用 pubsub.unsubscribe(pubId) 取消订阅

4.5 $nextTick原理及运用

4.5.1 nextTick是什么

  • Vue.nextTick( [callback, context] ),在下次 DOM 更新循环结束之后执行延迟回调

  • 在修改数据之后立即使用这个方法,获取更新后的 DOM

4.5.2 为什么需要它

原理

  • Vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,然后把在同一个事件循环 (event loop)当中观察到数据变化的 watcher 推送进这个队列

  • 如果这个watcher被触发多次,只会被推送到队列一次

  • 这种缓冲行为可以有效的去掉重复数据造成的不必要的计算和DOM操作

  • 而在下一个事件循环时,Vue会清空队列,并进行必要的DOM更新

实例

  • 假使你设置 vm.someData = 'new value',DOM 并不会马上更新,而是在异步队列被清除,也就是下一个事件循环开始时执行更新时才会进行必要的DOM更新

  • 如果此时你想要根据更新的 DOM 状态去做某些事情,就会出现问题

  • 为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用 Vue.nextTick(callback)

  • 这样回调函数在 DOM 更新完成后就会调用

4.5.3 在什么地方用它

created()钩子函数进行的DOM操作

  • 在Vue生命周期的created()钩子函数进行的DOM操作,一定要放在Vue.nextTick()的回调函数中

  • 原因是在created()钩子函数执行的时候,DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中

  • 与之对应的就是mounted钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题

数据变化后需要操作DOM

  • 在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候

  • 例如v-if/v-show根据字段变化显隐,这个操作都应该放进Vue.nextTick()的回调函数中

4.6 Vue封装的过渡与动画

4.6.1 基础概念

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

  • 图示:

4.6.2 使用方法

  • 元素进入时样式:【v-xxxx 中的v是默认名字,如果name有值,v将使用name值】

    • v-enter: 进入的起点

    • v-enter-active: 进入的过程

    • v-enter-to: 进入的终点

  • 元素离开时的样式:

    • v-leave: 离开的起点

    • v-leave-active: 离开的过程

    • v-leave-to: 离开的终点

  • 使用<transition>包裹要过渡的元素,并配置name属性:

    <Transition name="hello">
      <div v-show="isShow">toggled content</div>
    </Transition>
  • 备注:若有多个元素需要过渡,则需要使用<transitionGroup>包裹,每个元素需要指定key值

4.7 devServer.proxy 代理配置

4.7.1 跨域问题

  • 前端应用后端 API 服务器没有运行在同一个主机上

  • 前端应用后端 API 服务器端口不同

4.7.2 配置代理

  • vue.config.js 中的 devServer.proxy 选项来配置

  • changeOrigin: 默认为为 true

    • true:服务器收到请求头中的host为 localhost:5000

    • false:服务器收到请求头中的host为 localhost:8080

  • target:代理目标的基础路径

  • ws:是否启用webservice

const { defineConfig } = require('@vue/cli-service')
​
module.exports = defineConfig({
  devServer: {
    proxy: {
      '/api': {  // 匹配所有以 /api 开头的请求路径
        target: 'http://localhost:5000',  // 代理目标的基础路径
        pathRewrite:{'^/api':''}, //路径改写:将 /api 替换为空
        ws: true,
        changeOrigin: true
      },
    }
  }
})

4.7.3 代理执行流程

  1. 使用 axios 发出请求

  2. 访问代理服务器:拦截请求

  3. 代理服务器帮我们访问目标服务器

  4. 返回结果

4.8 slot 插槽

4.8.1 概念

  • 作用:让父组件可以向子组件指定位置插入html结构,是一种组件间通讯方式,适用于 父组件 ===> 子组件

  • 分类:默认插槽、具名插槽、作用域插槽

4.8.2 使用方式

默认插槽

  • 没有任何命名的插槽

// 父组件
<Hello>
    <div>html结构</div>
</Hello>
​
// 子组件
<template>
    <div>
      <!-- 定义默认插槽 -->
      <slot>插槽默认内容。。。。</slot>
    </div>
</template>

具名插槽

  • 有命名的插槽,可以有多个插槽

// 父组件
<Hello>
    <template slot="mySlot1">
        <div>html结构1</div>
    </template>
    <template slot="mySlot2">
        <div>html结构2</div>
    </template>
</Hello>
​
// 子组件
<template>
    <div>
      <!-- 定义具名插槽 -->
      <slot name="mySlot1">插槽默认内容。。。。</slot>
      <slot name="mySlot2">插槽默认内容。。。。</slot>
    </div>
</template>

作用域插槽

  • 理解:数据在组件自身,但是数据生成的结构需要组件的使用者决定

  • 实例:games数据在Hello组件中,但使用数据遍历出来的结构由APP来决定

// 父组件
<Hello>
    <template scope="{ games }">
        <!-- 生成ul结构 -->
        <ul>
            <li v-for="(g,index) in games" :key="index">{{g}}</li>
        </ul>
    </template>
</Hello>
​
// 子组件
<template>
    <div>
      <!-- 定义具名插槽 -->
      <slot :games="games"></slot>
    </div>
</template>
<script>
    export default{
        name: "Hello",
        data() {
            return {
                games: ["cs", "lol", "csgo"],
            }
        }
    }
</script>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值