一、汇总
本博客,记录了一些Vue在日常开发工作中比较实用的小技巧,后续会陆续添加更新。
1、利用Sass的:global
定义全局样式。
2、在<style>
内部使用v-bind
给CSS
属性绑定属性值。
3、父子组件传值时,使用.sync
修饰符后,可直接在子组件中通过$emit('update:propName')
来更新父组件中绑定的数据。
4、可在main.js
中通过app.config.globalProperties.***
声明全局变量。
5、通过Vue3新增的<Teleport>
内置组件,将组件内的HTML渲染到指定DOM下。
二、内容
1、利用Sass的:global
定义全局样式。
在 Vue.js 的单文件组件(.vue
文件)中,我们通常使用<style scoped>
来为当前组件添加样式,这样样式就只会作用于当前组件,不会影响其他组件。这实际上是通过给每个元素添加一个独特的属性(如data-v-f3f3eg9
),然后在样式中使用这个属性来选择元素,实现样式的局部作用。
但有时我们可能需要在这个样式块中添加一些全局样式。我们首先可以使用::v-deep
或者>>>
等方式来进行深度选择,不过这只能作用于当前组件内的子组件、子元素。而且无法影响同级或者上级组件、元素。如果我们需要真正的全局样式,那么我们可以使用:global
标记来实现。
:global
是 CSS 模块(CSS Modules)的一个特性,它允许你在模块化 CSS 中编写全局样式。在 CSS 模块中,所有的类名默认都是局部作用域的,也就是说它们只在当前 CSS 文件中有效。但在需要设置一些全局样式,这时就可以使用 :global
特性。在单文件组件(.vue
文件)的 <style>
标签中加入 scoped
属性, Vue 就会把这个样式块视为模块化 CSS。如果没有 scoped,那么所有的样式都会默认为全局样式,:global
就没有意义了。(所以单独写一个<style>
,其内部样式也都是全局样式~)。
在文件A.vue中:
<style lang="scss" scoped>
// 定义全局类名 其样式也变为全局样式
:global(.global-class) {
color: red;
}
// 定义一个普通的局部样式
.normal-class {
// 使用 !important 提升优先级
color: yellow!important;
}
</style>
A.vue同级目录下的B.vue文件中:
<!-- 类名 normal-class 位于后面 优先级更高 -->
<h1 class="global-class normal-class">测试:global全局样式</h1>
页面表现:
元素只受到全局样式.global-class
的影响:
2、在<style>
内部使用v-bind
给CSS
属性绑定属性值
在 Vue.js 的单文件组件(.vue
文件)中,如果我们想要动态的修改一个元素的样式,可以采取的方法有:① 设置行内style样式;② 动态设置类名。现在,我发现了第三种方法,原来Vue提供的v-bind
语法糖是可以直接在<style>
内部使用的,绑定声明的变量,而且实现了双向绑定,我们只需要通过修改变量值,即可动态修改元素样式。
注意:绑定的变量必须是在data
中声明的,否则无法绑定。
使用语法:
/* 变量名之前不需要加this */
css属性名: v-bind(变量名);
具体案例:
<template>
<div>
<h1>测试在style内部使用v-bind给CSS属性绑定属性值</h1>
</div>
</template>
<script>
export default {
data() {
return {
// 声明样式变量
color: "red",
};
},
mounted() {
// 动态修改变量值
setTimeout(() => {
this.color = "blue";
}, 2000);
},
};
</script>
<style lang="scss" scoped>
h1 {
font-size: 30px;
/* 绑定样式变量 */
color: v-bind(color);
}
</style>
页面效果:
初始:
两秒后:
3、父子组件传值时,使用.sync
修饰符后,可直接在子组件中通过$emit('update:propName')
来更新父组件中绑定的数据。
正常情况下,Vue中的数据流是单向的,即从父组件向子组件传递数据。子组件如果想要修改传递的数据,只能通过$emit()
向父组件传递事件,然后父组件监听绑定对应的处理函数,触发后修改数据,然后再自动把修改后的数据传递给子组件,子组件接收的数据才会更新。这实在是太麻烦了。
为了简化这个流程,Vue给我们提供了.sync
这个修饰符,用于实现父子组件之间的双向绑定。在父组件向子组件传值时,使用该修饰符后,我们就可以直接在子组件中通过$emit('update:propName')
来更新数据。这样代码更简洁,逻辑更清晰。
父组件:
<template>
<div>
<h1>这是父组件{{ count }}</h1>
<!-- 向子组件传递数据并使用sync修饰符 -->
<son :count.sync="count"></son>
</div>
</template>
<script>
import son from "../components/son.vue";
export default {
components: {
son,
},
data() {
return {
count: 1,
};
},
};
</script>
子组件:
<template>
<div>
<h3 @click="add()">这是子组件{{ count }}</h3>
</div>
</template>
<script>
export default {
props: {
// 接收父组件传递过来的值
count: {
type: Number,
default: 0,
},
},
methods: {
add() {
// 子组件直接修改父组件传递的值
this.$emit("update:count", this.count + 1);
},
},
};
</script>
页面效果:
初始状态:
点击后:
4、可在main.js
中通过app.config.globalProperties.***
声明全局变量。
如果我们想要在项目中定义一个变量,该变量可以在全局任何一个组件中被访问到,除了使用Vuex
之外,我们还可以通过在main.js
中通过app.config.globalProperties.***
声明全局变量的方式来实现该需求。ding该方式需要借助Vue的createApp()
方法,因此只能在Vue3及之后的版本中使用。
但是要注意通过app.config.globalProperties
定义的全局变量不支持双向绑定,因为这种方式只是将变量添加到Vue实例的原型链上,使得在组件中可以通过this
关键字来访问全局变量,因此该方式适用于初始定义变量值之后,基本不会进行改动,且不需要双向绑定的情况。
main.js文件定义全局变量:
// 导入createApp()函数
import { createApp } from 'vue'
// 导入App组件
import App from './App.vue'
// 创建App应用返回对应的实例对象
const app = createApp(App);
// 挂载全局变量
app.config.globalProperties.$overallObj = { value: 111, name: '全局对象' };
app.config.globalProperties.$overallString = '111全局字符串11111';
// 挂载实例对象
app.mount('#app')
单文件组件(.vue
文件)中,调用全局变量:
<template>
<div>
<h1 @click="changeValue()">
这个地方是调用的main.js中定义的全局字符串 --- {{ this.$overallString }}
</h1>
<h1>这个地方是调用的main.js中定义的全局对象 --- {{ this.$overallObj }}</h1>
</div>
</template>
<script>
export default {
methods: {
changeValue() {
console.log("修改前的全局字符串---", this.$overallString);
console.log("修改前的全局对象---", this.$overallObj);
this.$overallString = "我是改变后的全局字符串";
this.$overallObj.name = "我是改变后的全局对象";
console.log("修改后的全局字符串---", this.$overallString);
console.log("修改后的全局对象---", this.$overallObj);
},
},
};
</script>
页面效果:
初始效果:
触发点击事件后:
5、通过Vue3新增的<Teleport>
内置组件,将组件内的HTML渲染到指定DOM下。
在某些情况下,我们希望组件的某些内容不渲染在当前组件的位置,而是渲染到别的DOM元素下面。最常见的场景就是模态框弹窗组件的实现,我们可以通过给弹窗设置position: fixed;
来做到全屏展示,但是这样写必须限制祖先元素的样式不能有 transform
、perspective
或者 filter
样式属性,因此不太友好。Vue3给我们提供了一种新的实现方案,就是<Teleport>
内置组件。
<Teleport>
是 Vue 3 的新特性,用于将组件内的子节点传输/移动到 DOM 的其他位置。<Teleport>
接收一个 to
属性来指定传送的目标。to
的值可以是一个 CSS 选择器字符串,也可以是一个 DOM 元素对象。设置完,在页面渲染成后,就会发现组件内的子节点渲染到了目标DOM元素下,成为其子节点。但是<Teleport>
挂载时,传送的 to
目标必须已经存在于 DOM 中。
<Teleport>
只改变了渲染的 DOM 结构,它不会影响组件间的逻辑关系。<Teleport>
内部的节点能够正常的与其所在组件内的数据进行数据交互。
组件代码:
<template>
<div>
<!-- 指定内部节点渲染到body元素下 -->
<Teleport to="body">
<h1>这个组件用来测试Teleport内置组件的作用</h1>
</Teleport>
</div>
</template>