vue3学习笔记(二)

路由

  1. 路由是一组key—value的对应关系
  2. 多个路由(route)需要经过路由器(router)的管理

基本操作

首先需要安装路由

npm i vue-router

安装后建立router文件夹,index.ts文件内写配置

//创建路由并且暴露出去

//第一步:引入createRouter
import { createRouter,createWebHistory } from "vue-router";

//导入要呈现的组件
import  Home  from '@/components/home.vue'
import Person from "@/components/person.vue";
//第二步:创建路由器
const router = createRouter({
    history:createWebHistory(), //路由器的工作模式
    routes:[ //一个个路由的路由规则
        {
            path:'/home',
            component: Home
        },
        {
            path:'/person',
            component: Person
        }
    ]
})
//暴露出去
export default router

建立好路由后再main.ts中挂载路由

//导入一个盆
import { createApp } from "vue"
import router from '@/router'
//导入根
import App from "./App.vue"
//引用
const app =createApp(App)
//挂载路由
app.use(router)
app.mount('#app')

在app.vue中使用 router-view来引用页面,使用router-link实现页面跳转

	<router-link to="/home">home</router-link>
    <br>
    <router-link to="/person">person</router-link>
    <br>
    <router-view></router-view>

两个注意点

在vue中
路由组件通常放在pages和views文件夹中,一般组件通常存放在components文件夹中
(通过标签引入的则为一般组件 如:,使用route的为路由组件)
其中通过点击导航,视觉上消失的组件,默认是卸载,需要的时候再去挂载

工作模式

history模式:不带#,url更加美观,项目上线后需要服务端配合处理路径问题,不然刷新会出现404

createWebHistory 

hash模式:兼容性更好,不需要服务器配合处理路径问题,但是不美观,seo优化方面较差

createWebHashHistory

前台项目推荐history,后台项目推荐hash

to的有两种写法

	<router-link :to="{path:'/home'}">home</router-link>
    <br>
    <router-link to="/person">person</router-link>

命名路由

使用name给组件进命名,跳转时可以使用name来跳转

			name:'zhuye',
            path:'/home',
            component: Home
            //------------------
            <router-link :to="{name:'zhuye'}">home</router-link>

嵌套路由

路由配置中引用children

			name:'zhuye',
            path:'/home',
            component: Home,
            children:[{
                path:'detail',
                component: Detail
            }]
            //------------
            <router-view></router-view>//展示

query参数

在路径中传输,如同get请求传参
接收使用useRoute,其数据会在其query属性中

import { useRoute } from 'vue-router';
let route = useRoute()

params传参

使用path:需要提前在地址上占好位置

name:'de',
path:'detail/:id/:name',
component: Home

当访问地址(to)为:detail/哈哈/呵呵
会自动进行匹配
除此之外(to)还有另一种写法,使用name

	<router-link :to="{name:'de',params:{
        id:'1',
        name:'uu'
       }}" ></router-link>

总计:如果使用to的对象写法,则需要配置name,不可用path
如果使用params传递参数时,需要提前占位

路由的props配置

一共由三种写法

children:[
	name:xinwen,
	path:'xiangqing',
	componet:Detail,
	//第一种写法:将路由接受到的所有params参数作为props传给路由组件
	//props:true
	//第二种写法:函数写法,自己决定将什么作为props传给路由组件
	/*props(route){
		returen route.query
	}*/
	//第三种写法:对象写法,自己决定将什么作为props传给路由组件
	/*props:{
		a:'shu1',
		b:'shu2',
		c:'shu3'
	}*/
]

接受是使用defineProps方法

defineProps(['a','b','c'])

replace属性

作用:控制路由跳转时操作浏览器历史记录的模式
浏览器记录的写入模式由两种:分别是push与replace
push:追加历史记录,默认时这种,即进入新页面后可以回退到原来的页面
replace:替换当前记录,即不可回退

在导航标签上使用

<RouterLine replace/>

编程式导航

使用useRouter

const router = useRouter()
router.push({
	name:'xinagq',
	query:{
		id:news.id,
		title:nes.title,
		content:news.content
	}
})

push里放对象,其内容位标签种to中的内容

重定向

在index.ts种新增一个路由,使用redirect实现

{
path:'/',
redirect:'/home'
}

pinia

vue.js的状态管理库,是vuex的轻量级替代

创建搭建

首先项目安装pinia

npm i pinia

其次在mian.ts文件中创建跟使用

//pinia 引用
import { createPinia } from 'pinia'
//创建pinia
const pinia = createPinia()
//使用pinia
app.use(pinia)

存储+读取数据

存储数据:
在项目中建立store文件夹,该文件夹下写相关文件,如 count.ts

import { defineStore } from 'pinia'

export const useCountStore =  defineStore('count',{
	//真正存储数据的地方
    state () {
        return {
            sum:8
        }
    }
})

使用则直接导入使用,如上方定义了useCountStore

import { useCountStore } from '@/store/count';
const countStore = useCountStore()

console.log('cs',countStore) //打印出来是一个reactive的对象
console.log('sum',countStore.sum) //sum是一个ref的用响应式数据

上面之所以不使用value是存在reactive包裹的ref数据,可以不需要用value就能直接打印出来

修改数据(三种方式)

第一种是直接修改

countStore.sum += 1;

第二种是使用patch进行碎片化的修改

	countStore.$patch({
        sum:11
    })

第三种使用actions,其action的配置在对应的ts文件中

import { defineStore } from 'pinia'

export const useCountStore =  defineStore('count',{
    actions: {
        add () {
            this.sum ++;
        }
    },
    //真正存储数据的地方
    state () {
        return {
            sum:8
        }
    }
})

引用这是直接调用方法名即可,如上面所示则countStore.add()为引用(在vue文件中)
其次在ts文件中有this

storeToRefs

使用storeToRefs方法可以定向的接收对应属性,且保证响应式

const countStore = useCountStore()
const {sum} = storeToRefs(countStore)

getters的使用方法

在ts文件中编写,可以选择写构造函数,或普通函数,其中趋同函数可以使用this

	getters:{
        bigsum:state=> state.sum * 10,

        bigSum1 (state) {
            return state.sum * 20
        }
    }

$subscribe (订阅)

可以监控数据的变化,具体使用如下

const countStore = useCountStore()

countStore.$subscribe((mutate,state)=>{
    console.log('mutate是改前的数据',mutate)
    console.log('state是改后的数据',state)
})

组合式写法

在ts文件中可以选择选项式写法与组合式写法,上面的是选项式,下面是组合式

export const useCountStore =  defineStore('count',()=>{
    const sum = ref(8);
    function add () {
        sum.value++;
    }

    return{sum,add};
})

组合式写法使用的箭头函数,无法使用this

组件通讯

pops

分别有子传父,父传子两种情况
父传子:
首先是父类需要在标签上进行一个定义(car)

<child :car="car"/>

其中就是将car传给子类种的car

子类使用defineProps接受数据与方法

defineProps(['car'])

子 传父:
通过方法将数据传输

<child :car="car" :send="get"/>

子类接收并调用send方法

defineProps(['car''send'])

父类则会调用自己的get方法,实现数据的接收

自定义事件

父类自定义事件,子类接收事件并且是使用事件 ,事件触发后父类调用回调函数

下面是自定义了haha事件,回调函数是xyz

<child @haha="xyz"/>

子类使用前需要使用defineEmits接收事件

const emit = defineEmits(['haha'])

定义好后,使用emit方法带上对应参数则会使用这个事件(后面可以到数据传回父类回调函数)

<button @click="emit('haha',6666)"></button>

注:自定义事件的命名推荐使用my-event 或 myevent,不推荐小驼峰

mit

mitt与pubsub订阅消息与发布消息功能类似,它可以实现在任意组件间的通信

安装&引用mitt

npm i mitt

安装好后在src文件夹下建立utills文件夹,在utills文件夹下建立emitter.ts

//引入mitt
import mitt from 'mitt'

//调用mitt,得到emitter,emitter可以绑定事件和触发事件
const emitter = mitt()

//暴露emitter
export default emitter

随后在main.ts中引用emitter

import emitter from '@/utils/emitter'

emitter四种用法

四种方法分别是:
on():用来绑定事件,接收两个参数,第一个参数是事件名,第二个参数是事件触发时的回调函数
emit():用来触发事件,参数为事件名
off():解绑事件 ,参数为事件名
all(): 具有clear属性,直接调用clear可以解绑全部事件

简单的数据传输方式

定义一个父组件,两个子组件
两个子组件分别都引入emitter

import emitter from '@/utils/emitter';

在子组件1中定义数据,以及设置事件触发的按钮

<button @click="emitter.emit('getBook',book)">将book信息发送给子组件2</button>
let book = ref('理想国')

在第二个组件中定义事件

//给emitter绑定getBook事件,传入回调函数,回调函数接收一个参数
emitter.on('getBook',(val:any)=>{
	book.value= val.value
})
let book = ref('');

v-model

v-model在vue3中有许多的语法

单个绑定

父组件进行值的定义与传输

<!--定义value值,并且使用v-model传输给子组件-->
<child  v-model="value"/>

子组件使用defineProps进行接收
其中因为父组件传输值时使用的是v-model=‘数据名’
所有接收的时候只能接收到modelValue

//下面只写相应的关键代码

// 接收
  defineProps([
    'modelValue', // 接收父组件使用 v-model 传进来的值,必须用 modelValue 这个名字来接收
  ]);
  const emit = defineEmits(['update:modelValue']); // 必须用 update:modelValue 
  function handle() {
    // 参数1:通知父组件修改值的方法名
    // 参数2:要修改的值
    emit('update:modelValue', '子改变值');
  }

其中值改变后是一个双向改变,子类父类的值会同步

多个绑定

与当个不同的是我们会给对应的值定义名称
父组件

<Child v-model:msg1="val1" v-model:msg2="val2" />

子组件

// 接收
  defineProps({
    msg1: String,
    msg2: String,
  });
  const emit = defineEmits(['update:msg1', 'update:msg2']);
  function changeMsg1() {
    emit('update:msg1', '蔬菜1');
  }
  function changeMsg2() {
    emit('update:msg2', '蔬菜2');
  }

v-model修饰符

v-model中内置了好几种修饰符如:trim、.number 和 .lazy,不过大多是时候需要自己定制修饰符
下面我将定义修饰符good,将内容改成very good

 <Child v-model.good="val" />

//接收修饰符与数据
  const props = defineProps(['modelValue', 'modelModifiers']);
  const emit = defineEmits(['update:modelValue']);
  //进行修饰符判断
  onMounted(() => {
    // 判断有没有good修饰符,有的话就执行 下面得方法 方法
    if (props.modelModifiers.good) {
      emit('update:modelValue', 'very good');
    }
  });

$attrs

在数据传输中attrs存放的是未被pops接收的数据

祖传孙

在多层组件嵌套下,如 父 子 孙 三层,当子要与孙进行通信时就可以用attrs解决
首先解释一下什么是未被接收的数据

<child  a='10' b='20' c='30'/>

//只接收a
definePops(['a'])

只接收a,那么a数据会存在于pops中,b c数据会在attrs

对此我们可以通过这样由子传给孙

<grandchild  $attrs/>

上面的代码类似于

<grandchild  b='20' c='30'/>

所以在孙模块中可以接收到b c

defineProps(['b','c'])

孙传祖

现在父模块内定义方法,并且传输到孙模块即可实现
默认定义了 a b c

<Child :a="a" :b="b" :c="c" :changeA="changeA"/>
function changeA(value:number){
    a.value += value
}

<grandchild  :="$attrs"/>

defineProps(['a','b','c','changeA'])

要改变数值只需要调用changeA()即可

$refs与$parent

$refs用于父传子,$parent用于子传父

$refs

ref在普通DOM标签上的作用是获取DOM节点,在组件上的作用是获取组件的示例对象

<Child ref="a"/>
let  a = ref()

//子组件通过defineExpose将数据交出去
defineExpose({name,age})

//改变值的方法
function changeA(){
	a.value.name= '卡卡西'
}

父组件调用changeA的时候可以改变子组件暴露出来的name值

$parent

$parent的用法与$refs用法类似,$parent获取的是父组件的实例对象

//暴露数据
defineExpose({money})

<!--调用方法传入 $parent--->
<button @click="minusMoney($parent)">减少父组件存款</button>
//定义方法操作数据
function minusMoney(parent:any){	
	parent.money -= 1
}

provide与inject

provide与inject 前者提供数据,后者注入接收是使用

祖传孙

import {reactive,provide} from 'vue'

//提供数据
provide('person',person)

import { inject } from 'vue';

//注入数据
let person= inject('person')

inject方法第一个参数是接收名,第二个参数可以定义默认值,当没有数据提供时也不会报错

孙传祖

//方法
function chuangeA(value:number){
  person.age = value
}
//提供方法
provide('chuangeA',chuangeA)

let discount = inject('chuangeA',(value:number)=>{})
<button @click="chuangeA(7)">改名年龄</button>

slot插槽

插槽分为三种:默认插槽,具名插槽,作用域插槽。

默认插槽

<slot>这是默认内容</slot>

普通的标签类似于div

具名插槽

<Child>
        <!-- v-slot后面是冒号,冒号后面对应插槽名称 -->
        <template v-slot:title>
          <h2>热门游戏列表</h2>
        </template>
        <!-- steup语法糖,直接使用#代替v-slot: -->
        <template #content>
        <span>魔兽世界</span>
        </template>
   </Child>

 <!-- 插槽1 -->
 <slot name="title">这是默认内容</slot>
  <!-- 插槽2 -->
  <slot name="content">这是默认内容</slot>

通过具体名字,父类的定义会插入到子类的对位置

作用域插槽

用于子传父,其数据存在子组件,但是数据结构由父组件决定

<slot :games="games"></slot>

类似于pops的方式传输数据

<template v-slot="params">
		<ul>
    		<li v-for="g in params.games" :key="g.id">{{ g.name }}</li>
        </ul>
    </template>

父组件使用v-slot接收,也可使用语法糖#写法

此外该还有个在接收的时候进行了解构赋值

 <!-- 在接收的时候进行了解构赋值-->
  <template #default="{games}">
       <h5 v-for="g in games" :key="g.id">{{ g.name }}</h5>
  </template>
  • 14
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值