Vue全家桶之Vue2(保姆级教程)


一、Vue2基础

1.什么是Vue

Vue是用于构建用户界面渐进式JavaScript框架。
所谓构建用户界面就是基于数据渲染出用户所看到的页面。

2.Vue2的特点

1.采用组件化开发。
Vue2将应用拆分为多个独立、可复用的组件,每个组件专注于特定功能,从而提高了代码复用率,让代码更好维护。在后面组件化开发会详细的讲解这部分内容。

2.声明式编码。
像JavaScript则是命令式编码,例如要给一个div添加背景色,首先要获取到该div元素,然后使用元素的 style 对象访问 CSS 属性,设置其背景色backgroundColor。

<div id="myDiv">这是一个 div</div>
<button onclick="changeColor()">改变颜色</button>

<script>
function changeColor() {
  const div = document.getElementById('myDiv');
  div.style.backgroundColor = 'blue'; // 直接设置颜色值
}
</script>

可见,命令式编码以 “如何做” 为核心,他需要通过明确指令告诉计算机每一步操作,关注执行过程。
而声明式编码则更关注于“做什么” ,它不关心具体实现步骤,而是由框架或语言机制处理执行细节。

3.使用虚拟DOM+Diff算法。
在原生JavaScript中,它直接将数据转化为真实DOM,当添加数据或者替换到原数据时,它会重新渲染整个DOM,这就会导致大量不必要的性能开销。
而Vue框架则是将数据转化为虚拟DOM,再由虚拟DOM转为真实DOM。当添加数据或者替换到原数据时,Diff算法会将新旧虚拟DOM进行比对,相同则直接复用真实DOM,不同则再更新。这样就减少了不必要的性能开销。

关于虚拟DOM和Diff算法,有些朋友可能会好奇它们到底是什么。
虚拟DOM: 是一种轻量级的 JavaScript 对象,它是真实 DOM 的抽象表示。
Diff算法:进行精细化比对(新、旧虚拟DOM间),实现最小量更新。


右侧就是虚拟DOM,各位可以对应看看各个属性的数据,这里就不多赘述了。

3.Vue基本语法

(1)准备容器

<div id="root">  </div>

(2)引包(开发版本/生产版本)

//本地引入
 <script type="text/javascript" src="./js/vue.js"></script>
 
 //在线引入
 <!-- 开发版本,包含帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<!-- 生产版本 -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>

(3)创建Vue实例

 new Vue({ })

(4)指定配置项
el:通过选择器指定挂载点,看他为哪个容器服务。
data:为模板提供数据。
一旦data中的数据发生改变,那么页面中用到该数据的地方也会自动更新。

  new Vue({
            el:'#root',
            data:{
                username:''
            }
        })

对于将实例挂载到容器,除了通过el挂载,还有另一种方法:

  vm.$mount('#root')  //$mount是vue原型上的方法,vue实例能够使用

el会在实例创建后立即挂载到容器上,而$mount更具灵活性,能够控制挂载时机。甚至可以通过定时器让它1秒钟后再挂载。

 <div id="root">{{msg}}</div>
    <script>
        const vm=new Vue({
            data:{
                msg:'aaa'
            }
        })
        setTimeout(function(){
             vm.$mount('#root')
        },1000)
    </script>   

另外data除了可以写成“对象式”,还可写为“函数式”。

 <div id="root"></div>
    <script>
        const vm=new Vue({
            el:'#root',
            data:function(){
               return{
               msg:'aaa'
             }
            }
        })
        //可简写为:
          data(){
             return{
              msg:'aaa'
             }
    </script>   


需要记住的是:
组件化开发时data必须写成函数!!
当data是普通函数时,this——>vue实例
当data是箭头函数时,由于箭头函数没有this,所以this——>window
所以data最好写为普通函数

4.插值表达式

{{表达式}}

作用:利用表达式进行插值,渲染到页面。
插值表达式可以直接读取到data中的所有属性。
但其实data中数据存储到vue实例上,插值表达式可以直接读取到vm上数据。

 <div id="root">{{msg}}</div>
    <script>
       new Vue({
            data:{
                msg:'aaa'
            }
        })
    </script>   

结果:
在这里插入图片描述

5.Vue指令

v-html

v-html的作用是将绑定表达式的值作为 HTML 内容插入到所在的 DOM 元素中,支持解析标签。双引号里不能直接放置需要显示的字符串内容。
错误示例:

<div v-html="<span>这段内容不会被正确解析</span>"></div>

正确用法:应该将 HTML 字符串定义在 Vue 实例的数据属性中,然后通过v-html绑定这个属性。

  <div id="root">
    <div v-html="msg"></div>
   </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                msg:'<h1>文本</h1>'
            }
        })
    </script>   

v-text

可以向所在标签中插入文本,无法解析标签。

  <div id="root">
    <div v-text="msg1">初始文本</div>
   </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                msg1:'文本'
            }
        })
    </script>   

结果:
在这里插入图片描述
他的效果类似于插值表达式{{msg1}},但插值表达式可以进行拼接,而v-text拿到msg1的值后会完全覆盖掉整个div的内容


v-show

控制元素的显示、隐藏
等价于为元素添加display:none是视觉上的隐藏,适用于需要频繁切换显示隐藏的时候。
引号内表达式为true显示,为false隐藏。

<div v-show="表达式">文本</div>

v-if

控制元素的显示、隐藏
等价于创建、删除元素,在结构上消失。适用于不频繁显示隐藏。
引号内表达式为true显示,为false隐藏。

<div v-if="表达式">文本</div>

v-else 与 v-else-if

控辅助v-if判断渲染。必须紧跟v-if否则无效。
他会按照顺序依次执行,一旦满足某个条件,就会渲染对应元素,并且不会对后续的条件进行判断,即使下面的判断有成立的。

 <div id="root">
    <div v-if="num===10">文本1</div>
    <div v-else>文本2</div>
   </div>
    <script>
        new Vue({
            el:'#root',
            data:{
                num:10
            }
        })
    </script>   

结果:
在这里插入图片描述

v-on 事件处理

(1)基本语法
v-on是用于监听 DOM 事件的指令,它可以绑定事件监听器到元素上。当指定的事件触发时,会执行对应的 JavaScript 代码或方法。

<!-- 内联语句 -->
<button v-on:click="count++">点击加1</button>     //可直接使用data中数据

<!-- 方法调用 -->
<button v-on:click="handleClick">点击调用方法</button>

<!-- 缩写形式(@符号) -->
<button @click="handleClick">缩写语法</button>

v-on所调用的方法,在vue实例的methods中声明,最终会在vm上。并且当要使用data中的数据时,需要用this指向对应的vue实例,即:this.属性

 <div id="root">
        <button @click="handleClick">点击count加1</button>
        <p>{{count}}</p>
    </div>
    <script>
        new Vue({
            el: '#root',
            data: {
                count: 1
            },
            methods: {
                handleClick() {
                    this.count++
                }
            }
        })
    </script>

要注意这里的this指向并不一定是vue实例,当methods中定义的方法是箭头函数时,this指向window。(所有被vue所管理的函数最好都写成普通函数)

(2)传参
如果事件处理方法没有显式传递参数,Vue 会自动传递原生 DOM 事件对象,event

<button @click="handleClick">点击</button>

methods: {
  handleClick(event) {
    console.log(event.target); // 输出触发事件的DOM元素
  }
}

如果需要传递其他参数时:

<button @click="handleClick(66)">点击</button>

methods: {
  handleClick(num) {
    console.log(num); // 输出66
  }
}

这时候会发现event没有了,就算我们再设置几个参数也没法拿到event。

<button @click="handleClick(66)">点击</button>

methods: {
  handleClick(num,a,b,c) {
    console.log(num,a,b,c); // 输出66,undifined,undifined,undifined
  }
}

那如果既想传传参,还想要event,就可以用 $event进行占位 ,具体顺序无所谓。

<button @click="handleClick(66,$event)">点击</button>

methods: {
  handleClick(num,e) {
    console.log(num,e.target.innerHTML); // 输出66,点击
  }
}

(3)事件修饰符

  • 阻止默认行为:@click.prevent
  • 阻止冒泡:@click.stop
    冒泡:从目标节点—>文档根结点(子—>父)
<div class="demo1" @click="showInfo">
<button @click.stop="showInfo">点我提示信息</button>   //若没阻止冒泡会弹出提示两次
</div>
  • 事件只触发一次:@click.once
  • 进行事件捕获:@click.capture
    捕获:从根节点—>目标结点(父—>子)
  <div class="demo2" @click.capture="showInfo(1)">
        div1
        <div @click="showInfo(2)">div2</div>
    </div>
    <script>
        new Vue({
            el: '.demo2',
            methods: {
                showInfo(value) {
                    console.log(value)
                }
            }
        })
    </script>

在这里插入图片描述

  • 只有当前元素才能触发:@click.self
  <div class="demo2" @click="showInfo">
        div1
        <div @click="showInfo">div2</div>
    </div>
    <script>
        new Vue({
            el: '.demo2',
            methods: {
                showInfo(e) {
                    console.log(e.target)
                }
            }
        })
    </script>

在这里插入图片描述
点击div2,可以发现返回的都是div2,也就是说无论冒泡到哪里,触发事件的一直都是div2。
当为div1加上self修饰符时,并点击div2时:

  <div class="demo2" @click.self="showInfo">
        div1
        <div @click="showInfo">div2</div>
    </div>

在这里插入图片描述
此时确实触发了div1的showInfo,但e.target却是div2,而非它本身,所以div2不会执行。
所以有时候也可以用self去阻止冒泡。

  • 事件默认行为立即执行,无需等待回调函数执行完毕:@click.passive

另外,并不仅仅只可以有一个事件修饰符,当某元素想要阻止默认事件的同时还阻止冒泡,就可以写为:@click.prevent.stop=" "

(4)触发事件

  • 点击事件 @click
  • 键盘事件 @keyup @keydown
    例如在传统javascript中确认点击的是“回车”可以用e.key===‘Enter’
    而在vue中可以写为:@keyup.enter=“ ”
  • 鼠标事件
    @mouseenter :鼠标进入元素时触发 (不冒泡)(推荐)
    @mouseleave:鼠标离开元素时触发 (不冒泡)(推荐)
    @mouseover:鼠标进入元素时触发 (冒泡)
    @mouseout:鼠标离开元素时触发 (冒泡)

v-bind 单向数据绑定

v-bind可以动态设置标签属性。
(1)基础语法
v-bind:属性=“表达式”:属性=“表达式”

<!-- 完整语法 -->
<img v-bind:src="imageUrl" alt="示例图片">

<!-- 缩写语法(推荐) -->
<img :src="imageUrl" alt="示例图片">

例如:

<input  type="text" :value="num"> 
<script>
        new Vue({
            el:'#root',
            data:{
                num:'111' 
            }
        })
    </script>

当data中数据发生变化时,输入框内容发生改变;当输入框内容改变时,data中的数据不发生改变。
这是因为v-bind是单向数据绑定,数据只能从data—>绑定元素

(2)动态绑定样式

class="固定样式"    v-bind:class="变化样式"

不变的样式写在class中,而后期需要变化的样式写在:class中。(原生class与绑定class共存)
通过动态绑定样式,就可以在不操作DOM元素的情况下就能够修改样式,方便vue管理。

1.字符串写法:
在:class中写属性,data属性中存样式。

<template>
  <div :class="activeClass"></div>
</template>

<script>
export default {
  data() {
    return {
      activeClass: 'bg-primary text-white' // 存储在 data 中的类名字符串
    }
  }
}
</script>

<style>
.bg-primary { background-color: blue; }
.text-white { color: white; }
</style>

2.数组写法
有多个样式可供选择,可以通过push、pop、shift操作数组,添加或删除样式。
直接在模板中绑定数组:

<template>
  <div :class="[classA, classB]">示例文本</div>
</template>

<script>
export default {
  data() {
    return {
      classA: 'text-primary',
      classB: 'font-bold'
    }
  }
}
</script>

在data中定义样式数组,动态样式绑定数组名:

<template>
  <div :class="classArr">示例文本</div>
</template>

<script>
data:{
classArr:['text-primary','font-bold']
}
</script>

3.对象写法
适用于样式个数确认、名称确认,并动态切换样式是否使用。

:class="{样式1:布尔值,样式2:布尔值}"
<template>
  <div :class="{ 'active': isActive, 'text-danger': hasError }"> </div>
</template>

<script>
export default {
  data() {
    return {
      isActive: true,
      hasError: false
    }
  }
}
</script>

或:

<template>
  <div :class="classObject">动态样式示例</div>
</template>

<script>
export default {
  data() {
    return {
      classObject: {
     active: true,
     'text-danger': false,
      }
    }
  }
}
</script>

v-model 双向数据绑定

主要服务于表单元素(有value值),进行双向数据绑定,可以快速获取或设置表单元素内容。
当data中数据变化,视图自动更新。
当视图变化,data中数据自动更新。

写法:v-model:属性="值"    v-model="值"    //v-model默认绑定value

6.MVVM模型

是一种前端架构模式,在Vue最开始设计的时候,Vue的作者就参考了MVVM(Model-View-ViewModel)模型。而VUE的双向数据绑定就是利用了MVVM。
M:数据模型(Model)——>data中的数据
V:视图(View)——>模板代码
VM:视图模型(ViewModel)——>Vue实例对象
MVVM 的核心优势在于双向绑定:ViewModel作为“桥梁”,当 Model 变化时通过数据绑定 View 自动更新,View 交互时通过数据监听⑩ Model 同步修改。
在这里插入图片描述

7.数据代理(重点)

7.1 Object.defineProperty

学到数据代理,首先就要明白Object.defineProperty方法。
这个方法主要是用来给对象添加属性。

 Object.defineProperty(对象名,'属性',{
      //基础配置项
      value:属性值,
      enumerable:true/false,   //是否可被枚举,默认false
      writable:true/false,     //是否可被修改,默认false
      configurable:true/false  //是否可被删除,默认false
 })

假设要给person对象添加属性age,并设值为18。

 <script>
    let person={
        name:'pink',
        sex:'女'
    }
    //给person添加属性age
    Object.defineProperty(person,'age',{
        value:18
    })
    console.log(person)
  </script>

结果:
在这里插入图片描述
有人可能说,我直接在对象中加入属性不是Object.defineProperty效果一样嘛。

 <script>
    let person={
        name:'pink',
        sex:'女',
        age:18
    }
    console.log(person)
  </script>

结果:
在这里插入图片描述
两种结果对比,可以发现通过Object.defineProperty添加的属性age颜色较浅,那是因为它想要告诉我们age属性是不可以被枚举的,意思就是说age属性不参与遍历的

<script>
    let person={
        name:'pink',
        sex:'女'
    }
    //给person添加属性age
    Object.defineProperty(person,'age',{
        value:18
    })
    for(let key in person){
        console.log(key)
    }
  </script>

结果:
在这里插入图片描述
若是想让age属性被遍历,就需要在配置项中加入:

 enumerable:true   //enumerable可列举的

它可以控制属性是否可以被枚举,默认值为false,不被枚举的。
另外通过Object.defineProperty添加的属性默认无法修改、无法删除,可以通过以下配置项进行设置。

 writable:true/false,     //是否可被修改,默认false
 configurable:true/false  //是否可被删除,默认false
 //控制台输入delete person.age删除age属性

除了以上基础配置项,Object.defineProperty还有一些高级配置项。

 <script>
    let num=100
    let person={
        name:'pink',
        sex:'女',
        age:num
    }
   console.log(person)
  </script>

在person外面定义一个变量num,并让age的值为num的值。
结果:
在这里插入图片描述
可见确实让age拿到了num的值。但是当我们修改num的值,再次输出person时,却会发现age的值并没有发生变化。
在这里插入图片描述
这是因为在我们定义完num和person后代码已经执行完了,之后再怎么修改num都无法影响到age的值。除非你在修改完num的值后,用person.age=num再次获取到num的值才会变化。
如果我们想在num的值修改之后,age的值也跟着变化,那就要用到Object.defineProperty的高级配置项get了。
当有人读取属性,就会调用get方法。

 <script>
    let num=100
    let person={
        name:'pink',
        sex:'女',
    }
    Object.defineProperty(person,'age',{
        enumerable:true,
        //当有人读取person的age属性时,get方法就会被调用,且返回值就是age的值
        get:function(){
            return num
        }
    })
   console.log(person)
  </script>

在这里插入图片描述
和get相辅相成的还有一个set方法。
当有人修改了数据,就会调用set方法。set方法的参数就是修改后的新值。

 //当有人修改person的age属性时,set方法就会被调用,且会收到具体的值
       set(value){
            console.log('有人修改了age属性,且值为'+value) 
            num=value
        }

在这里插入图片描述

7.2 数据代理

概述:数据代理是通过一个对象代理对另一个对象中属性的操作。(读/写)
数据代理的好处:简化访问,保持API一致性
vue实例通过“数据代理”把_data中所有的属性都代理到实例vm上,使vm.name=vm._data.name。这样就让用户无需通过this._data.xxx去访问数据,而是直接用this.xxx。可以统一通过this去访问数据、方法和计算属性。
基本原理:

  • 通过Object.defineProperty()把data中的所有属性添加到vm上。
  • 为每一个添加到vm上的属性,都指定一个getter/setter。
  • 在setter/getter内部去操作(读/写)data中对应的属性。
    在这里插入图片描述
    首先vue进行数据劫持,将data中的数据存入vue实例vm的_data上,
 <script>
    let obj1={x:100}
    let obj2={y:50}
    //我想让obj2读取到obj1的x属性,并且能够修改x属性
    Object.defineProperty(obj2,'x',{
        get(){
            return obj1.x
        },
        set(value){
            obj1.x=value
        }
    })
  </script>

在这里插入图片描述

 <div id="root">
        <div>{{msg}}</div>
    </div>
  <script>
    const vm=new Vue({
        el:'#root',
        data:{
            msg:111
        }
    })
  </script>

当我们在控制台输入vm时可以发现,在vue实例上有
在这里插入图片描述
在这里插入图片描述
这和之前用Objext.defineProperty()添加的属性效果类似。
当通过vm读msg时通过getter方法读取data中的msg,当通过vm改的msg时通过setter方法改data中的msg。
在这里插入图片描述
vue实例定义了一个_data将data中的数据存在它身上。若要访问data中的数据,可以在控制台输入:

vm._data.属性

在这里插入图片描述
可以发现_data中也有getter/setter方法,但这里不是数据代理,而是做了数据劫持

8.计算属性

计算属性是基于现有数据计算出新属性,它的结果会被缓存,只有在依赖数据变化时才会重新计算
原理:底层借助了Object.defineProperty的getter和setter。
相较于method,computed具有缓存机制。
计算属性会作为属性最终存在vue实例上,直接读取使用即可。
如果计算属性被修改,那么必须写set方法去响应修改,且set中药引起计算时所依赖的数据发生改变。
(1)基本语法

<div>{{计算属性}}</div>     //注意不要和data属性同名
  computed:{
            计算属性(){
                return 结果   //把值返回给计算属性
            }
        }

注意:这种简单写法只能获取,无法修改。(有get无set)
(2)完整写法

   computed:{
            计算属性名:{
              get(){
                return 结果
              },
              set(修改的值){
              //修改依赖数据
              }
            }
        }

get的作用:是当有人读取计算属性时,get就会被调用,且返回值就作为计算属性的值。
get什么时候执行:1.初次读取计算属性时。2.所依赖的数据发生变化时
set什么时候执行:当修改计算属性时。注意要在set中修改依赖数据,否则无效。

我们以拼接姓名为例,分别通过methods与computed实现。

  <div id="root">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName">
    <p>{{fullName()}}</p>    //插值表达式调用method方法记得加()
   </div>
   <script>
    new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        methods:{
            fullName(){
                return this.firstName+'-'+this.lastName
            }
        }
    })
   </script>

在这里插入图片描述

  <div id="root">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName">
    <p>{{fullName}}</p>
   </div>
   <script>
    new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
            fullName(){
                return this.firstName+'-'+this.lastName
            }
        }
    })
   </script>

在这里插入图片描述
可以发现methods与computed的结果完全相同,那既然效果相同又为什么要用computed呢?
那是因为computed相较于methods具有缓存特性
假设:

  <div id="root">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName">
    <p>{{fullName}}</p>   //多次调用计算属性
    <p>{{fullName}}</p>
    <p>{{fullName}}</p>
   </div>
   <script>
    new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
            fullName(){
            console.log('计算属性被调用了调用')
                return this.firstName+'-'+this.lastName
            }
        }
    })
   </script>

结果:计算属性只被调用一次。
在这里插入图片描述

9.监视属性

监视属性(watch)是一种用于监听数据(data属性、计算属性、props)变化并执行相应操作的机制。
若监视的数据不存在,不会报错,新旧值都为undifined。
在 Vue 实例中,可以通过 watch 选项来声明监视属性,监视的属性要写成对象形式。
(1)基本语法
法一:

 watch:{
        监听属性:{
          handler(newValue,oldValue){
           //执行操作
           console.log('新值为'+newValue,'旧值为'+oldValue)
          }
        }
      }

当监听的属性发生变化时,调用handler。
如果希望在 Vue 实例初始化时立即执行一次监听器可以为监听属性添加配置项:immediate:true

简写:
当不需要深度监视,也不需要立即执行时可以用简写方式。

 watch:{
       监视属性(newValue,oldValue){

       }      
      }

法二:

 vm.$watch('监听属性',{
      handle(newValue,oldValue){
        
      }
    })

示例:

 <div id="root">
    <p>{{count}}</p>
    <button @click="count++">点击加一</button>
  </div>
  <script>
    new Vue({
      el:'#root',
      data:{
        count:1
      },
      watch:{
        count:{
          handler(newValue,oldValue){
            console.log('新值为'+newValue,'旧值为'+oldValue)
          }
        }
      }
    })
  </script>

(2)深度监听
当监视多级结构中某个属性的变化,需要用“对象名.属性名”指定监视属性,比方说监听person中的age属性。

 data:{
        msg:1,
        person:{
          name:'pink',
          age:18
        }
      },
        watch:{
        "person.age":{
          handler(newValue,oldValue){
            console.log('新值为'+newValue,'旧值为'+oldValue)
          }
        }
      }

那如果要监视整个person,person中的两个属性只要有一个发生变化就出发监听应该怎么写呢?这时候有人可能就这么写:

   watch:{
        person:{
          handler(newValue,oldValue){
            console.log('新值为'+newValue,'旧值为'+oldValue)
          }
        }
      }

但是控制台却没有任何输出。
原因是watch确实是在监视person对象,但watch却不监视对象里面的属性,而是把对象里面的看作一个整体。无论对象中的值如何变化,对像指定的地址都不发生改变,它就认为对象没有发生变化。
除非把对象整个替换掉,监视才会生效。
正确写法:加配置项deep:true

  watch:{
        person:{
          deep:true    //深度监听
          handler(newValue,oldValue){
            console.log('新值为'+newValue,'旧值为'+oldValue)
          }
        }
      }

这样name变了person监听会运行,age变了person监听也会运行。
所以:watch默认不监听多级结构中的属性,配置deep:true可以监测对像内部值变化。

10.监视属性与计算属性

computed:

  <div id="root">
    姓:<input type="text" v-model="firstName"><br>
    名:<input type="text" v-model="lastName">
    <p>{{fullName}}</p>
   </div>
   <script>
    new Vue({
        el:'#root',
        data:{
            firstName:'张',
            lastName:'三'
        },
        computed:{
            fullName(){
                return this.firstName+'-'+this.lastName
            }
        }
    })
   </script>

watch:

  <div id="root">
    <input type="text" v-model:value="firstName"><br>
    <input type="text" v-model:value="lastName">
    <p>{{fullName}}</p>
    </div>
    <script>
        const vm=new Vue({
            el:'#root',
            data:{
                firstName:'张',
                lastName:'三',
                fullName:''
            },
            watch:{
                firstName(newValue){
                    this.fullName=newValue+'-'+this.lastName
                },
                lastName(newValue){
                    this.fullName=this.firstName+'-'+newValue
                }
            }
        })
    </script>

可以发现watch监听既需要在data中定义fullName,还需要监听firstName和lastName,相较于computed来说比较麻烦。
但当想要修改姓名后1s再更新fullName呢?
watch:

watch: {
                firstName(newValue) {
                    setTimeout(() => {
                        this.fullName = newValue + '-' + this.lastName
                    }, 1000)
                },
            }

computed:

 computed:{
                fullName(){
                    setTimeout(()=>{
                        return this.firstName+'-'+this.lastName
                    },1000)
                }
            }

运行发现用定时器在watch里成功运行,但computed中却无效,这是因为computed不支持异步,watch支持异步任务

为什么 computed 不支持异步?
计算属性(computed)的核心设计是同步计算,因为它必须在依赖数据变化时立即更新结果,以保证数据的响应式一致性。
如果计算属性支持异步:
异步操作的结果不会被 Vue 自动追踪为依赖。
计算属性会在异步完成前就返回 undefined,导致结果不可预测。

watch中定时器要写成箭头函数。
如果是普通函数,this—>window
如果是箭头函数,本身无this,需要向外层寻找,这里定时器的this等同于firstName,而firstName属于vue实例。

*vue中关于要写成箭头函数还是普通函数:
1.被vue所管理的函数,最好写成普通函数,这样this的指向才是vue实例。
2.所有不被vue所管理的函数(如回调函数),最好写成箭头函数,这样this的指向才是vue实例。

<think>好的,用户现在问的是关于优快云热门搜索标题的介绍。首先,我需要回顾之前的对话历史,用户之前问过如何给优快云文章中的图片加超链接,我给出了详细的Markdown和HTML方法,还有注意事项和优化建议。现在用户的新问题是关于优快云热门搜索标题,可能需要了解如何制作或优化这类标题以增加文章的曝光率。 用户可能是在撰写优快云文章时,不仅想技术性地添加元素,比如图片链接,还想让文章标题更吸引人,从而进入热门搜索。因此,用户的需求可能涉及SEO优化、标题技巧、内容策略等方面。 接下来,我需要思考优快云热门搜索标题的特点。通常,这类标题会使用吸引眼球的词汇,如“爆款”、“万字长文”、“保姆教程”等,同时结合技术热点,比如AI、Python、算法等。另外,标题可能会采用疑问句、感叹号、数字列表等方式增强吸引力。 用户可能的深层需求是希望自己的文章能够获得更多流量和关注,因此需要了解如何构造符合优快云平台特性的标题,以及如何利用关键词和趋势。此外,用户可能还想知道如何避免标题党,保持内容与标题的相关性,避免被平台惩罚。 我需要整理这些信息,分点说明热门标题的结构、常用词汇、优化技巧,并给出实际例子。同时,提醒用户注意平台规则,避免违规操作。可能还需要加入SEO建议和工具推荐,比如使用站长工具或5118等分析关键词。 最后,确保回答结构清晰,易于理解,并且实用,帮助用户提升文章的曝光率。</think>在 优快云 平台打造热门搜索标题,需结合 **技术趋势**、**用户痛点** 和 **平台算法特性**。以下是标题设计方法论及示例: --- ### **一、优快云 热门标题核心公式** **<痛点/热点> + <解决方案> + <情绪价值> + <格式强化>** #### **示例解析** 🔥 **"SpringBoot 接口响应慢?3 行代码实现 Redis 缓存提速 20 倍!(附完整代码)"** - **痛点**:接口响应慢 - **方案**:Redis 缓存 - **情绪**:20 倍提速 + 完整代码 - **格式**:问号引发好奇 + 感叹号强调效果 --- ### **二、高频标题结构** #### **1. 问题导向型** - "为什么你的 Python 代码跑得慢?这 5 个性能陷阱 90% 新手都踩过!" - "MySQL 死锁排查太难?手把手教你用 EXPLAIN 破局!" #### **2. 资源合集型** - "2024 最新 AI 工具全家!GitHub 星标 10k+ 的宝藏项目整理" - "Linux 命令记不住?这份思维导图 PDF 免费下载,运维老手都在用" #### **3. 对比反差型** - "别再写循环嵌套了!用 Stream API 重构 Java 代码,效率提升 300%" - "Vue2Vue3 踩坑实录:从 3 天到 3 小时的迁移技巧" #### **4. 悬念揭秘型** - "华为大佬私下传阅的「数据结构速成笔记」,今天终于公开了!" - "面试被吊打后才明白:Redis 高频八股文答案全在这里!" --- ### **三、标题优化技巧** #### **1. 关键词布局** - **必加技术栈**:Python/Java/Spring/深度学习/大模型 - **强化场景词**:面试/实战/源码/调优/避坑/项目落地 ```markdown # 错误示例:如何优化代码? # 正确示例:SpringBoot 高并发场景下接口 QPS 从 100 到 5000 的调优实战 ``` #### **2. 数字魔法** - 奇数和具体数字更吸睛: "7 天搞定机器学习基础" → "5 天吃透 TensorFlow 核心模块" #### **3. 符号使用规范** - **竖线分隔**:`|` 比 `/` 更清晰 "AI绘图|Stable Diffusion 插件安装避坑指南" - **括号补充**:标注资源类型或福利 "(附源码)/(赠PDF)/(限时免费)" --- ### **四、优快云 算法偏好** #### **1. 时效性关键词** - 结合技术热点快速响应: "Claude 3 模型 API 调用全流程详解(2024最新版)" #### **2. 长尾词覆盖** - 避免宽泛,精准定位细分需求: "VSCode 远程连接 Docker 容器配置报错解决方案" #### **3. 互动指标** - 标题暗示可引发收藏/下载行为: "LeetCode 高频算法题解模板(建议收藏)" --- ### **五、避坑指南** | **违规操作** | **替代方案** | |-----------------------|----------------------------------| | 标题党:"震惊!某大厂程序员删库跑路..." | 改为技术复盘:"MySQL 误删数据抢救指南" | | 过度堆砌关键词 | 核心技术词不超过 3 个 | | 夸大效果:"学会这个秒杀所有人" | 量化描述:"响应时间降低 40%" | --- ### **六、工具推荐** 1. **关键词挖掘**:5118大数据 / 百度指数 2. **趋势追踪**:优快云 热搜榜 / GitHub Trending 3. **标题评分**:火龙果写作 / 文心一言标题优化 --- ### **实战案例** #### **修改前** "Python 数据处理教程" #### **修改后** 🔥 **"Pandas 处理 100GB 数据内存爆炸?这 4 个 Dask 技巧让你告别 OOM!(附性能对比图)"** - 点击率提升要素: ✅ 具体场景(100GB大数据) ✅ 解决方案(Dask 技巧) ✅ 量化结果(性能对比) ✅ 紧急感(内存爆炸/OOM)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值