当前位置: 首页 > news >正文

Vue 通信组件传值【10】

通信组件传值

  • 1.概述:
  • 2.分类:
  • 3.方式:
    • 1.props传值:
      • 概述:
      • 案例:
      • 测试:
      • 解析:
    • 2.自定义事件传值:
      • 概述:
      • 实现:
      • 测试:
      • 解析:
    • 3.mitt传值:
      • 概述:
      • 实现:
        • 1.安装mitt库
        • 2.配置mitt:
        • 3.发送数据的组件准备数据并发送;
        • 4.接收数据的组件订阅该事件,接收数据并在模板中渲染展示
        • 5.将两个组件都引用到App.vue中
      • 测试:
      • 解析:
    • 4.v-model传值:
      • 概述:
      • 案例:模拟v-model实现数据双向绑定
      • 案例:通过v-model实现数据传输:
        • 1.发送数据:
        • 2.接收数据:
      • 测试:![](https://i-blog.csdnimg.cn/img_convert/c4338b28376141b5cb9bb79336e16dc5.png)
      • 解析:
    • 5.$attrs祖孙传值:
      • 1.实现:
      • 2.测试:
      • 解析:
    • 6.provied和inject传值:
      • 概述:
      • 实现;
      • 测试:
      • 解析:
    • 7.插槽传值:
      • 概述:
        • 1.插槽(Slot)的基本概念:
        • 2.插槽传值的定义和作用:
          • 定义:
          • 作用:
      • 2.使用:
        • 1.默认插槽传值:
          • 实现:
          • 测试:
          • 解析:
        • 2.具名插槽传值:
          • 实现:
          • 测试:
          • 解析:
        • 3.作用域插槽传值::
          • 实现:
          • 测试:
          • 解析:

1.概述:

组件通信即表示Vue在各组件之间相互传递数据;

2.分类:

  • 子父组件传值;
  • 祖孙组件传值;
  • 任意组件之间传值;

3.方式:

1.props传值:

概述:

  • props传值应用在父组件向子组件中传值,或子组件向父组件传值;
  • 通过此方式父组件传递数据给子组件,子组件传递函数给父组件;

案例:

  1.父组件准备数据发送给子组件;
<template>
//展示父组件数据
<h1>我是父组件1:</h1><h2>父组件1的车:{{car}}</h2>//展示从子组件获取到的数据<h2>子组件1的玩具:{{toy}}</h2>//将父组件数据及函数传递到子组件<S1 :car="car" :getToy="getToy"></S1>
</template><script lang="ts" setup name="F1">import {ref} from "vue";import S1 from "./S1.vue";//父组件数据和函数let car=ref('大G')let toy=ref();const getToy=(value:string)=>{console.log("父组件1收到了子组件1的数据:",value)toy.value=value;}
</script><style scoped></style>   

2.子组件接收数据,并发送数据到父组件

<template>
//展示从父组件传递过来的数据;<h1>我是子组件1</h1><h2>父组件1给我的车:{{car}}</h2>//将父组件传递过来的函数绑定到单击事件上,当此事件触发时将数据传输到父组件<button @click="getToy(toy)">发送数据给父组件1</button>
</template><script lang="ts" setup name="S1">
import {defineProps, ref} from "vue";//准备子类数据let toy=ref('奥特曼')//接收父类数据及函数defineProps(['car','getToy'])</script><style scoped></style>

3.将父组件引用在App.vue上

<template>
<F1></F1>
</template><script lang="ts" setup name="App">
import F1 from "./components/F1.vue";</script><style scoped></style>

测试:

通过上面测试结果可以看出,子组件中接收到了父组件传递的数据;

此时单击子组件的功能按钮,发现子组件也成功将数据传递到父组件;

解析:

在上述案例中:

  • 我们在父组件中准备了一个数据car:大G,并通过引用子标签将此数据传递到子组件中;
  • 同时传递到子组件中的还有一个函数getToy,此函数用于子组件传递数据给父组件;
  • 在子组件中首先通过defineprops接收父组件传递过来的数据及函数,并将接收到的数据在模板中渲染展示;
  • 之后通过按钮绑定事件,并将接收到的函数作为此事件的回调函数;将子组件要传给父组件的数据作为此回调函数的参数,当事件触发时就可以将数据传递到负组件中;

2.自定义事件传值:

概述:

此方式主要用于子组件传输数据到父组件

实现:

1.子组件定义自定义事件并绑定到功能按钮上准备发送数据

 <template><h1>我是子组件2:</h1><br/><button @click="emit('xxx-xx','我是子组件')">发送数据给父组件2:</button>
</template><script lang="ts" setup name="S2">import {defineEmits} from "vue";const emit=defineEmits(['xxx-xx'])
</script><style scoped></style>

2.父组件引用子组件,并监听子组件的事件;

<template><h1>我是父组件2:</h1><h2>接收到子组件的数据:{{data}}</h2><hr/><S2 @xxx-xx="getDate"></S2></template><script lang="ts" setup name="F2">
import S2 from "./S2.vue";
import {ref} from "vue";
let data=ref();
const getDate=(value)=>{console.log("接收到了子组件的数据:",value)data.value=value;
}</script><style scoped></style> 

3.将父组件引用到App.vue中

 <template>
<F2></F2>
</template><script lang="ts" setup name="App">
import F2 from './components/F2.vue';</script><style scoped></style>

测试:

单击按钮发送数据给父组件

解析:

  • 在子组件中通过defineEmits([‘xxx-xx’])自定义了一个事件’xxx-xx’并指向函数emit;
  • 子组件中模板中定义按钮并绑定单击事件,并将函数emit绑定到单击事件上,当单击事件触发时就会将emit第二个参数(发送的数据)发送到接收的组件中;
  • 父组件中引用子组件,并监听子组件中的自定义事件执行,当事件执行时就会将数据从子组件传递到父组件;

3.mitt传值:

概述:

mitt传值应用于任意组件之间的传值;

实现:

1.安装mitt库
npm install mitt  
2.配置mitt:

在项目src/utils/emitters:用于mitt配置

//引入 mitt
import mitt from "mitt";//创建 emitter 实例
const emitter = mitt();
//订阅(接收)事件abc和xyz
emitter.on('abc', (value) => {console.log("abc事件被触发了", value)
})emitter.on('xyz', (value) => {console.log("xyz事件被触发了", value)
})
//创建定时器:每隔1秒abc和xyz发布一次数据;
setInterval(() => {emitter.emit('abc', 666)emitter.emit('xyz', 999)}, 1000)
//创建延时器:3秒后清除所有事件
setTimeout(() => {//清除所有的事件emitter.all.clear();
}, 3000)
//暴露mitt实例
export default emitter; 
3.发送数据的组件准备数据并发送;
 <template><h1>我是组件3:</h1><button @click="sendToy">发送数据给组件4</button>
</template><script lang="ts" setup name="F3">
import emitter from "../util/emitter";
import {ref} from "vue";let toy=ref('奥特曼')const sendToy=()=>{console.log('发送数据给组件4')emitter.emit('sendToy',toy.value)}
</script><style scoped></style>
4.接收数据的组件订阅该事件,接收数据并在模板中渲染展示
<template>
<h1>我是组件4:</h1><h2>收到组件3的数据:{{data}}</h2>
</template><script lang="ts" setup name="F4">import emitter from "../util/emitter";import {onBeforeUnmount, onUnmounted, ref} from "vue";let data=ref();emitter.on('sendToy',(value)=>{console.log('收到了组件4的数据',value)data.value=value;})//在此组件销毁之前解绑订阅的事件,避免无休止等待onBeforeUnmount(()=>{//解绑事件emitter.off('sendToy');})
</script><style scoped></style>  
5.将两个组件都引用到App.vue中
 <template><F3></F3><f4></f4>
</template><script lang="ts" setup name="App">
import F3 from "./components/F3.vue";
import F4 from "./components/F4.vue";</script><style scoped></style> 

测试:

通过控制台可以看出此时订阅的abc和xyz事件触发了;

此时点击按钮,发送数据的组件就可以将数据传递到接收数据的组件了;

如果时间超过三秒,再点击按钮时,接收数据的组件将无法接收到数据,因为在mitt配置中,我们定义的延时器会在三秒后清除所有事件,所以在三秒后,接收数据的组件再也收不到订阅的事件了;

解析:

  • 首先安装mitt库,此库通过事件的发布及订阅实现数据的传递
  • 配置mitt实例,包括订阅的事件,事件的发布,及事件的清除等等
  • 在数据发送的组件中,通过mitt实例的emit发布事件并携带要发送的数据;
  • 数据的接收组件订阅该事件,就可以接收到对应的数据了;

4.v-model传值:

概述:

在js中我们了解过v-model指令:用于数据的双向绑定,但实际上可通过v-model指令实现数据传输,其底层是通过一个属性modelValue和一个事件 @update来实现的;

案例:模拟v-model实现数据双向绑定

 <template><h2>姓名为:{{name}}</h2>
<!-- 通过输入事件改变单向绑定为双向绑定  --><inputtype="text":value="name"@input="name= (<HTMLInputElement>$event.target).value"/></template><script lang="ts" setup name="App">import {ref} from "vue";import Test from './components/Test.vue'let name=ref('默认数据');</script><style scoped></style> 

说明:

  • :value="name":这是 Vue.js 中的属性绑定语法(: v-bind 的缩写),它会将 name 变量的值作为 input 文本框的 value 属性的值进行绑定。这样,当组件渲染时,文本框初始会显示 name 变量的初始值,即 “默认数据”。这实现了从数据到视图的单向绑定,确保视图能根据数据的初始状态正确显示。
  • @input="name = (<HTMLInputElement>$event.target).value":这是事件绑定语法,当文本框触发 input 事件(即用户在文本框中输入内容时),会执行绑定的这个表达式。
  • $event 是 Vue.js 在事件处理函数中自动提供的事件对象,$event.target 指向触发事件的 DOM 元素,在这里就是文本框本身。通过 (<HTMLInputElement>$event.target) 将其转换为 HTMLInputElement 类型(确保能正确获取其 value 属性的值),然后将获取到的文本框的新 value 值赋给 name 变量。这样,当用户在文本框中输入新内容时,name 变量的值就会实时更新,从而实现了从视图到数据的反向更新,与前面的单向绑定结合起来就构成了双向数据绑定。

案例:通过v-model实现数据传输:

1.发送数据:
<!--v-model传值-->
<template><h2>姓名为:{{name}}</h2>
<!--通过v-model实现传值:下面为v-model的底层细节展示--><Test v-model="name"></Test><p>--------------------------------</p><Test :modelValue="name" @update:model-value="name=$event"></Test>
</template><script lang="ts" setup name="App">import {ref} from "vue";import Test from './components/Test.vue'let name=ref('默认数据');</script><style scoped></style>
2.接收数据:
 <template><h2>测试组件:</h2><inputtype="text":value="modelValue"@input="emit('update:model-value',$event.target.value)"/>
</template><script lang="ts" setup name="Test">
import {defineEmits, defineProps} from "vue";defineProps(['modelValue'])//声明事件const emit=defineEmits(['update:model-value'])
</script><style scoped></style> 

测试:

通过测试结果可以看出接收数据的组件接收到了数据;

当接收端的数据改变后,发送组建的数据同时也发生了改变;

解析:

  • 案例中本质上是通过v-model指令将数据从发送组件发送到接受组件;
  • v-model指令底层是通过一个属性modelValue和一个事件@update="model-value"来实现数据的双向绑定的;
  • 在案例中我们模仿v-model的底层,通过属性modelValue发送数据到接收组件;
  • 在接受组件中接收该数据,并模拟v-model指令的底层定义事件update=“model-value”;
  • 在接收端的输入框中绑定事件,当输入框内容改变时,将输入框内容改变后的新值发送到发送组件中;
  • 发送组件监听该事件,当事件触发时,就可获取到输入框数据更新后的值了;

5.$attrs祖孙传值:

1.实现:

 1.祖组件App.vue准备数据发送到父组件
 <template><h2>我是App组件</h2><h3>a:{{a}}--b:{{b}}</h3><h3>c:{{c}}--d:{{d}}</h3><F5 :a="a" :b="b" :c="c" :d="d" v-bind="{x:100,y:200}" :updateA="updateA"></F5></template><script lang="ts" setup name="App">import {ref} from "vue";import F5 from './components/F5.vue';let a=ref(1);let b=ref(2);let c=ref(3);let d=ref(4);const updateA=(value)=>{a.value=value;}</script><style scoped></style>

2.父组件将数据发送到子组件

<template>
<h2>我是F5组件</h2><hr/><S5 v-bind="$attrs"></S5><hr/>
</template><script lang="ts" setup name="F5">
import S5 from "./S5.vue";
import {defineProps} from "vue";//如果父组件接收了参数,则孙组件就无法接收到该数据;
//defineProps(['x','y'])
</script><style scoped></style>

3.子组件接收数据,并渲染展示

<template>
<h2>我是S5组件</h2><h2>收到App组件的数据:</h2><h3>a:{{a}}--b:{{b}}</h3><h3>c:{{c}}--d:{{d}}</h3><h3>x:{{x}}--y:{{y}}</h3><button @click="updateA(999)">点击更新数据a</button>
</template><script lang="ts" setup name="S5">import {defineProps} from "vue";defineProps(['a','b','c','d','x','y','updateA'])
</script><style scoped></style>

2.测试:

通过测试结果可以看出子组件接收到了App组件传递的数据;

当点击数据更新按钮时,可以发现在子组件和App.vue组件中的a都发生了改变;

解析:

  • 在App.vue中发送了数据a,b,c,d,x,y和函数updateA到父组件;
  • 父组件通过v-bind="$attrs"将数据转发到子组件中
  • 子组件通过defineprops接收来自于App组件的数据和函数;
  • 将接收到的数据进行渲染展示,并将接收到的函数作为事件的回调函数绑定在按钮上,当事件触发时,更新数据会发送到App组件中;
  • 注意:如果在父组件中接收了App组件传给Son组件的数据,那么在Son组件中将无法在接受到该数据;

6.provied和inject传值:

概述:

 此方式也用于祖孙组件之间的传值,但与$attrs不同的是,此方式不需要借助父组件进行转发,而更像是通过发布订阅模式来直接实现祖孙组件之间的数据传递;

实现;

1.App组件准备数据,并进行发布数据

<template><h3>父组件</h3><h4>资产:{{ money }}</h4><h4>汽车:{{ car }}</h4><button @click="money++">资产++</button><button @click="car.price++">汽车价格++</button><F6></F6>
</template><script setup lang="ts" name="App">
import {provide, reactive, ref} from "vue";
import F6 from './components/F6.vue'let money = ref(100);
let car = reactive({brand: '奔驰',price: 100
})const updateMoney = (value: number) => {money.value += value
}
//提供数据
provide('moneyContext', {money, updateMoney})
provide('carContext', car)</script><style scoped></style> 

2.父组件引用子组件(不做其他处理)

<template><h1>我是Father组件</h1><hr/><S6></S6><hr/>
</template><script lang="ts" setup name="F6">
import S6 from "./S6.vue";</script><style scoped></style>

3.子组件接收数据

<template><h3>我是孙组件</h3><h3>资产:{{ money }}</h3><h3>汽车:{{car}}</h3><button @click="updateMoney(888)">更新资产</button>
</template><script lang="ts" setup name="S6">
import {inject} from "vue";
//接收并解析App组件传递过来的数据及函数;
//inject第二个参数表示默认值;
let {money, updateMoney} = inject('moneyContext', {money: 0, updateMoney: (x: number) => {}
})let car = inject('carContext');
</script><style scoped></style>

测试:

通过测试结果可以看出Son组件接收到了App组件传递的数据;

当App组件中的数据发送更新后,Son组件仍能接收到最新的数据;

当Son组件中修改了接收到的数据时,此修改仍能同步到App组件中;

解析:

  • App组件中准备数据,并通过provied实现数据提供(发布);
  • Father组件仅仅引用展示Son组件,不做其他处理;
  • Son组件通过inject接收App组件发布的数据和函数,并将函数作为回调函数绑定到当前组件模板的功能按钮上,实现了Son组件与App组件数据的双向传递和同步更新;

7.插槽传值:

概述:

1.插槽(Slot)的基本概念:
  • 在 Vue.js 中,插槽是一种用于组件复用和内容分发的机制。它允许在组件的模板中定义一个 “占位符”,这个占位符可以在使用该组件的时候被填充不同的内容。就像是一个有 “空洞” 的模具,在不同的使用场景下,可以往这个 “空洞” 里放入不同的材料来塑造出不同的形状。
  • 插槽分为默认插槽、具名插槽和作用域插槽。
2.插槽传值的定义和作用:
定义:

插槽传值是指在使用插槽的过程中,将数据从父组件传递到子组件插槽内部使用的一种方式。

作用:
  • 增强组件复用性:可以让一个组件在保持自身结构和功能的基础上,根据不同的使用场景接收并展示不同的数据。例如,一个通用的卡片组件,通过插槽传值可以在不同的页面展示不同的标题、内容和图片等信息。
  • 灵活的内容分发:使父组件能够更好地控制子组件内部的部分内容,实现更细粒度的组件定制。比如,在一个布局组件中,父组件可以通过插槽传值决定子组件中的某个区域是显示文本、按钮还是其他自定义的元素。

2.使用:

1.默认插槽传值:
实现:
   1.App.vue组件发送数据:
<template><Category title="热门游戏"><ul><li>植物大战僵尸</li><li>王者荣耀</li><li>原神</li></ul></Category><Category title="热门景点"><img src="./assets/vue.svg"></Category>
</template><script setup lang="ts" name="App">import Category from './components/Category.vue';
</script><style scoped></style>

2.接收数据:

<template><div style="width: 200px;background-color: skyblue"><h3>{{ title }}</h3><!-- 默认插槽  --><slot></slot></div>
</template><script setup lang="ts" name="Category">
defineProps(['title'])</script><style scoped>
h3 {background-color: orange;text-align: center;
}</style>
测试:

解析:
  • App组件两次引用自定义组件Category,用于向自定义组件传输不同的数据;
  • 自定义组件通过defineprops接收App组件传递过来的标题title;
  • 自定义组件通过 <slot></slot> 定义了一个默认插槽,用于接收父组件在使用该子组件时填充进来的内容,比如前面父组件传递的无序列表或图片等内容;
2.具名插槽传值:
实现:

1.App组件发送数据:

<template><Category title="热门游戏"><template v-slot:s1><ul><li>植物大战僵尸</li><li>王者荣耀</li><li>原神</li></ul></template><template #s2><a href="#">更多...</a></template></Category><Category title="热门景点"><template #s2><img src="./assets/vue.svg"></template><template #s1><h4>点击查看</h4></template></Category>
</template><script setup lang="ts" name="App">import Category from "./components/Category.vue";
</script><style scoped></style>

2.接收数据:

<template><div style="width: 200px;background-color: skyblue"><h3>{{ title }}</h3><!-- 具名插槽  --><slot name="s1"></slot><p>我是一段内容</p><slot name="s2"></slot></div>
</template><script setup lang="ts" name="Category">
defineProps(['title'])</script><style scoped>
h3 {background-color: orange;text-align: center;
}</style>
测试:

解析:

App组件中:

  1. 这里两次使用了自定义组件 Category,每次使用时都通过属性绑定 title="热门游戏"title="热门景点" 给子组件传递标题属性。
  2. 对于每个 Category 组件的使用,父组件通过具名插槽向子组件的不同区域传递不同内容:
  3. 当使用 Category 且设置了 title="热门游戏" 时:
  • 通过 <template v-slot:s1> 向名为 s1 的具名插槽传递了一个包含热门游戏列表的无序列表 <ul>
  • 通过 <template #s2>#v-slot 的缩写)向名为 s2 的具名插槽传递了一个带有链接的文本 <a href="#">更多...</a>
  1. 当使用 Category 且设置了 title="热门景点" 时:
  • 通过 <template #s2> 向名为 s2 的具名插槽传递了一张图片 <img src="./assets/vue.svg">

  • 通过 <template #s1> 向名为 s1 的具名插槽传递了一个 <h4> 标题标签,内容为 “点击查看”。

    自定义组件中:

  1. 首先定义了一个 <div> 容器,设置其宽度为 200px 且背景颜色为 skyblue,用于包裹子组件的内容。
  2. <div> 内部,通过插值表达式 {{ title }} 展示了从父组件传递过来的 title 属性的值,会将对应的标题(如 “热门游戏” 或 “热门景点”)显示在一个 <h3> 标题标签内,并且设置了 <h3> 标签的背景颜色为 orange 且文本居中对齐(通过下面的样式部分设置)。
  3. 接着,通过 <slot name="s1"></slot><slot name="s2"></slot> 分别定义了名为 s1s2 的具名插槽,用于接收父组件通过具名插槽传递过来的不同内容,并且在两个具名插槽之间还添加了一段普通文本 <p>我是一段内容</p>
3.作用域插槽传值::
实现:
  1.自定义组件准备数据发送给App组件:
<template><div style="width: 200px;background-color: skyblue"><h3>{{ title }}</h3><!-- 作用域插槽  --><slot :games="games" msg="测试数据"></slot></div>
</template><script setup lang="ts" name="Category">
import {reactive} from "vue";defineProps(['title'])
let games = reactive([{id: '001', name: '植物大战僵尸'},{id: '002', name: '王者荣耀'},{id: '003', name: '原神'}
])</script><style scoped>
h3 {background-color: orange;text-align: center;
}</style>

2.App组件接收数据:

 <template>
<!--  <Category v-slot="params" title="热门游戏">-->
<!--  <Category v-slot:default="params" title="热门游戏">--><Category #default="params" title="热门游戏"><ul><li v-for="g in params.games" :key="g.id">{{ g.name }}</li></ul></Category>
</template><script setup lang="ts" name="App">import Category from "@/components/Category.vue";
</script><style scoped></style>
测试:

解析:

子组件部分:

  • 定义了一个 <div> 容器,设置宽度为 200px 且背景颜色为 skyblue,用于包裹子组件的内容。
  • 通过插值表达式 {{ title }}<h3> 标签内展示从父组件传递过来的 title 属性的值,<h3> 标签的样式被设置为背景颜色是 orange 且文本居中对齐(由子组件的样式部分设置)。
  • 关键在于 <slot :games="games" msg="测试数据"></slot> 这行,这里定义了一个作用域插槽。通过 :games="games" 将子组件内部的数据 games 传递给插槽,同时还传递了一个固定的字符串 msg="测试数据"。当父组件使用这个作用域插槽时,可以获取到这些传递的数据并进行相应的处理。

App组件部分:

  • 这里使用了子组件 Category,并通过属性绑定 title="热门游戏" 给子组件传递了标题属性。
  • 对于作用域插槽的使用,有几种等价的写法,这里采用的是 #default="params"#v-slot 的缩写),它获取了子组件通过作用域插槽传递过来的数据,并将其赋值给 params 变量。然后在 <ul> 列表中,通过 v-for="g in params.games" 循环遍历 params.games(即子组件传递过来的游戏数据数组),并将每个游戏的 name 属性值通过插值表达式 {{ g.name }} 展示在 <li> 标签内。
http://www.dtcms.com/a/487321.html

相关文章:

  • web vue之状态管理Pinia
  • [Backstage] 前端扩展 | 应用扩展树 | 工厂函数 | attachTo附着点
  • 凡科网站案例网站备案好麻烦
  • ps做全屏网站画布要多大网络推广与传统推广的区别
  • 动易网站 首页模板修改智能科技网站模板
  • JVM 内存结构与 GC 机制详解( 实战优化版)
  • JVM垃圾收集器详解(jdk21+25实战版)
  • 花店网站建设规划书如何用易语言做网站辅助
  • 怎样做交互式网站网站建设的标语
  • 【iOS】KVC
  • 自己注册公司网站教育网站建设网站
  • 九度企业网站推广软件合肥网站建设工作
  • Beyond Vision (BV) -具有人工智能功能的全自动多旋翼无人机和混合垂直起降无人机
  • 做网站网络公司无收入阿里巴巴建站多少钱
  • 旅游网站对比模板下载08wordpress主题
  • HTTP之POST请求和GET请求
  • 聚类算法详解:k-means、层次聚类和DBSCAN
  • 廊坊中小企业网站制作做汽配找哪个网站好
  • 网站建设视频教程集工厂管理软件
  • Linux 学习笔记之 VI 编辑器与文件查找技巧
  • 贵阳网站建设多钱钱清远专业网站制作公司
  • 网站设计对网站搜索引擎友好性的影响南宁市两学一做网站
  • 什么是部署php网站邢台城乡建设局网站
  • 搜狐三季度营收多少新开网站seo
  • 基于 clangd 搭建 Redis 6.2 源码阅读与调试环境
  • 备案主体负责人 网站负责人哪个网站做ppt好
  • C文件中在编译时候怎么把几个同名函数链接进来
  • 影视 IP 全链开发:App 如何成为核心
  • 机房网络组建方案搜索引擎优化的核心是
  • CentOS7虚拟机扩容操作指南(CentOS7虚拟机磁盘大小不够)