vue笔记
vue笔记(持续更新)
Vue scoped
scoped解决了什么?
模块化编程下,在对应模块的js中import css,这个css仍然是全局。因此会产生css样式之间污染。scoped可以使css样式只作用于当前组件,解决了组件之间样式污染。给每个style都设置上scoped,相当于实现了样式的模块化。
官方解释:当style有scoped属性时,它的CSS只作用于当前组件中元素(解决样式冲突)
<style scoped>
@media (min-width: 250px) {
.list-container:hover {
background: orange;
}
}
</style>
<!--
scoped 会自动添加一个唯一的 attribute (如 data-v-hash) 为组件内 CSS 指定作用域,编译的时候 .list-container:hover 会被编译成 .list-container[data-v-hash]:hover。
-->
例如:
<!-- scoped转译前 -->
<style lang="scss" scoped>
.test {
background: blue;
span{
color:red;
}
}
</style>
<!-- scoped转译后 -->
<style lang="css">
.test[data-v-ff86ae42] {
background: blue;
}
.test span[data-v-ff86ae42]{
color: red;
}
</style>
以前有个人在Vue提了个issue,style的scope使一些必要的css无效,然偶后尤大大亲自耐心的回答了,scope的功能是为了让css更规范,能更简单让css仅对本组件的内容起到作用而不影响其他组件,这样也是为了减少各组件之间的样式黏性,可以避免修改单组件样式而影响到整个项目众多组件的问题。反正能用外联css或公共css文件建立共有的css,所以我是非常建议使用scope但别穿透它
穿透scoped
为什么要穿透scoped?
通过scoped,组件的样式是被封装在组件范围内的,也就是说组件样式对外部组件是不可见的。这种封装样式的机制可以防止样式冲突和作用域污染,提高样式的可维护性。然而某些情况下,我们希望通过组件样式去修改或影响子组件内部的样式。
<template>
<div class="parent">
<child-component class="custom-class" />
</div>
</template>
<style scoped>
.parent /deep/ .custom-class {
/* 修改子组件的样式 */
}
</style>
使用scoped情况
在模板中使用两次style标签
<!-- 使用两次style分别控制 需要覆盖子组件的样式 和 只能本模块使用样式 -->
<style lang="scss">
/*添加要覆盖的样式*/
</style>
<style lang="scss" scoped>
/* 本模块样式 */
</style>
<!-- vue官网明确表示一个vue文件可以包含多个style标签 -->
scoped穿透
<!--使用 >>> 或者 /deep/ 操作符(Sass,less 之类的预处理器无法正确解析 >>>,可以使用/deep/)-->
<style lang="scss" scoped>
.box {
/deep/ input {
width: 166px;
text-align: center;
}
}
</style>
或者
<style lang="scss" scoped>
.box >>> input {
width: 166px;
text-align: center;
}
</style>
不使用scoped情况
-
使用全局样式:将样式定义在全局的CSS文件中,这样定义的样式将会被整个应用所共享。
-
使用CSS Modules:CSS Modules允许您在每个组件中定义独立的、局部作用域的样式,但仍然可以通过类名选择器来影响其他组件的样式
-
使用CSS预处理器:大多数CSS预处理器(如Sass、Less)都支持全局样式和变量。
总结
scoped穿透是一种非正式的语法,不是标准的CSS规范,因此在使用时要谨慎考虑其兼容性和易读性。
总而言之,scoped穿透在一定程度上打破了组件样式的封装性,允许父组件的样式影响到子组件内部的样式,但需要注意合理使用,避免引入样式的混乱和复杂性。
Vue nextTick
为什么会存在nextTick?
vue采用异步更新策略来提高性能,当修改Vue实力数据时,Vue并不会立即更新真实DOM,而是讲DOM更新操作推入一个队列中,在下一个事件循环周期中进行统一的更新。这样做可以有效地合并多次数据变更,避免频繁的DOM操作。然而,这也导致了一个问题:在某些情况下,我们需要在数据更新之后立即访问更新后的DOM。
nextTick作用
通过使用nextTick方法接收一个回调函数作为参数,并讲这个回调函数延迟到下次DOM更新循环结束后执行,确保DOM已经被更新。这样就能够安全地操作更新后的DOM元素,而不用担心获取到旧的值或状态。
nextTick实现原理
将传入的回调函数包装成异步任务,异步任务又分微任务和宏任务,为了尽快执行所以优先选择微任务;
nextTick 提供了四种异步方法 Promise.then、MutationObserver、setImmediate、setTimeout(fn,0)
这四种异步可以阅读nextTick源码解读。
<!-- 例子解释 -->
<script>
console.log('start');
process.nextTick(() => {
console.log('nextTick callback');
});
console.log('end');
</script>
<!-- 输出结果:
start
end
nextTick callback
-->
Vue computed
computed解决了什么问题?
computed 的存在是为了提供一种方便、高效地对响应式数据进行计算和处理的机制。
解决的问题有:
简化复杂逻辑:当需要进行复杂的数据计算或处理时,使用 computed 可以将这些逻辑封装在一个计算属性中,使代码更易于理解、维护和重用。
避免重复计算:computed 会根据其依赖的响应式数据来进行缓存。只有在依赖发生变化时,才会重新计算计算属性的值。这样可以避免重复计算,提高性能并减少不必要的计算开销。
自动追踪依赖关系:Vue.js 的响应式系统会自动追踪 computed 属性所依赖的响应式数据。当依赖的数据发生改变时,相关的计算属性会自动重新计算,确保计算结果的及时更新。
优化模板渲染:通过在模板中使用 computed,可以将复杂的数据处理逻辑移到计算属性中,简化模板的写法,使模板更易读、清晰。
Vue官方示例computed
<!-- message数据需要展示 -->
<template>
<div id="app">
{{message}}
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
message: 'Hello'
}
}
}
</script>
<!-- ! 需求:对message反转并展示 -->
<!-- 正确但不合适的做法:直接在模板转化或在methods中定义一个方法调用 -->
<template>
<div id="app">
<p>{{message}}</p>
<p>{{message.split('').reverse().join('')}}</p>
</div>
</template>
<!-- 正确且合适的做法:使用computed -->
<template>
<div id="app">
<p>{{message}}</p>
<p>{{reverseMessage}}</p>
</div>
</template>
<script>
export default {
name: 'App',
computed: {
reverseMessage: function(){
return this.message.split('').reverse().join('');
}
},
data() {
return {
message: 'Hello'
}
}
}
</script>
解析:
当我们使用不合适的直接转换展示时,每次我们需要完成这个需求,都要写一遍处理逻辑。
使用不合适的methods中定义一个方法,方法写上处理逻辑,每次需要完成这个需求时,调用方法。这种方式表面上不需要写很多遍处理逻辑,但是每次调用这个方法时候,都会执行处理逻辑。
使用合适的computed时,computed会保存处理逻辑的值,每次需要完成这个需求时,直接获取computed缓存好的值,不需要反复执行处理逻辑,只有当依赖项改变时才会重新执行处理逻辑,并缓存更新后的值。
Vue Watch
watch作用?
Vue中的watch又名为侦听属性,它主要用于侦听数据的变化,在数据发生变化的时候执行一些操作。
作用有:
响应式数据的监控:通过 watch,您可以监听指定的数据(包括响应式数据和计算属性),一旦这些数据发生变化,就会触发相应的回调函数。这使得您可以实时捕捉数据的改变并做出相应的处理。
复杂依赖关系的处理:有时候,数据之间存在复杂的依赖关系,一个数据的改变可能会影响到其他相关的数据。使用 watch,您可以轻松地处理这种复杂的依赖关系,监听多个数据,并在其中一个数据发生变化时进行相应的处理。
异步操作的触发:watch 支持异步处理逻辑在回调函数中执行,这对于需要进行异步操作的场景非常有用。例如,当某个数据发生变化后,您可以在回调函数中发送网络请求或执行其他异步任务。
避免不必要的计算开销:由于 watch 会立即执行回调函数来响应数据的变化,因此您可以根据需要选择性地监听特定的数据,避免无谓的计算开销和性能浪费。
Vue 官方示例
Vue官网很明确的建议我们这样使用watch侦听属性:当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
<template>
<p>
Ask a yes/no question:
<input v-model="question" />
</p>
<p>{{ answer }}</p>
</template>
<script>
export default {
data() {
return {
question: '',
answer: 'Questions usually contain a question mark. ;-)'
}
},
watch: {
// 每当 question 改变时,这个函数就会执行
// newQuestion更新后的值,oldQuestion更新前的值
question(newQuestion, oldQuestion) {
if (newQuestion.includes('?')) {
this.getAnswer()
}
}
},
methods: {
async getAnswer() {
this.answer = 'Thinking...'
try {
const res = await fetch('https://yesno.wtf/api')
this.answer = (await res.json()).answer
} catch (error) {
this.answer = 'Error! Could not reach the API. ' + error
}
}
}
}
</script>
解析:
以上定义了一个input框收集用户输入的问题,一个p标签回答用户问题,每当input框的question发生改变时,都会触发watch中的question方法执行处理逻辑,判断是否有?,有则执行methods中的getAnswer方法
computed 和 watch如何选择?
Vue官网的示例
<script>
// 使用computed实现
// 定义计算属性fullName,将firstName和lastName的值进行拼接并返回。
computed: {
fullName: function() {
return this.firstName + ' ' + this.lastName;
}
},
// 使用watch实现
// watch侦听firstName和lastName,当这两个数据发生变化时更新fullName的值。
watch: {
firstName: function(newValue) {
this.fullName = newValue + ' ' + this.lastName;
},
lastName: function(newValue){
this.fullName = this.firstName + ' ' + newValue;
}
}
</script>
解析:
两个方法效率都差不多,每次firstName,lastName都会,而computed实现方式更加简洁。
computed应用场景:模板中有复杂的计算。
watch应用场景:当数据发生变化时执行 异步操作 或者 开销较大的操作。
注意:
当多个数据影响一个数据时,会导致watch多次被调用,这个时候尽量使用computed。
浙公网安备 33010602011771号