前言

最近使用vue3重新写了项目,发现人家都配置好了,使用setup语句可以非常方便的运行各种组件和状态的管理,跟react越来越像了。
最开始参考 Vue3 setup语法糖使用简易教程(上) - 掘金 的使用说明,结合setup的语法糖,熟悉之后各种组件之间的状态同步等,都变得非常的丝滑。
以下文章都是以setup语法糖来做说明

1
2
3
<script setup>
....
</script>

数据相关

ref

string、array、num等对象的情况下可以直接使用ref
如果不使用 ref会导致UI模板的template不能渲染

1
2
3
4
5
6
7
<template>
<div>{{num}}</div>
</template>
<script setup>
import { ref } from "vue";
let num=ref(1)
</script>

ref赋值

ref 赋值需要复制给他的 data.value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script setup>
import { reactive,ref } from "vue";

let data = ref(1)

const setData = () => {
data.value = 2
}

</script>


<template>
<div>
this is :{{ data }}
<button @click="setData">setData</button>
</div>
</template>


ref拿DOM元素

ref 需要在 onMounted生命周期之后才能正常拿到数据,并且需要用ref进行包裹,不然UI无法刷新。但是需要注意的是,你在script中使用ref定义的数据,需要使用 num.value来进行取数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<script setup>
import { ref } from "vue";

// 这里需要定义个foo变量ref(),跟下面组件说上的ref一样的名称
const foo = ref()
let data = ref(1)


const setData = () => {
console.log(foo.value)
}

</script>


<template>
<div>
this is :{{ data }}
<!-- 一样的名称 foo 已经在上面定义过了 -->
<button ref="foo" @click="setData">setData</button>
</div>
</template>


使用reactive定义数据

reactive的定义必须是一个对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<script setup>
import { ref, reactive } from "vue";

// 这里需要定义个foo变量ref(),跟下面组件说上的ref一样的名称

let data = reactive({
foo: "bar",
});


const setData = () => {
data.foo = "change"
}

</script>


<template>
<div>
<div>
this is :{{ data.foo }}
</div>
<!-- 一样的名称 foo 已经在上面定义过了 -->
<button ref="foo" @click="setData">setData</button>
</div>
</template>

常用方法

定义和调用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
 <div>
   <button @click="setFn"></button>
 </div>
</template>
<script setup>
// 以下方法都可以定义函数,按自己开发习惯定义一种即可
let setFn = ()=>{
 console.log("我是匿名函数");
}
function setFn(){
 console.log('我是普通函数');
}
</script>

computed使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<template>
 <div class="box">
   <!-- 在上方调用即可,结果为169 -->
   {{add}}
 </div>
</template>
<script setup>
import { computed, ref } from "vue";
let num1 = ref(13);
let num2 = ref(13);
// 设置个变量接收
let add = computed(() => {
 return num1.value * num2.value;
});

watch 使用

单个watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
 <div class="box">
   <input type="text" v-model="user" />
 </div>
</template>
<script setup>
import { watch, ref } from "vue";
// 用户名
let user = ref();
// watch监听接收两个或者三个匿名函数,第一个是监听的数值,第二个是处理监听函数,第三个是否开启深监听(可选)
watch(
() => user.value,
(newVal, oldVal) => {
   console.log("新值:" + newVal + "旧值:" + oldVal);
},
 // 可选项,是否开启深监听
{
   deep: true
}
);
</script>

多个watch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
 <div class="box">
   <input type="text" v-model="user" />
 </div>
</template>
<script setup>
import { watch, ref } from "vue";
// 用户名
let user = ref();
// watch监听接收两个或者三个匿名函数,第一个是监听的数值,第二个是处理监听函数,第三个是否开启深监听(可选)
watch(
() => user.value,
(newVal, oldVal) => {
   console.log("新值:" + newVal + "旧值:" + oldVal);
},
 // 可选项,是否开启深监听
{
   deep: true
}
);
</script>

组件相关

组件引用

1
2
3
4
5
6
7
8
9
10
11
<template>
 <div class="box">
   <!-- 子组件引用 -->
  <v-child></v-child>
 </div>
</template>
<script setup>
// 引入后无需注册
import vChild from '../components/child.vue'
</script>

defineProps传参(父传子)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//父元素
<template>
 <div class="box">
   <!-- 子组件引用 -->
  <v-child msg='我给子元素带的一段话'></v-child>
 </div>
</template>
//子元素
<template>
   <div class="child">
      我是子组件
   </div>
</template>
<script setup>
import {defineProps} from 'vue'
// 在接收时候也得注意,vue3 props接收必须规定数据类型,如果父元素数据类型出错,那么会报错
const props = defineProps({msg:String})
console.log(props); // Proxy {msg: '我给子元素带的一段话'}
</script>

defineEmits传值(子传父)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//子组件
<template>
   <div class="child">
      我是子组件
   </div>
</template>
<script setup>
import {defineEmits,onMounted} from 'vue'
const emit = defineEmits()
onMounted(()=>{
   emit('getChildMsg','我是子元素,给父元素传的话')
})
</script>

//父组件
<template>
 <div class="box">
   <!-- 接收子组件的方法 -->
   <v-child @getChildMsg="getMsg"></v-child>
 </div>
</template>
<script setup>
// 引入后无需注册
import vChild from "../components/child.vue";
let getMsg = e => {
 console.log(e); //我是子元素,给父元素传的话
};
</script>


defineExpose(父拿子方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//子组件
<template>
   <div class="child">
       {{val}}
   </div>
</template>
<script setup>
import {ref,defineExpose} from 'vue'
let val = ref('我是子组件')
let fn = ()=>{
   val.value='我改变了子组件'
}
// 暴露val和fn
defineExpose({
   val,fn
})
</script>
//父组件
<template>
 <div class="box">
   <!-- 接收子组件的方法 -->
   <v-child ref ='child'></v-child>
 </div>
</template>
<script setup>
// 引入后无需注册
import vChild from "../components/child.vue";
import {ref,onMounted} from 'vue';
// 获取child实例
let child = ref()
onMounted(()=>{
 console.log(child.value.val);//直接打印:我是子组件,并不需要加.value
 // 执行子组件的fn函数
 child.value.fn()
})
</script>

pinia 使用 类似vux

定义一个 pinia

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
// 也可以定义为
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++
},
},
})

在一个组件中使用

先实例化,再使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script setup>
import { ref, reactive } from "vue";
import { useCounterStore } from "@/stores/maintest";


// 这里需要实例化一个counterStore
const counterStore = useCounterStore();

let data = reactive({
foo: "bar",
});

// 设置count的值
const setData = () => {
counterStore.count ++
}

</script>

<template>
<div class="p-10">
<div>
pinia: 【{{counterStore.count}}】
</div>
<button ref="foo" @click="setData">setData</button>
</div>
</template>

两个组件联动

test1.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script setup>
import { ref, reactive } from "vue";
import { useCounterStore } from "@/stores/maintest";
// 这里需要定义个foo变量ref(),跟下面组件说上的ref一样的名称

const counterStore = useCounterStore()

let data = reactive({
foo: "bar",
});


const setData = () => {
data.foo = "change"
}

</script>

<template>
<div class="p-10">
<div>
{{counterStore.count}}
</div>
<div>
this is :{{ data.foo }}
</div>
<!-- 一样的名称 foo 已经在上面定义过了 -->
<button ref="foo" @click="setData">setData</button>
</div>
</template>

test2.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<script setup>
import { ref, reactive } from "vue";
import { useCounterStore } from "@/stores/maintest";


// 这里需要实例化一个counterStore
const counterStore = useCounterStore();

let data = reactive({
foo: "bar",
});

// 设置count的值
const setData = () => {
counterStore.count ++
}

</script>

<template>
<div class="p-10">
<div>
pinia: 【{{counterStore.count}}】
</div>
<button ref="foo" @click="setData">setData</button>
</div>
</template>

实时刷新

1
2
import { useMainStore } from "@/stores/main";
const userFilterTags = computed(()=> mainStore.userFilterTags)

参考

Vue3 setup语法糖使用简易教程(上) - 掘金
Vue3 setup语法糖使用简易教程(下) - 掘金
介绍 | Pinia 中文文档
单组件的编写 | Vue3 入门指南与实战案例