重学vue(2, 3)及其生态+TypeScript 之 vue(中)

简介: 重学vue(2, 3)及其生态+TypeScript 之 vue

watch监听器


如果我们需要监听数据变化,然后做一些逻辑处理,就需要用到watch了。


如何使用? 默认情况下,监听器只能监听本身数据的变化,内部属性的变化是不能被监听的(对于对象来说)


watch: {
        // 侦听顶级 property
        a(val, oldVal) {
          console.log(`new: ${val}, old: ${oldVal}`)
        }
    }


如果想要监听内部数据(数组或者对象)的变化,我们可以将监听写成一个对象,并且传入一个deep: true属性,来让他深度监听,不管内部嵌套多深,都会被监听到。这里需要注意的是,监听函数的新旧值是一模一样的,因为它们的引用指向同一个对象/数组。Vue 不会保留变更之前值的副本。如果想要使用旧数据,我们需要自己拷贝副本。


watch: {
        // 该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深
        c: {
          handler(val, oldVal) {
            console.log('c changed')
          },
          deep: true
        },
    }


如果我们想要立即执行监听器,我们就需要传递一个immediate: true属性。


watch: {
        // 该回调将会在侦听开始之后被立即调用
        e: {
          handler(val, oldVal) {
            console.log('e changed')
          },
          immediate: true
        },
    }


我们还可以对一个属性传入多个监听函数。他将被依次调用


watch: {
        // 你可以传入回调数组,它们会被逐一调用
        f: [
          'handle1', // mothods中定义的方法
          function handle2(val, oldVal) {
            console.log('handle2 triggered')
          },
          {
            handler: function handle3(val, oldVal) {
              console.log('handle3 triggered')
            }
            /* ... */
          }
        ]
    }


我们还可以单独监听一个对象中的特定属性值的变化。注意:监听函数拿到的新旧值依旧是一样的。都是改变后的新值。而且是整个对象。而非单独监听的这个属性的值。


watch: {
        // 侦听单个嵌套 property
        'c.d': function (val, oldVal) {
          // do something
        }
    }


如果我们想要监听数组中对象属性值的变化,我们不可以像上面那种监听方法,我们或者通过deep: true来深度监听,或者在子组件中监听传递的数组中的每一项


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


我们还可以调用this.$watch()来监听。并且他会返回一个函数,用于取消监听。


  • 第一个参数是要侦听的源。


  • 第二个参数是侦听的回调函数callback。


  • 第三个参数是额外的其他选项,比如deep、immediate。


const unwatch = this.$watch("info", 
        function (newInfo, oldInfo) {
          console.log(newInfo, oldInfo);
        }, 
        {
          deep: true,
          immediate: true
        }
     )
     // 调用它将取消监听
     unwatch()


mixins 混入


组件和组件之间有时候会存在相同的代码逻辑,我们希望对相同的代码逻辑进行抽取。这个属性对于vue2中代码抽离和复用,非常有效。但是vue3中我们可以使用另外的方式来对代码进行抽离复用


在Vue2和Vue3中都支持的一种方式就是使用Mixin来完成:


  • Mixin提供了一种非常灵活的方式,来分发Vue组件中的可复用功能。


  • 一个Mixin对象可以包含任何组件选项。


  • 当组件使用Mixin对象时,所有Mixin对象的选项将被 混合 进入该组件本身的选项中。 如果Mixin对象中的选项和组件对象中的选项发生了冲突,那么Vue会如何操作呢?


这里分成不同的情况来进行处理;


  • 情况一:如果是data函数的返回值对象 如果data返回值对象的属性发生了冲突,那么会保留组件自身的数据。


  • 情况二:混入生命周期钩子函数


生命周期的钩子函数会被合并到数组中,都会被调用。


  • 情况三:值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。


  • 比如都有methods选项,并且都定义了方法,那么它们都会生效;


  • 但是如果对象的key相同,那么会取组件对象的键值对; 如果每个组件都需要用到一段相同的逻辑,那么我们就可以使用全局混入。


  • 全局的Mixin可以使用 应用app的方法 mixin 来完成注册。


  • 一旦注册,那么全局混入的选项将会影响每一个组件。


app.mixin(混入的对象)


混入的代码和该组件中本身的代码执行顺序:全局混入 > 混入 > 自身组件中的代码。


Vue的组件化


我们将一个完整的页面分成很多个组件,每个组件都用于实现页面的一个功能块,而每一个组件又可以进行细分,而组件本身又可以在多个地方进行复用。前面我们的createApp函数传入了一个对象App,这个对象其实本质上就是一个组件,也是我们应用程序的根组件。


vue中的组件其实很简单,官网讲的很详细。


v3.cn.vuejs.org/guide/compo…


但是有很多需要注意的地方。接下来我们就介绍一下:


props约束


  • 当传递的是对象或者数组,我们指定默认值必须是一个工厂函数。并且返回默认值对象和数组。


  • 我们可以通过数组来表示可以是多个类型。


  • 我们还可以通过validator检验函数来自定义约束类型。


  • Prop 的大小写命名,最好使用-链接命名。


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


非props属性处理


当我们传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits时,就称之为 非Prop的Attribute。


  • 当组件有单个根节点时,非Prop的Attribute将自动添加到根节点的Attribute中


  • 如果我们不希望组件的根元素继承attribute,可以在组件中设置 inheritAttrs: false


  • 禁用attribute继承的常见情况是需要将attribute应用于根元素之外的其他元素。


  • 我们可以通过 $attrs来访问所有的 非props的attribute。


  • 多个根节点的attribute


  • 多个根节点的attribute如果没有显示的绑定,那么会报警告,我们必须手动的指定要绑定到哪一个属性上。


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


子组件向父组件传参


我们可以通过emits来对传递的事件参数进行校验,如果出现不符合的,将会出现警告。


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


如果我们徐想要校验参数,直接写数组就行。


emits: ["add", "sub", "addN"]


全局事件总线


主要用在非父子组件传递参数。


Vue3从实例中移除了 on、on、onoff 和 $once 方法,所以我们如果希望继续使用全局事件总线,要通过第三方的库mitt


// eventBus.js
    import mitt from 'mitt';
    const emitter = mitt();
    export default emitter;


注册和监听事件


// 发送事件 
    emitter.emit("字符串事件名", 参数) 
    // 定义事件 
    emitter.on('字符串事件名', 回调函数)
    // 监听所有事件
    emitter.on('*', (事件类型, 对应事件传递的参数) => {})


移除事件


// 移除所有事件
    emitter.all.clear()
    // 移除指定事件
    emitter.off("事件名", 移除事件的引用)


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


vite的简单介绍


下一代前端开发与构建工具。


他是解决上一代构建工具的问题:


  • 在实际开发中,我们编写的代码往往是不能被浏览器直接识别的,比如ES6、TypeScript、Vue文件等等。所以我们必须通过构建工具来对代码进行转换、编译,类似的工具有webpack、rollup、parcel。


  • 随着项目越来越大,需要处理的JavaScript呈指数级增长,模块越来越多。


  • 构建工具需要很长的时间才能开启服务器,HMR也需要几秒钟才能在浏览器反应出来。


  • 开发阶段不需要对代码做过多的适配,并且将浏览器不能识别的文件都转化为esModule文件,提升构建速度,开发效率提升。当项目打包时,在对项目做适配。


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


它主要由两部分组成:


  • 一个开发服务器,它基于原生ES模块提供了丰富的内建功能,HMR的速度非常快速;


  • 一套构建指令,它使用rollup打开我们的代码,并且它是预配置的,可以输出生成环境的优化过的静态资源;


如果我们不借助于其他工具,直接使用ES Module来开发有什么问题呢?


  • 首先,当加载一个库时,加载了这个库的所有依赖模块的js代码,对于浏览器发送请求是巨大的消耗。


  • 其次,我们的代码中如果有TypeScript、less、vue等代码时,浏览器并不能直接识别。


多以上述问题就需要vite来解决。


现在先安装vite


npm install vite –g  #全局安装
    npm install vite –D  #局部安装


Vite对css的支持


  • vite可以直接支持css的处理


  • vite可以直接支持css预处理器,比如less,sass


  • 但是需要安装less,sass编译器


npm install less -D
    npm install sass -D


  • vite直接支持postcss的转换:


  • 只需要安装postcss,并且配置 postcss.config.js 的配置文件即可


npm install postcss postcss-preset-env -D


// postcss.config.js
    module.exports = {
      plugins: [
        require("postcss-preset-env")
      ]
    }


vite对Typescript的支持


  • vite对TypeScript是原生支持的,它会直接使用ESBuild来完成编译:


  • 只需要直接导入即可。


如果我们查看浏览器中的请求,会发现请求的依然是ts的代码:


这是因为vite中的服务器Connect会对我们的请求进行转发,获取ts编译后的代码,给浏览器返回,浏览器可以直接进行解析。 注意:在vite2中,已经不再使用Koa了,而是使用Connect来搭建的服务器


Vite对vue的支持


  • Vue 3 单文件组件插件支持:@vitejs/plugin-vue


  • Vue 3 JSX 插件支持:@vitejs/plugin-vue-jsx


  • Vue 2 插件支持:underfin/vite-plugin-vue2 在vite.config.js中配置插件:


const vue = require('@vitejs/plugin-vue')
    module.exports = {
      plugins: [
        vue()
      ]
    }


上述配置完成后,我们引入.vue文件,并启动项目,会报错。这时候需要我们安装@vue/compiler-sfc插件即可。


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


Vite脚手架工具


执行以下命令即可创建一个完整的vue项目。


npm install @vitejs/create-app -g
    create-app 项目名


插槽


插槽的作用


通过props传递给组件一些数据,让组件来进行展示,但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素。我们可以定义插槽,让外部可以自定义展示的内容和元素。


插槽的使用


插槽的使用过程其实是抽取共性、预留不同。我们会将共同的元素、内容依然在组件内进行封装。同时会将不同的元素使用slot标签作为占位,让外部决定到底显示什么样的元素。


具体使用可以访问官网。


v3.cn.vuejs.org/guide/compo…


下面我们来介绍插槽使用的需要注意什么。


注意事项


  • 如果想要给插槽做样式定义,我们需要给slot标签包裹上一个div元素,如果直接在slot标签上写class,那么插槽替换的内容将替代完整的slot插槽。


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


  • 除了默认插槽外,我们传入内容是都需要在template标签上指定插槽的名称。


  • 可以通过 v-slot:[SlotName]方式动态绑定一个名称。


  • 插槽不能访问提供插槽的组件中的属性。


  • 如果我们渲染插槽的时候,需要用到子组件中的数据,我们就可以通过作用域插槽来将数据传递到父组件进行使用。数据放在一个对象中,并且将作为v-slot指令的值。


// 这里的item, index属性将会被放入一个对象中传递给父组件。
     <slot :item="item" :index="index"></slot>


动态组件


我们如果需要根据条件切换组件,我们就可以使用component标签。并指定一个is属性。其中is属性的值:


  • 可以是通过component函数注册的组件。


  • 在一个组件对象的components对象中注册的组件。 所以切换组件,我们就可以改变is属性中的值。


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


并且,我们还可以将组件中的props和事件写入component组件进行传递。当渲染对应的组件时,就会将props和事件传入到对应的组件中。


<component :is="currentTab"
             name="zh"
             :age="20"
             @pageClick="pageClick">
    </component>


组件缓存


默认情况下,我们每次离开一个组件时,该组件都会被销毁,有时候,我们希望保持组件的状态。所以就需要使用keep-alive组件来包裹住需要缓存的组件。只要被包裹后,该组件中的状态就不会消失。


keep-alive有一些属性:(这些一般用于动态组件,路由使用。单个组件包裹一般不需要)


  • include - string | RegExp | Array。只有名称匹配的组件会被缓存。


  • exclude - string | RegExp | Array。任何名称匹配的组件都不会被缓存。


  • max - number | string。最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁。


include 和 exclude prop 允许组件有条件地缓存:


  • 二者都可以用逗号分隔字符串、正则表达式或一个数组来表示。


  • 匹配首先检查组件自身的 name 选项。


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


如果我们想要在组件缓存进入和离开之前做一些事情的时候,我们不能调用create, unmounted钩子函数,但是vue给我们内置了用activateddeactivated 这两个生命周期钩子函数。


activated() {
      console.log("about activated");
    },
    deactivated() {
      console.log("about deactivated");
    }


异步组件


如果我们的项目过大了,对于某些组件我们希望通过异步的方式来进行加载(目的是可以对其进行分包处理),那么Vue中给我们提供了一个函数:

defineAsyncComponent


defineAsyncComponent接受两种类型的参数:


  • 类型一:工厂函数,该工厂函数需要返回一个Promise对象。


defineAsyncComponent(() => import("./AsyncCategory.vue"))


上面的import函数返回的就是一个promise对象。是es6的语法。


  • 类型二:接受一个对象类型,对异步函数进行配置。


import { defineAsyncComponent } from 'vue'
    const AsyncComp = defineAsyncComponent({
    // 工厂函数
    loader: () => import('./Foo.vue')
    // 加载异步组件时要使用的组件
    loadingComponent: LoadingComponent,
    // 加载失败时要使用的组件
    errorComponent: ErrorComponent,
    // 在显示 loadingComponent 之前的延迟 | 默认值:200(单位 ms)
    delay: 200,
    // 如果提供了 timeout ,并且加载组件的时间超过了设定值,将显示错误组件
    // 默认值:Infinity(即永不超时,单位 ms)
    timeout: 3000,
    // 定义组件是否可挂起 | 默认值:true
    suspensible: false,
    /**
    *
       * @param {*} error 错误信息对象
       * @param {*} retry 一个函数,用于指示当 promise 加载器 reject 时,加载器是否应该重试
       * @param {*} fail  一个函数,指示加载程序结束退出
       * @param {*} attempts 允许的最大重试次数
       */
      onError(error, retry, fail, attempts) {
        if (error.message.match(/fetch/) && attempts <= 3) {
          // 请求发生错误时重试,最多可尝试 3 次
          retry()
        } else {
          // 注意,retry/fail 就像 promise 的 resolve/reject 一样:
          // 必须调用其中一个才能继续错误处理。
          fail()
        }
      }
    })


结合Suspense组件使用


与之结合使用后,他会忽略提供的异步组件中的加载、错误、延迟和超时选项。 suspense组件,具有两个插槽。而且两个插槽只能有一个直接子节点。


  • default默认插槽,用来显示异步组件。


  • fallback插槽,用来显示加载时的组件。


<suspense>
      <template #default>
        // 异步组件
        <async-category></async-category>
      </template>
      <template #fallback>
        <loading></loading>
      </template>
    </suspense>


teleport组件


在组件化开发中,我们封装一个组件A,在另外一个组件B中使用。那么组件A中template的元素,会被挂载到组件B中template的某个位置。最终我们的应用程序会形成一颗DOM树结构。


但是某些情况下,我们希望组件不是挂载在这个组件树上的,可能是移动到Vue app之外的其他位置。比如移动到body元素上,或者我们有其他的div#app之外的元素上。这个时候我们就可以通过teleport来完成。


Teleport是什么呢?


它是一个Vue提供的内置组件,类似于react的Portals。teleport翻译过来是心灵传输、远距离运输的意思。


它有两个属性:


  • to:指定将其中的内容移动到的目标元素,可以使用选择器。


  • disabled:是否禁用 teleport 的功能。但是他仍然是使用方的子组件。仍然可以传递props。同一个目标父组件可以挂载多个teleport传递的组件。按先后顺序插入。


<teleport to="#zh">
      <hello-world :name="helloVal"></hello-world>
    </teleport>
    <teleport to="#zh">
      <p>另外一个组件</p>
    </teleport>
      components: {
        HelloWorld,
      },
      setup() {
        const helloVal = ref('hello')
        return {
          helloVal,
        }
      }


// HelloWorld.vue
  <div>
    <h2>{{name}}</h2>
  </div>
  props: ['name']
}


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


vue生命周期


每个组件都可能会经历从创建、挂载、更新、卸载等一系列的过程。在这个过程中的某一个阶段,用于可能会想要添加一些属于自己的代码逻辑(比如组件创建完后就请求一些服务器数据)。


但是我们如何可以知道目前组件正在哪一个过程呢?


Vue给我们提供了组件的生命周期函数,生命周期钩子的 this 上下文将自动绑定至实例中,因此你可以访问 data、computed 和 methods。


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


相关文章
|
3月前
|
JavaScript 前端开发 安全
【技术革新】Vue.js + TypeScript:如何让前端开发既高效又安心?
【8月更文挑战第30天】在使用Vue.js构建前端应用时,结合TypeScript能显著提升代码质量和开发效率。TypeScript作为JavaScript的超集,通过添加静态类型检查帮助早期发现错误,减少运行时问题。本文通过具体案例展示如何在Vue.js项目中集成TypeScript,并利用其类型系统提升代码质量。首先,使用Vue CLI创建支持TypeScript的新项目,然后构建一个简单的待办事项应用,通过定义接口描述数据结构并在组件中使用类型注解,确保代码符合预期并提供更好的编辑器支持。
85 0
|
3月前
|
JavaScript 前端开发 安全
立等可取的 Vue + Typescript 函数式组件实战
立等可取的 Vue + Typescript 函数式组件实战
|
4月前
|
JavaScript 前端开发
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
51 0
【Vue3+TypeScript】CRM系统项目搭建之 — 关于如何设计出优质的 Vue 业务组件
|
5月前
|
JavaScript 安全 前端开发
Vue 3 中的 TypeScript
【6月更文挑战第15天】
84 6
|
6月前
|
JavaScript 前端开发 开发者
类型检查:结合TypeScript和Vue进行开发
【4月更文挑战第24天】TypeScript是JavaScript超集,提供类型注解等特性,提升代码质量和可维护性。Vue.js是一款高效前端框架,两者结合优化开发体验。本文指导如何配置和使用TypeScript与Vue:安装TypeScript和Vue CLI,创建Vue项目时选择TypeScript支持,配置`tsconfig.json`,编写`.tsx`组件,最后运行和构建项目。这种结合有助于错误检查和提升开发效率。
56 2
|
6月前
|
JavaScript 前端开发 开发者
Vue工具和生态系统: Vue.js和TypeScript可以一起使用吗?
【4月更文挑战第18天】Vue.js与TypeScript兼容,官方文档支持在Vue项目中集成TypeScript。TypeScript作为JavaScript超集,提供静态类型检查和面向对象编程,增强代码准确性和健壮性。使用TypeScript能提前发现潜在错误,提升代码可读性,支持接口和泛型,使数据结构和函数更灵活。然而,不是所有Vue插件都兼容TypeScript,可能需额外配置。推荐尝试在Vue项目中使用TypeScript以提升项目质量。
117 0
|
6月前
|
JavaScript 前端开发
在Vue中使用TypeScript的常见问题有哪些?
在Vue中使用TypeScript的常见问题有哪些?
101 2
|
7天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
vue学习第四章
|
7天前
|
JavaScript 前端开发
vue学习第九章(v-model)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript与Vue的大一学生,自学前端2年半,正向全栈进发。此篇介绍v-model在不同表单元素中的应用及修饰符的使用,希望能对你有所帮助。关注我,持续更新中!🎉🎉🎉
vue学习第九章(v-model)
|
7天前
|
JavaScript 前端开发 开发者
vue学习第十章(组件开发)
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文深入讲解Vue组件的基本使用、全局与局部组件、父子组件通信及数据传递等内容,适合前端开发者学习参考。持续更新中,期待您的关注!🎉🎉🎉
vue学习第十章(组件开发)
下一篇
无影云桌面