Vue高级

一、Vue组件

1.1 什么是组件化开发

        组件化开发指的是:根据封装的思想,把页面上可重用的 UI 结构封装为组件,从而方便项目的开发和维护。

1.2 Vue中的组件化开发

        Vue 是一个支持组件化开发的前端框架。

        vue 中规定:组件的后缀名.vue。之前接触到的 App.vue 文件本质上就是一个 Vue 的组件

1.3 Vue 组件的三个组成部分

        每个 .vue 组件都由 3 部分构成,分别是:

  • template  -> 组件的模板结构
  • script       -> 组件的 JavaScript 行为
  • style        -> 组件的样式

其中,每个组件中必须包含 template 模板结构,而 script 行为和 style 样式是可选的组成部分。

Tips:在vscode中安装Vetur和Vue 3 Snippets插件,在新的组件页面输入“<”时就能选择自动生成Vue结构

1.3.1 template

        vue 规定:每个组件对应的模板结构,需要定义到 <template> 节点中。

 注意:

  • template 是 vue 提供的容器标签,只起到包裹性质的作用,它不会被渲染为真正的DOM 元素。
  • template 中只能包含唯一的根节点(el所控制的区域)。

1.3.2 script

        vue 规定:开发者可以在 <script> 节点中封装组件的 JavaScript 业务逻辑。

 注意:

  • .vue 组件中的 data 必须是一个函数,不能直接指向一个数据对象。
data() {
    return {
        username: 'admin'
    }
}

1.3.3 style 

        vue 规定:开发者可以在<style>节点中编写样式,用来美化当前组件的 UI 结构。

        若需要style 中支持 less 语法

在<style>标签上添加 lang="less" 属性,即可使用 less 语法编写组件的样式:

1.4 组件之间的父子关系

组件封装好后,彼此之间是相互独立的,不存在父子关系
使用组件时,根据彼此嵌套关系,形成父子或兄弟关系

1.4.1 使用组件的三个步骤

示例:

<template>
  <div class="app-container">
    <h1>App 根组件</h1>
    <hr />
 
    <div class="box">
      <!-- 以标签的形式使用注册好的组件 -->
      <!-- 渲染 Left 组件和 Right 组件 -->
      <Left></Left>
      <Right></Right>
    </div>
  </div>
</template>
 
<script>
// 1、导入需要使用的.vue组件
import Left from '@/components/Left.vue'
import Right from '@/components/Right.vue'
 
export default {
  // 2、注册组件
  components:{
    Left,
    Right
  }
}
</script>
 
<style lang="less">
.app-container {
  padding: 1px 20px 20px;
  background-color: #efefef;
}
.box {
  display: flex;
}
</style>

注意:路径中的@,Vue默认配置完成,可以使用 @ 作为 src 跟目录

想要导入文件时,有路径提示,先安装Path Autocomplete插件

配置方法:在vscode中的 settings.json 里添加以下代码:

"path-autocomplete.extensionOnImport": true,
"path-autocomplete.pathMappings": {
   "@":"${folder}/src"
 }

Tips:打开settings.json:

点击vscode左下角齿轮设置,在设置界面点击右上角“ 打开设置(json)”

1.4.2 通过 components 注册的是私有子组件

例如:在组件 A 的 components 节点下,注册了组件 F。 则组件 F 只能用在组件 A 中;不能被用在组件 C 中。

为什么 F 不能用在组件 C 中?

        因为C组件中没有注册F;

怎样才能在组件 C 中使用 F?

        在C中的components节点注册F。

1.4.3 注册全局组件

如果某个组件频繁被用到,重复注册会很麻烦,可以注册全局组件解决,只需注册一次,除了自己其他每个组件都可以直接使用。

在 vue 项目的 main.js 入口文件中,通过 Vue.component() 方法,可以注册全局组件。示例代码如下:

// 导入需要被全局注册的那个组件
import Count from '@/components/Count.vue'

//参数1:字符串格式,表示组件的“注册名称”
//参数2:需要被全局注册的那个组件
Vue.component('MyCount', Count)

1.5 组件的 props

        props 是组件的自定义属性,允许在使用自定义属性时为当前组件指定初始值。在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性! 它的语法格式如下:

export default {
  //组件的自定义属性
  //props 里面的属性,也能通过 this访问到
  props:['自定义属性A','自定义属性B','其他自定义属性'...],

  //组件的私有数据
  data(){
    return {

    }
  }
}

然后就能在使用这个组件的组件里使用自定义过的属性,props中的属性可以直接再模板结构中被使用。

举个栗子:

//Count.vue 全局组件名为MyCount
<p>count的值是:{{ init }}</p>
...
<scrpit>
export default {
    ...
    props: ['init']
    ...
    }
</script>
//Left.vue
<MyCount init="9"></MyCount>
//使用的是v-bind属性绑定,此处的9是数值,字符串应该再加一层引号
//Right.vue
<MyCount :init="6"></MyCount>
//使用的是v-bind属性绑定,此处的6是数值,字符串应该再加一层引号

区别:Count.vue是被封装的组件,Left.vue和Right.vue是该被封装组件的使用者。

1.5.1 props 是只读的

vue 规定:组件中封装的自定义属性是只读的,不能直接修改 props 的值。否则会直接报错。

解决办法:如果需要修改props自定义属性的值,可以将其转存到data中,因为data中的数据是可读可写的。

<!-- Count.vue -->
<p>count的值是:{{ count }}</p>
<button @click="count+=1">+1</button>
...
<script>
data() {
    return {
        count: this.init
    }
}
...
</script>

1.5.2 props 的 default 默认值 

        在声明自定义属性时,可以通过 default 来定义属性的默认值。示例代码如下:

export default {
  props: {
    init: {
        //用default定义默认值
      default: 0
      
    }
  },

 实际开发中更多是这样的写法,而不是上述数组的写法。

props中的自定义属性写法


1.5.3 props 的 type 值类型

        在声明自定义属性时,可以通过 type 来定义属性的值类型。示例代码如下:

export default {
  props: {
    init: {
      default: 0,
        // init 的值类型必须是 Number 数字
        //若值的类型不符的时候终端则会报错
      type: Number
      
    }
  },

1.5.4 props 的 required 必填项 

在声明自定义属性时,可以通过 required 选项,将属性设置为必填项,强制用户必须传递属性的值。示例代码如下:

export default {
  props: {
    init: {
      default: 0,
      // init 的值类型必须是 Number 数字
      type: Number,
      // 必填项校验
      required: true
    }
  },

 小结:在封装通用组件的时候,合理地使用 props 可以极大的提高组件的复用性!

1.6 组件之间的样式冲突问题

默认情况下,写在 .vue 组件中的样式会全局生效,因此很容易造成多个组件之间的样式冲突问题。

导致组件之间样式冲突的根本原因是:

  • 单页面应用程序中,所有组件的 DOM 结构,都是基于唯一的 index.html 页面进行呈现的;
  • 每个组件中的样式,都会影响整个 index.html 页面中的 DOM 元素。

1.6.1 思考:如何解决组件样式冲突的问题

        为每个组件分配唯一的自定义属性,在编写组件样式时,通过属性选择器来控制样式的作用域,示例代码如下:

 需要同一组件加相同的属性,不同的组件加的属性不一样。

1.6.2 style 节点的 scoped 属性

        为了提高开发效率和开发体验,vue 为 style 节点提供了 scoped 属性,从而防止组件之间的样式冲突问题:

 (在底层Vue会为该组件的标签加上如1.6.1所描述的属性data-v-xxxx一串数字) 

1.6.3 /deep/ 样式穿透

        如果给当前组件的 style 节点添加了 scoped 属性,则当前组件的样式对其子组件是不生效的。如果想让某些样式对子组件生效,可以使用 /deep/ 深度选择器。

使用场景:当使用第三方组件库的时候,如果有修改第三方组件库默认样式的需求,需要用到/deep/

注意:/deep/ 是 vue2.x 中实现样式穿透的方案。在 vue3.x 中推荐使用 :deep() 替代 /deep/。

小补充:

  1. 实际上浏览器并不认识.vue文件,需要通过Vue模板编译器编译成js文件再渲染到浏览器
  2. 被调用的子组件相当于一个构造函数,是Vue组件的实例对象,以标签形式使用组件相当于new一个构造函数的过程

二、组件的生命周期

2.1 生命周期 & 生命周期函数

生命周期(Life Cycle)是指一个组件从创建 -> 运行 -> 销毁的整个阶段,强调的是一个时间段。

生命周期函数:是由 vue 框架提供的内置函数,会伴随着组件的生命周期,自动按次序执行

注意:生命周期强调的是时间段,生命周期函数强调的是时间点。

2.2 组件生命周期函数的分类

生命周期内的生命周期函数

  • 组件创建之前->组件创建好(内存中)->组件渲染之前->组件渲染到浏览器页面上
  • 组件更新前->组件更新后
  • 组件销毁前->组件销毁后

2.3 生命周期图示

        参考 vue 官方文档给出的“生命周期图示”,进一步理解组件生命周期执行的过程:Vue 实例 — Vue.js

  • created阶段经常调用 methods 中的方法,请求服务器的数据,并把请求到的数据,转存到 data 中,供 template 模板渲染的时候使用
  • mounted阶段可以用于操作DOM元素
  • updated阶段完成了$el中的数据与data中的数据的同步

三、组件之间的数据共享

3.1 组件之间的关系

在项目开发中,组件之间的最常见的关系分为如下两种:

        ① 父子关系 ② 兄弟关系

3.2 父子组件之间的数据共享

父子组件之间的数据共享又分为:

         ① 父 -> 子共享数据 ② 子 -> 父共享数据

3.3 父组件向子组件共享数据

父组件向子组件共享数据需要使用自定义属性props。示例代码如下:

即在子组件中props中声明属性,父组件中被调用的子组件绑定属性并传值。

3.4 子组件向父组件共享数据

子组件向父组件共享数据使用自定义事件。示例代码如下:

当$emit被触发的时候,自定义事件被触发,对应的处理函数被触发。左边this.count是实参,传递给右边val形参。

3.5 兄弟组件之间的数据共享

在 vue2.x 中,兄弟组件之间数据共享的方案是 EventBus。

EventBus 的使用步骤 :

  1. 创建 eventBus.js 模块,并向外共享一个 Vue 的实例对象;
  2. 在数据发送方,调用 bus.$emit('事件名称', 要发送的数据) 方法触发自定义事件;
  3. 在数据接收方,调用 bus.$on('事件名称', 事件处理函数) 方法注册一个自定义事件。 

四、ref引用

4.1 什么是 ref 引用

ref 用来辅助开发者在不依赖于 jQuery 的情况下,获取 DOM 元素或组件的引用。

每个 vue 的组件实例上,都包含一个 $refs 对象,里面存储着对应的 DOM 元素或组件的引用。

<template>
  <div class="right-container">
    <h3>MyRef 组件</h3>
    <button @click="getRef">获取 $refs 引用 </button>
  </div>
</template>

<script>
export default {
  methods: {
    getRef() {
      console.log(this) //打印的是vue的实例对象
    }
  }
  
}
</script>

默认情况下, 组件的 $refs 指向一个空对象。

前面带$的对象是Vue的内置成员。 

4.2 使用 ref 引用 DOM 元素

如果想要使用 ref 引用页面上的 DOM 元素,则可以按照如下的方式进行操作:

<template>
  <div class="right-container">
    <!-- 使用 ref 属性,为对应的 DOM 添加引用名称 -->
    <h3 ref="myh3">MyRef 组件</h3>
    <button @click="getRef">获取 $refs 引用 </button>
  </div>
</template>

<script>
export default {
  methods: {
    getRef() {
      console.log(this)
      //通过this.$refs.引用的名称可以获取到 DOM 元素的引用
      console.log(this.$refs.myh3)
      this.$refs.myh3.style.color = 'red'
    }
  }
  
}
</script>
this是当前组件的实例对象
console.log(this.$refs.myh3)

即想要拿到DOM元素可以给元素加一个ref属性(属性值不能冲突),通过this.$refs.属性名可以拿到。 

4.3 使用 ref 引用组件实例

如果想要使用 ref 引用页面上的组件实例,则可以按照如下的方式进行操作:

即在父组件中引用子组件时给子组件添加ref属性,再通过this.$refs.属性值调用子组件中的方法。

即ref能够获得组件的引用,从而能够调用子组件的方法,从而可以操作子组件中的数据。

这是在父组件中直接去调子组件中的方法最常用的方式。

4.4 控制文本框和按钮的按需切换 

写个小例子,前期准备:通过布尔值 inputVisible 来控制组件中的文本框与按钮的按需切换。示例代码如下:

4.5 让文本框自动获得焦点 

当文本框展示出来之后,如果希望它立即获得焦点。

方法:为其添加 ref 引用,并调用原生 DOM 对象的 .focus() 方法即可。示例代码如下:

此处会出现报错:TypeError: Cennot read property' focus' of undefined 

原用:当数据更新时,页面还没有渲染DOM结构。即当 this.inputVisible=true 执行完,页面上还是button而不是文本框,立即执行DOM操作拿不到。所以拿DOM元素的操作应该放在页面更新完之后进行。

        对此Vue提供了this.$nextTick(cb)方法

4.6 this.$nextTick(cb) 方法

        组件的 $nextTick(cb) 方法,会把 cb (callback)回调推迟到下一个 DOM 更新周期之后执行。

        通俗的理解是:等组件的 DOM 更新完成之后,再执行 cb 回调函数。从而能保证 cb 回调函数可以操作到最新的 DOM 元素。

所以当需要将操作滞后至DOM更新后,可以使用该方法。

### Vue高级应用实验报告示例 #### 实验目标 通过本实验,学习者将深入了解Vue.js高级特性及其实际应用场景。重点包括插件使用、状态管理(Vuex)、生命周期钩子的深入理解以及组件间通信等[^1]。 #### 环境准备 - **Node.js与npm**:确保已安装最新版本的Node.js和npm。 - **Vue CLI**:用于快速搭建Vue项目框架。 - **其他依赖**:根据需求安装Vuex、Vue Router等插件。 #### 核心内容详解 #### 插件集成与使用 在Vue项目中,插件可以通过`Vue.use()`方法进行注册和使用。例如,引入并配置两个自定义插件: ```javascript import Vue from 'vue'; import { Plugin1, Plugin2 } from './plugins'; Vue.use(Plugin1, '参数1'); Vue.use(Plugin2, '参数2'); ``` 此代码片段展示了如何通过`Vue.use()`方法来注册插件,并传递初始化参数[^2]。 #### Vuex状态管理 Vuex是Vue官方的状态管理库,适用于复杂数据流的应用场景。在Vue实例中,`this`指向Vue实例本身,因此可以直接访问Vuex中的状态或调用mutations和actions。需要注意的是,在methods中定义的函数应避免使用箭头函数,以确保`this`正确指向Vue实例[^1]。 #### 生命周期钩子 Vue提供了多个生命周期钩子,如`created`、`mounted`等。这些钩子函数自动绑定`this`上下文到Vue实例中,因此可以直接访问实例属性和方法。同样地,生命周期钩子不应定义为箭头函数,因为这会导致`this`指向父级作用域而非Vue实例[^1]。 #### 组件间通信 Vue支持多种组件间通信方式,包括props、events、provide/inject以及Vuex。对于父子组件通信,推荐使用props和events;而对于跨层级组件通信,则可以借助Vuex或EventBus[^3]。 #### 示例代码 以下是一个简单的Vuex模块示例,展示如何管理全局状态: ```javascript const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment(state) { state.count++; } }, actions: { increment({ commit }) { commit('increment'); } } }); ``` #### 结果分析 通过上述步骤,学习者应能够构建一个具有复杂状态管理和组件间高效通信的Vue应用。同时,对Vue生命周期和插件机制的理解也将更加深刻。 #### 总结 本实验旨在帮助开发者掌握Vue.js高级特性和最佳实践。通过实际操作,加深对框架核心概念的理解,并为进一步探索更复杂的前端架构奠定基础。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值