Vue3+TS系统学习八 - 组件化知识补充(下)

简介: 组件化知识补充(下)

三. 模块引用


3.1. $refs


某些情况下,我们在组件中想要直接获取到元素对象或者子组件实例:

  • 在Vue开发中我们是不推荐进行DOM操作的;
  • 这个时候,我们可以给元素或者组件绑定一个ref的attribute属性;

组件实例有一个$refs属性:

  • 它一个对象Object,持有注册过 ref attribute 的所有 DOM 元素和组件实例。

App.vue的实现:

<template>
  <div>
    <h2 ref="title">哈哈哈</h2>
    <hello-world ref="helloCpn"></hello-world>
    <button @click="visitElement">访问元素或者组件</button>
  </div>
</template>
<script>
  import HelloWorld from './HelloWorld.vue';
  export default {
    components: {
      HelloWorld
    },
    methods: {
      visitElement() {
        // 访问元素
        console.log(this.$refs.title);
        // 访问组件实例
        this.$refs.helloCpn.showMessage();
      }
    }
  }
</script>

HelloWorld.vue实现:

<template>
  <div>
  </div>
</template>
<script>
  export default {
    methods: {
      showMessage() {
        console.log("我是HelloWorld组件的showMessage方法");
      }
    }
  }
</script>


3.2. $parent


我们可以通过$parent来访问父元素。

HelloWorld.vue的实现:

  • 这里我们也可以通过$root来实现,因为App是我们的根组件;
<template>
  <div>
    <button @click="visitParent">访问父组件</button>
  </div>
</template>
<script>
  export default {
    methods: {
      showMessage() {
        console.log("我是HelloWorld组件的showMessage方法");
      },
      visitParent() {
        console.log(this.$parent.message);
      }
    }
  }
</script>

注意:在Vue3中已经移除了$children的属性,所以不可以使用了。


四. 生命周期


4.1. 生命周期图片


什么是生命周期呢?

  • 每个组件都会经历从创建、挂载、更新、卸载等一系列的过程;
  • 在这个过程中的某一个阶段,用于可能会想要添加一些属于自己的代码逻辑(比如组件创建完后就请求一些服务器数据);
  • 但是我们如何可以知道目前组件正在哪一个过程呢?Vue给我们提供了组件的生命周期函数;

生命周期函数:

  • 生命周期函数是一些钩子函数,在某个时间会被Vue源码内部进行回调;
  • 通过对生命周期函数的回调,我们可以知道目前组件正在经历什么阶段;
  • 那么我们就可以在该生命周期中编写属于自己的逻辑代码了;

image.png                                                实例的生命周期


4.2. 生命周期演练


我们通过一个App和Home来演练所有的生命周期函数。

App.vue组件对象:

<template>
  <div>
    <button @click="toggle">切换</button>
    <div v-if="isShow">
      <home></home>
    </div>
  </div>
</template>
<script>
  import Home from './Home.vue';
  export default {
    components: {
      Home
    },
    data() {
      return {
        isShow: true
      }
    },
    methods: {
      toggle() {
        this.isShow = !this.isShow;
        console.log(this.isShow);
      }
    }
  }
</script>

Home.vue组件对象:

<template>
  <div>
    <button @click="changeMessage">修改message</button>
    <h2 ref="titleRef">{{message}}</h2>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        message: "Hello World"
      }
    },
    methods: {
      changeMessage() {
        this.message = "你好啊,李银河";
      }
    },
    beforeUpdate() {
      console.log("beforeUpdate");
      console.log(this.$refs.titleRef.innerHTML);
    },
    updated() {
      console.log("updated");
      console.log(this.$refs.titleRef.innerHTML);
    },
    beforeCreate() {
      console.log("beforeCreate");
    },
    created() {
      console.log("created");
    },
    beforeMount() {
      console.log("beforeMount");
    },
    mounted() {
      console.log("mounted");
    },
    beforeUnmount() {
      console.log("beforeUnmount");
    },
    unmounted() {
      console.log("unmounted");
    }
  }
</script>


五. 组件的v-model


5.1. 组件的v-model


前面我们在input中可以使用v-model来完成双向绑定:

  • 这个时候往往会非常方便,因为v-model默认帮助我们完成了两件事;
  • v-bind:value的数据绑定和@input的事件监听;

如果我们现在封装了一个组件,其他地方在使用这个组件时,是否也可以使用v-model来同时完成这两个功能呢?

  • 也是可以的,vue也支持在组件上使用v-model;

当我们在组件上使用的时候,等价于如下的操作:

  • 我们会发现和input元素不同的只是属性的名称和事件触发的名称而已;

image.png

那么,为了我们的MyInput组件可以正常的工作,这个组件内的 <input> 必须:

  • 将其 value attribute 绑定到一个名叫 modelValue 的 prop 上;
  • 在其 input 事件被触发时,将新的值通过自定义的 update:modelValue 事件抛出;

MyInput.vue的组件代码如下:

<template>
  <div>
    <input :value="modelValue" @input="inputChange">
  </div>
</template>
<script>
  export default {
    props: ["modelValue"],
    emits: ["update:modelValue"],
    methods: {
      inputChange(event) {
        this.$emit("update:modelValue", event.target.value);
      }
    }
  }
</script>

在App.vue中,我们在使用MyInput可以直接使用v-model:

<template>
  <div>
    <my-input v-model="message"/>
    <button @click="changeMessage">修改message</button>
  </div>
</template>
<script>
  import MyInput from './MyInput.vue';
  export default {
    components: {
      MyInput
    },
    data() {
      return {
        message: ""
      }
    },
    methods: {
      changeMessage() {
        this.message = "Hello World"
      }
    }
  }
</script>


5.2. computed实现


在上面的案例中,我们可能会想到一种实现方法:直接将Props中的属性双向绑定到input上

<template>
  <div>
    <input v-model="modelValue">
  </div>
</template>
<script>
  export default {
    props: ["modelValue"]
  }
</script>

上面这种方式可以实现组件的双向绑定吗?答案是不可以

  • 因为我们在内部修改了props之后,外界并不知道我们对props的修改,所以并不会将事件传递出去;
  • 另外,在开发中直接修改props中的属性不是一个好的习惯,不要这样去做;

那么,我们依然希望在组件内部按照双向绑定的做法去完成,应该如何操作呢?我们可以使用计算属性的settergetter来完成。

<template>
  <div>
    <input v-model="value">
  </div>
</template>
<script>
  export default {
    props: ["modelValue"],
    emits: ["update:modelValue"],
    computed: {
      value: {
        get() {
          return this.modelValue;
        },
        set(value) {
          this.$emit("update:modelValue", value)
        }
      }
    }
  }
</script>


5.3. 绑定多个属性


我们现在通过v-model是直接绑定了一个属性,如果我们希望绑定多个属性呢?也就是我们希望在一个组件上使用多个v-model是否可以实现呢?

  • 我们知道,默认情况下的v-model其实是绑定了 modelValue 属性和 @update:modelValue的事件;
  • 如果我们希望绑定更多,可以给v-model传入一个参数,那么这个参数的名称就是我们绑定属性的名称;

我们先看一下在App.vue中我是如何使用的:

<template>
  <div>
    <my-input v-model="message" v-model:title="title"/>
    <h2>{{message}}</h2>
    <button @click="changeMessage">修改message</button>
    <hr>
    <h2>{{title}}</h2>
    <button @click="changeTitle">修改title</button>
  </div>
</template>
<script>
  import MyInput from './MyInput.vue';
  export default {
    components: {
      MyInput
    },
    data() {
      return {
        message: "",
        title: ""
      }
    },
    methods: {
      changeMessage() {
        this.message = "Hello World"
      },
      changeTitle() {
        this.title = "Hello Title"
      }
    }
  }
</script>

注意:这里我是绑定了两个属性的

<my-input v-model="message" v-model:title="title"/>

v-model:title相当于做了两件事:

  • 绑定了title属性;
  • 监听了 @update:title的事件;

所以,我们MyInput中的实现如下:

<template>
  <div>
    <input :value="modelValue" @input="input1Change">
    <input :value="title" @input="input2Change">
  </div>
</template>
<script>
  export default {
    props: ["modelValue", "title"],
    emits: ["update:modelValue", "update:title"],
    methods: {
      input1Change(event) {
        this.$emit("update:modelValue", event.target.value);
      },
      input2Change(event) {
        this.$emit("update:title", event.target.value);
      }
    }
  }
</script>
相关文章
|
2月前
|
JavaScript 前端开发 安全
Vue 3
Vue 3以组合式API、Proxy响应式系统和全面TypeScript支持,重构前端开发范式。性能优化与生态协同并进,兼顾易用性与工程化,引领Web开发迈向高效、可维护的新纪元。(238字)
608 139
|
2月前
|
缓存 JavaScript 算法
Vue 3性能优化
Vue 3 通过 Proxy 和编译优化提升性能,但仍需遵循最佳实践。合理使用 v-if、key、computed,避免深度监听,利用懒加载与虚拟列表,结合打包优化,方可充分发挥其性能优势。(239字)
283 1
|
7月前
|
缓存 JavaScript PHP
斩获开发者口碑!SnowAdmin:基于 Vue3 的高颜值后台管理系统,3 步极速上手!
SnowAdmin 是一款基于 Vue3/TypeScript/Arco Design 的开源后台管理框架,以“清新优雅、开箱即用”为核心设计理念。提供角色权限精细化管理、多主题与暗黑模式切换、动态路由与页面缓存等功能,支持代码规范自动化校验及丰富组件库。通过模块化设计与前沿技术栈(Vite5/Pinia),显著提升开发效率,适合团队协作与长期维护。项目地址:[GitHub](https://github.com/WANG-Fan0912/SnowAdmin)。
1032 5
|
3月前
|
开发工具 iOS开发 MacOS
基于Vite7.1+Vue3+Pinia3+ArcoDesign网页版webos后台模板
最新版研发vite7+vue3.5+pinia3+arco-design仿macos/windows风格网页版OS系统Vite-Vue3-WebOS。
449 11
|
2月前
|
JavaScript 安全
vue3使用ts传参教程
Vue 3结合TypeScript实现组件传参,提升类型安全与开发效率。涵盖Props、Emits、v-model双向绑定及useAttrs透传属性,建议明确声明类型,保障代码质量。
320 0
|
4月前
|
缓存 前端开发 大数据
虚拟列表在Vue3中的具体应用场景有哪些?
虚拟列表在 Vue3 中通过仅渲染可视区域内容,显著提升大数据列表性能,适用于 ERP 表格、聊天界面、社交媒体、阅读器、日历及树形结构等场景,结合 `vue-virtual-scroller` 等工具可实现高效滚动与交互体验。
506 1
|
4月前
|
缓存 JavaScript UED
除了循环引用,Vue3还有哪些常见的性能优化技巧?
除了循环引用,Vue3还有哪些常见的性能优化技巧?
301 0
|
5月前
|
JavaScript
vue3循环引用自已实现
当渲染大量数据列表时,使用虚拟列表只渲染可视区域的内容,显著减少 DOM 节点数量。
147 0
|
7月前
|
JavaScript API 容器
Vue 3 中的 nextTick 使用详解与实战案例
Vue 3 中的 nextTick 使用详解与实战案例 在 Vue 3 的日常开发中,我们经常需要在数据变化后等待 DOM 更新完成再执行某些操作。此时,nextTick 就成了一个不可或缺的工具。本文将介绍 nextTick 的基本用法,并通过三个实战案例,展示它在表单验证、弹窗动画、自动聚焦等场景中的实际应用。
664 17
|
8月前
|
JavaScript 前端开发 算法
Vue 3 和 Vue 2 的区别及优点
Vue 3 和 Vue 2 的区别及优点