项目结构(新的)

components

用来装子组件的

assets

用来装css图片等资源

router

有一个index.js用来装不同的url路径对应的处理函数以及所对应的挂载的组件

store

里面装的是一个用来存储不同网页的共同使用的资源的文件

views

里面装的是组件的视窗部分,就是给路由用的

reactive和ref函数

ref reactive
数据类型 原始数据、对象 对象
操作 js中需要添加.valuetamplate中则不用 都不用添加.value

watch监听

1
2
3
4
watch(count, (newCount, oldCount) =>{
console.log(`count change from ${oldCount} to ${newCount}`);
})
//count 的位置可以填对象,基本数据,计算属性等

立即执行

1
2
3
4
5
6
7
8
9
watch(
zzy,
() => {
console.log("zzy changed");
},
{
immediate: true,
}
);

深度监听

当你监听的是一个对象而且没有进行深度监听的时候,当对象的某个属性值改变的时候是不会触发监听事件的。这个时候就要加上一个{deep:true,}

1
2
3
4
5
6
7
8
9
watch(
zzy,
(newZzy, prevZzy) => {
console.log(`zzy changed from ${prevZzy.age} to ${newZzy.age}`);
},
{
deep: true,
}
);

多重监听

主要是把单个名字改成一个数组形式,

1
2
3
4
5
6
7
8
9
10
watch(
[count, zzy],
([newCount, newZzy], [prevCount, prevZzy]) => {
console.log(`多重监听count changed from ${prevCount} to ${newCount}`);
console.log(`多重监听zzy changed from ${prevZzy.age} to ${newZzy.age}`);
},
{
deep: true,
}
);

监听单个属性

1
2
3
4
5
6
watch(
() => zzy.value.age,
(newAge, prevAge) => {
console.log(`zzy.age changed from ${prevAge} to ${newAge}`);
}
);

使用箭头函数作为watch的回调函数可以让我们再函数内部访问到变化前后的属性值

templateRef

  1. 需要在你想要调用的元素的标签名里面加上ref = index(这是一个别名)
  2. <script setup>里面写上const index = ref(null)这里写上null并没关系。
  3. 调用templateRef
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <div ref="index">
    <h1>templateRef模板引用</h1>
    <p>打开控制台查看</p>
    </div>
    //以下是script
    import {ref} from 'vue'

    const index = ref(null)

    function handleClick() {
    console.log(index.value)
    }
    //以下是在控制台的输出结果
    <div ref="index">
    <h1>templateRef模板引用</h1>
    <p>打开控制台查看</p>
    </div>
  4. 实现dom树的修改
1
2
3
4
function changeColor() {
if(index.value.style.color == 'red')index.value.style.color = 'blue'
else index.value.style.color = 'red'
}

父子组件通信

子组件向父组件传输数据

defineEmits

1
2
3
4
5
const emit = defineEmits(['pass-msg-to-father'])
const msg2 = ref(666)
onMounted(()=>{
emit('pass-msg-to-father', msg2)
})

注意:这里emit不可以随便修改,两个都是!
在父组件中子组件的标签内用@pass-msg-to-father = "getMagFromSon"自己定义的一个方法名
<script setup>中添加

1
2
3
4
const msg2 = ref('')
const getMagFromSon = (data) => {
msg2.value = data.value
}

来实现子组件向父组件的通信
当然,这里的data也是一个别名

defineExpose(学长甄选,更加符合直觉,我也是这么觉得滴)

1
2
3
4
defineExpose({
sonMsg,
changeSonMsg
})

这里的sonMsgchangeSonMsg等就是已经在子组件已经定义的变量和函数
然后再在父组件的script里面加上这几句,其实就是你平时怎么用就怎么用就好了

1
2
3
4
5
6
const getMsgFromSon2 = () => {
console.log(son2.value.sonMsg)
son2.value.changeSonMsg()
son2Msg.value = son2.value.sonMsg
console.log(son2.value.sonMsg)
}

父组件向子组件的通信

defineProps

在子组件当中创建一个props对象

1
2
3
4
5
6
const props = defineProps({
msg: {
type: Number,
required: true
}
})

这里的defineProps就相当于给子组件添加了新的属性
然后再在父组件当中的子组件标签当中用v-bind实现双向绑定,然后再再父组件中添加const msg = ref(0)等语句就可以实现父组件给子组件传值。

祖孙组件传值

provide and inject

1
2
3
4
5
6
7
8
import { provide, ref } from 'vue';

const count = ref(0);
const addCount = () => {
count.value++;
}
provide('count', count);
provide('addCount', addCount);

只要在祖组件当中使用过一次provide子组件和孙组件等只需要inject就可以共享使用变量和方法了

1
2
3
4
5
6
7
<script setup>
import sonComponent from './sonComponent.vue';
import { inject } from 'vue';

const count = inject('count');
const addCount = inject('addCount');
</script>
1
2
3
4
5
6
<script setup>
import { inject } from 'vue';

const count = inject('count');
const addCount = inject('addCount');
</script>

然后只要按照平时使用变量和函数的方法正常使用就没有问题了

pinia

是vue专属的最新的状态管理库,允许跨组件或页面来共享数据的状态

添加pinia项目

  • 命令行添加依赖npm install pinia
  • 在入口文件main.js中引入Pinia
    1
    2
    3
    import { createPinia } from 'pinia'
    //别的乱七八糟
    app.use(createPinia())

使用pinia项目

要在专门的store文件夹里面添加不同的文件

1
2
3
4
5
6
7
8
9
10
11
12
13
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
const decrement = () => count.value--

return { count, doubleCount, increment, decrement }
})

注意:

  1. useCounterStore位置是实际引用的时候会使用到的名称
  2. const前要记得加上export,导入之前自然要先导出,没有疑问的
  3. 回调函数的最后记得将需要导出的变量和方法名return出来。

在组件中使用

1
2
3
4
5
6
<script setup>
import {useCounterStore} from '@/stores/counter'

const counterStore = useCounterStore()

</script>

然后正常使用就可以了,比如需要用count直接写counterStore.count想要使用,想要使用increment方法就可以直接写counterStore.increment

实践

在实际使用的时候只要在创建vue项目的时候选择添加pinia就可以了

router

添加router项目

创建一个router文件夹,这个文件夹和组件store等在同一层
然后在router文件夹里面创建一个index.js文件

index.js

index.js的开头记得加上import { createRouter, createWebHistory } from 'vue-router'

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: refAndReactive
},
{
path: '/refAndReactive',
name: 'refAndReactive',
component: refAndReactive
},
{
path: '/computedAndWatch',
name: 'computedAndWatch',
component: () => import('../views/computedAndWatch.vue')
},
]
})

export default router

这是路由的模板,有两种挂载组件的方法,可以在一开始导包import refAndReactive from '../views/refAndReactive.vue'然后在路由当中用component: refAndReactive直接挂载,但是如果每次都一次性导包,效率未免有些低,所以可以用component: () => import('../views/computedAndWatch.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
32
33
34
35
import { RouterLink, RouterView } from 'vue-router'
const List = [
{
url:'/refAndReactive',
name: '响应式和ref与reactive'
},
{
url:'/computedAndWatch',
name: 'computed和watch'
},
{
url:'/tamplateRef',
name: 'templateRef模板引用'
},
{
url:'/lifeCycle',
name: '生命周期函数'
},
{
url: '/defineProps',
name: '父子组件通信'
},
{
url: '/provideAndInject',
name: '祖孙组件通信'
},
{
url: '/pinia',
name: 'pinia'
},
{
url: '/router',
name: 'router'
}
]

vue-router导入RouterLinkRouterView等,然后创建一个数组,存储urlname
然后使用

1
<router-link :to="item.url">{{ item.name }}</router-link> 

来创建链接实现跳转,item.url就是要跳转的url不过是在App.vue的基础上跳转的,item.name就是相对的名字等

1
<router-view></router-view>

这个就是用来展示views的视窗

v-on绑定

1
<button @click="$router.push('/refAndReactive')">点击返回refAndReactive</button>

使用v-on绑定事件$router.push('url')就可以直接跳转到对应的页面

useRouter

1
2
3
4
5
6
7
8
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()

const toPage = (url) => {
router.push(url)
}
</script>
1
<button @click="toPage('/computedAndWatch')">点击返回computedAndWatch</button>

'/computedAndWatch'处也是填入对应的url