Vue进阶:关于Vue常用的语法与指令

1,180 阅读12分钟

1. 引言

上一篇文章我们一起初步认识了一下Vue,今天我们继续来学习一下Vue一些常用的语法与指令。

我们先用vite创建一个项目,得到了我们所需要的目录结构。我们可以在src中的App.vue写代码。这次,我们来实现一下组件化开发。我们可以在components文件夹下写一些demo的vue文件,然后引入到App.vue中作为一个组件来使用。

我们这样来使用,在每个demo里写一些组件,然后用import引入到App.vue文件中。这就是App.vue文件,引入的vue文件就能作为标签使用。

<template>
  <div>
    <demo1></demo1>
    <demo2></demo2>
    <demo3></demo3>
    <demo4></demo4>
    <demo5></demo5>
  </div>
</template>

<script setup>
import demo1 from './components/demo1.vue'
import demo2 from './components/demo2.vue'
import demo3 from './components/demo3.vue'
import demo4 from './components/demo4.vue'
import demo5 from './components/demo5.vue'
</script>

<style lang="css" scoped></style>

2. reactive, ref

我们先到demo1文件中,我们来学习一下reactive和ref的区别。

我们先在template中添加一个button为0,如果我们想点击它就累加,就给它绑定一个点击事件取名为add,然后将add拿到setup函数中写成一个函数,作用是让count累加,那我们就需要再定义一个变量count,我们可以将它写在state对象中,然后引入到button里。

<template>
    <div>
        <button v-on:click="add">{{ state.count }}</button>
    </div>
</template>

<script setup>

const state = {
    count: 0
}

const add = () => {
    state.count++
}
</script>

<style lang="css" scoped></style>

现在页面上确实会出现一个按钮值为0,但我们点击它会有效果吗?并不会,我们在上一篇文章中提到过,因为state对象没有声明为响应式,所以我们需要将reactive引入进来,并把state声明为响应式。

<template>
    <div>
        <button v-on:click="add">{{ state.count }}</button>
    </div>
</template>

<script setup>
import { reactive } from 'vue'

const state = reactive({
    count: 0
})

const add = () => {
    state.count++
}
</script>

<style lang="css" scoped></style>

这样当我们修改count的值,页面就会重新渲染。

PixPin_2024-12-11_22-59-09.gif

成功的实现了累加的效果。

其实Vue中还提供了一个可以声明响应式的方法:ref。我们来使用一下ref看看和reactive有什么区别。

我们再在页面中添加一个button,值为num,我们也要实现一个累加的效果。当我们点击button时,num值能增加。

<template>
    <div>
        <button v-on:click="add">{{ state.count }}</button>
        <button @click="add2">{{ num }}</button>
    </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

const num = 100
const state = reactive({
    count: 0
})

const add = () => {
    state.count++
}
</script>

<style lang="css" scoped></style>

这次我们就不写在对象里。直接声明一个变量为num初始值为100。我们还是需要为这个按钮绑定一个点击事件,取名为add2。我们要想使用ref,同样也要引入。

我们来看看ref是怎么使用的。

<template>
    <div>
        <button v-on:click="add">{{ state.count }}</button>
        <button @click="add2">{{ num }}</button>
    </div>
</template>

<script setup>
import { reactive, ref } from 'vue'

const num = ref(100)
const state = reactive({
    count: 0
})

const add = () => {
    state.count++
}

const add2 = () => {
    num.value++
}
</script>

<style lang="css" scoped></style>

我们需要将num的值传给ref去调用,此时num就是一个响应式变量了。但我们想要使用num的值时,就得num.value去使用,所以我们在add2函数中要写 num.value++。这样完成的效果和reactive一样。

PixPin_2024-12-11_23-14-16.gif

所以它们的效果其实是一样的,只不过是用法和操作对象不同。

  1. reactive 函数负责将一个对象变成响应式,这个对象中任何属性值修改都会触发页面更新
  2. ref 函数 通常用于将一个原始类型变成响应式

但其实ref 函数不止可以将原始类型变成响应式,它也可以将对象变成响应式,只不过它的用法每次都要加上value,很麻烦,所以我们通常拿它声明原始类型,直接用reactive声明对象更痛快。

3. v-bind

demo1就先写成这样,我们再来到demo2中来学习一下v-bind。

在上一篇文章中我们也简单提到过v-bind,它可以动态添加一个属性。

比如我们来实现这样一个效果:我们在页面上添加一个h2标签,里面放上hello world。当我们点击它时,让它的颜色在红色与黄色上反复横跳。

那我们就需要给h2标签绑定一个点击事件取名为handle,并且我们提前写好两个样式,一个类名为yellow将颜色改为yellow,一个类名为red将颜色改为red。

<template>
    <div>
        <h2 @click="handle">hello world</h2>  
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const handle = () => {
    
}
</script>

<style lang="css" scoped>
.red {
    color: red;
}

.yellow {
    color: yellow;
}
</style>

应该怎么写呢?我们可以提前声明一个变量flag,值为false。当我点一下h2标签,就让flag的值变为true,再根据flag的值动态去为h2标签添加类名。是不是就要用上v-bind了呀。

<template>
    <div>
        <h2 v-bind:class="[flag ? 'yellow' : 'red']" @click="handle">hello world</h2>
    </div>
</template>

<script setup>
import { ref } from 'vue'

const flag = ref(false)
const handle = () => {
    flag.value = !flag.value
}
</script>

<style lang="css" scoped>
.red {
    color: red;
}

.yellow {
    color: yellow;
}
</style>

我们需要将flag声明为响应式,于是来用ref函数。每点击一下h2标签,就把flag的值取反。注意这里我们是用ref函数,所以想使用flag的值得写flag.value。再根据flag的值为h2标签动态添加类名。用了一个三元运算符,这里要用 [] 括起来。当flag值为true时,类名就为yellow,当flag值为false时,类名就为red。

我们来看一下有没有这个效果。

PixPin_2024-12-11_23-42-25.gif

成功的实现了这个效果。这就是v-bind的妙用。

我们再来,我们再添加一个h3标签,放上内容‘子俊有点帅’。我希望我鼠标一直点击着文字文字变为绿色,松开鼠标文字变回黑色。

那我们先二话不说给h3标签绑定事件。鼠标一直按住的事件叫mousedown,鼠标放开的事件叫mouseup。

<template>
    <div>
        <h2 v-bind:class="[flag ? 'yellow' : 'red']" @click="handle">hello world</h2>
        <h3 @mousedown="down" @mouseup="up">子俊有点帅</h3>
    </div>
</template>

<script setup>
import { ref } from 'vue'

const flag = ref(false)
const handle = () => {
    flag.value = !flag.value
}

const down = () => {
    
}
const up = () => {
    
}
</script>

<style lang="css" scoped>
.red {
    color: red;
}

.yellow {
    color: yellow;
}

.green {
    color: green;
}
</style>

那我们就需要为h3标签动态添加‘green’类名。当鼠标点击时添加‘green’。当鼠标放开时去除类名。

是不是可以用上一个例子一样的思路啊。我们先准备一个‘isGreen’默认值为false。当触发down事件时,就把‘isGreen’改为true,触发up事件时把‘isGreen’改为false。当‘isGreen’为true时就为h3标签添加‘green’类名。

<template>
    <div>
        <h2 v-bind:class="[flag ? 'yellow' : 'red']" @click="handle">hello world</h2>
        <h3 v-bind:class="{ 'green': isGreen }" @mousedown="down" @mouseup="up">子俊有点帅</h3>
    </div>
</template>

<script setup>
import { ref } from 'vue'

const flag = ref(false)
const handle = () => {
    flag.value = !flag.value
}

const isGreen = ref(false)
const down = () => {
    isGreen.value = true
}
const up = () => {
    isGreen.value = false
}
</script>

<style lang="css" scoped>
.red {
    color: red;
}

.yellow {
    color: yellow;
}

.green {
    color: green;
}
</style>

我们来看一下效果。

PixPin_2024-12-12_09-39-41.gif

我们再来一个h4标签,内容放上‘阿炜有点帅’。我们想给h4标签添加一个行内样式,改变字体的颜色。并且让这个颜色能跟着一个量改变。

这是不是也是动态属性,所以我们也要用上v-bind。我们这样写:

<template>
    <div>
        <h2 v-bind:class="[flag ? 'yellow' : 'red']" @click="handle">hello world</h2>
        <h3 v-bind:class="{ 'green': isGreen }" @mousedown="down" @mouseup="up">子俊有点帅</h3>
        <h4 v-bind:style="{ color: state.color }">阿炜有点帅</h4>
    </div>
</template>

<script setup>
import { ref, reactive } from 'vue'

const flag = ref(false)
const handle = () => {
    flag.value = !flag.value
}

const isGreen = ref(false)
const down = () => {
    isGreen.value = true
}
const up = () => {
    isGreen.value = false
}

const state = reactive({
    color: 'blue'
})
</script>

<style lang="css" scoped>
.red {
    color: red;
}

.yellow {
    color: yellow;
}

.green {
    color: green;
}
</style>

我们声明一个响应式对象state,里面放上一个color值为blue,再将state.color添加到h4标签中去。当我们更改对象中color的值时,h4标签的颜色就能更改。

image.png

初始颜色为蓝色。这样h4标签的颜色就能随着数据的更改而更改。

4. v-show, v-if,v-else

demo2就先写到这里,我们再来到demo3中,来学一下v-show, v-if,v-else

我们先放一个h2标签,内容放上‘章总萌萌的’。再放一个button,内容是‘显示隐藏’。现在页面上会出现:

image.png

我希望当我点击‘显示隐藏’时,‘章总萌萌的’就消失,再点击时就出现。

我们先给button绑定一个点击事件,取名为toggle。

<template>
    <div>
        <h2>章总萌萌的</h2>
        <button @click="toggle">显示隐藏</button>
    </div>
</template>


<script setup>
const toggle = () => {

}
</script>


<style lang="css" scoped></style>

那我们就要用到一个指令v-show。当v-show的值为true时,这个容器就会出现,当值为false时,就会消失。

所以我们可以将这个指令用在h2标签上,再准备一个变量isShow默认值为true。让v-show的值随着变量isShow改变而改变。我们再在toggle去修改isShow的值,每点击一次‘显示隐藏’时,就将isShow的值取反。

<template>
    <div>
        <h2 v-show="isShow">章总萌萌的</h2>
        <button @click="toggle">显示隐藏</button>
    </div>
</template>


<script setup>
import { ref } from 'vue'
const isShow = ref(true)
const toggle = () => {
    isShow.value = !isShow.value
}
</script>


<style lang="css" scoped></style>

我们来看看效果:

PixPin_2024-12-12_10-14-32.gif

成功的实现了效果,并且我们发现,当我们检查时,是h2标签上的display属性在改变,这就是v-show的原理,它可以控制display属性。

还有一个指令也能实现一样的效果:v-if。我们来看看他和v-bind有什么区别。

<template>
    <div>
        <h2 v-if="isShow">章总萌萌的</h2>
        <button @click="toggle">显示隐藏</button>
    </div>
</template>


<script setup>
import { ref } from 'vue'
const isShow = ref(true)
const toggle = () => {
    isShow.value = !isShow.value
}
</script>


<style lang="css" scoped></style>

PixPin_2024-12-12_10-09-58.gif

我们检查一发现,它是直接让h2标签从dom结构中消失了。

v-if还可以与v-else配套使用,比如我们再添加一个h2标签,内容放上‘陈总更萌’,并为它添加这个指令。我们来看看效果。

<template>
    <div>
        <h2 v-if="isShow">章总萌萌的</h2>
        <h2 v-else>陈总更萌</h2>        
        <button @click="toggle">显示隐藏</button>
    </div>
</template>


<script setup>
import { ref } from 'vue'
const isShow = ref(true)
const toggle = () => {
    isShow.value = !isShow.value
}
</script>


<style lang="css" scoped></style>

PixPin_2024-12-12_10-22-15.gif

v-if值为true时就执行v-if,当值为false时就执行v-else。他直接将if,else封装起来给我们使用了,非常方便。

5. v-for,v-model

我们再来到demo4里面,来认识一下v-for,v-model

<template>
    <div>
        <ul>

        </ul>
    </div>
</template>


<script setup>
const list = ['html', 'js', 'css', 'vue', 'json']
</script>


<style lang="css" scoped></style>

我有一个数组list,我希望将list中的值放到ul中的li在页面中展示。这时就需要去遍历数组list了,就要用到 v-for 指令。

<template>
    <div>
        <ul>
            <li v-for="(item, i) in list">{{ i + 1 }} -- {{ item }}</li>
        </ul>
    </div>
</template>


<script setup>
const list = ['html', 'js', 'css', 'vue', 'json']
</script>


<style lang="css" scoped></style>

v-for接收两个参数,item表示数组每一项,i表示下标。

image.png

这样就成功在页面中展示了。

那我们再来,我们再在页面上添加一个input框和一个button,我希望当我在input框输入的内容,当我点击button时,可以直接在页面中li后面添加一项。

<template>
    <div>
        <input type="text">
        <button>添加</button>
        <ul>
            <li v-for="(item, i) in list">{{ i + 1 }} -- {{ item }}</li>
        </ul>
    </div>
</template>


<script setup>
const list = ['html', 'js', 'css', 'vue', 'json']
</script>


<style lang="css" scoped></style>

image.png

这时应该怎么写呢?我们需要获取到用户在input框中输入的内容并把它添加到list数组中去,这样才能在页面中展示。

那我们就需要用到v-model指令了,我们将它添加到input框中,它就能获取用户的输入内容。

<template>
    <div>
        <input type="text" v-model="data">
        <button @click="add">添加</button>
        <ul>
            <li v-for="(item, i) in list">{{ i + 1 }} -- {{ item }}</li>
        </ul>
    </div>
</template>


<script setup>
import { ref } from 'vue'
const list = ref(['html', 'js', 'css', 'vue', 'json'])
const data = ref('')
const add = () => {
    // 获取用户在input框中输入的内容再push进list
    list.value.push(data.value)
}
</script>


<style lang="css" scoped></style>

我们将v-model绑定到data身上,用户输入的内容就会在data中保存。我们就得声明一下data初始值为空字符串。再给button绑定一个点击事件add,当用户点击了button之后,就将用户的输入内容data.value放进数组中。

我们来看看效果。

PixPin_2024-12-12_10-44-42.gif

完美的实现了效果,这就是v-model的妙用。

6. computed, watch

demo4就先写到这里,我们再来到demo5中来认识一下computed, watch

我们来完成一下这样一个效果。

<template>
    <div>
        <h2>当前温度:{{ state.temp }} 建议穿衣:{{ state.suggest }}</h2>
        <button>-5</button>
        <button>+5</button>
    </div>
</template>


<script setup>
import { reactive } from 'vue'

const state = reactive({
    temp: 9,
    suggest: '羽绒服'
})
</script>


<style lang="css" scoped></style>

我们在h2标签里引入了两个变量state.temp和state.suggest,还有两个button,页面效果现在长这样:

image.png

我希望当我点击-5时,温度就减5;点击+5时,温度就加5。并且后面的‘建议穿衣’随着温度改变而改变。比如当大于10度时,‘建议穿衣’显示棉服。

这样应该怎么实现呢?

首先给两个按钮绑定点击事件,由于功能只有一个,我们直接在行内写:

<template>
    <div>
        <h2>当前温度:{{ state.temp }} 建议穿衣:{{ state.suggest }}</h2>
        <button @click="() => state.temp -= 5">-5</button>
        <button @click="() => state.temp += 5">+5</button>
    </div>
</template>

我们想要实现的这个效果底层原理就是:当 state.temp值改变了,state.suggest的值随着它去改变。这就要用到Vue的一个方法:computed,也叫计算属性

computed可以接收一个回调函数,我们可以这样写,把逻辑写到这个回调函数里。当然我们想用computed得先引入:

<template>
    <div>
        <h2>当前温度:{{ state.temp }} 建议穿衣:{{ suggest }}</h2>
        <button @click="() => state.temp -= 5">-5</button>
        <button @click="() => state.temp += 5">+5</button>
    </div>
</template>


<script setup>
import { reactive, computed } from 'vue'

const state = reactive({
    temp: 9,
    // suggest: '羽绒服'
})

const suggest = computed(() => {  // 内部依赖的变量值发生变更,计算属性就会重新执行
    if (state.temp > 30) {
        return '短袖'
    } else if (state.temp > 20) {
        return '夹克'
    } else if (state.temp > 10) {
        return '棉服'
    } else {
        return '羽绒服'
    }
})
</script>


<style lang="css" scoped></style>

我们让suggest等于computed函数的返回结果,当state.temp的值改变时,suggest也会跟着改变。

这样我们是单独声明了一个变量suggest,就不需要用对象里的state了,在h2标签中也直接写suggest。

只要内部依赖的变量值发生变更,计算属性就会重新执行。

我们来看看有没有这个效果:

PixPin_2024-12-12_11-41-19.gif

成功让suggest的值随着state.temp的值改变而改变。

Vue还有一个方法能实现这个效果:watch,也叫监听器。

我们来看看它的用法:

<template>
    <div>
        <h2>当前温度:{{ state.temp }} 建议穿衣:{{ state.suggest }}</h2>
        <button @click="() => state.temp -= 5">-5</button>
        <button @click="() => state.temp += 5">+5</button>
    </div>
</template>


<script setup>
import { reactive, computed, watch } from 'vue'

const state = reactive({
    temp: 9,
    suggest: '羽绒服'
})

watch(
    () => state.temp,
    (newVal, oldVal) => {
        if (newVal > 30) {
            state.suggest = '短袖'
        } else if (state.temp > 20) {
            state.suggest = '夹克'
        } else if (state.temp > 10) {
            state.suggest = '棉服'
        } else {
            state.suggest = '羽绒服'
        }
    })
</script>


<style lang="css" scoped></style>

我们直接将watch触发掉,它接收两个参数。第一个参数你要监听谁,第二个参数是一个回调函数。当第一个参数的值发生改变时,第二个函数就会自动触发。回调函数也接收两个参数:newVal, oldVal。newVal代表state.temp改变后的值,也就是新值;oldVal代表改变前的值,也就是旧值。

在这里我们要用的就是newVal,我们要看state.temp改变之后是否到达了某一个条件,然后去更改state.suggest中的值。

这里我们直接用的就是对象里的suggest。这样的效果和computed是一样的。

PixPin_2024-12-12_11-41-19.gif

7. 总结

本篇文章我们一起学习了一下Vue中常用的语法与指令,这些都是非常好用且方便的方法,好好掌握能对我们的开发效率大有帮助。可以多看几遍。