常用的路由组件了解

基本路由组件基础知识了解

props:实现父子组件(数组、字符串)、子父组件(函数)、兄弟组件之间的通信(数据挂载到父组件上)(只读)
自定义事件:可以实现子父组件通信
全局事件总线$BUS:可以实现任意组件通信(vue2很重要)
pubsub:发布订阅模式实现任意组件通信(vue项目很少用,react项目和微信小程序项目用的较多)
vuex:集中式状态管理容器,实现任意组件通信(缺点:存储数据并非持久化)
ref:父组件获取子组件实例VC,获取子组件响应式数据以及方法
slot:插槽(默认插槽,具名插槽,作用域插槽)实现父子组件通信

1props路由组件

基本常识:1.运行项目:在终端中输入npm run dev
2.自动生成vue文件模板方式:文件-》首选项-》用户代码片段-》输入vue.json-》输入代码:

{

	"Vue Component Template": {
	"prefix": "vue",
	"body": [
		"<template>",
		"  <div>",
		"    <!-- Component HTML goes here -->",
		"  </div>",
		"</template>",
		"",
		"<script>",
		"export default {",
		"  name: '$1',",
		"  data() {",
		"    return {",
		"      // component data",
		"    };",
		"  },",
		"  methods: {",
		"    // component methods",
		"  }",
		"};",
		"</script>",
		"",
		"<style scoped>",
		"/* component CSS styles */",
		"</style>"
	],
	"description": "Basic Vue component structure"
	}


	
}

props:可以实现父子组件通信,props数据还是只读的!!!

1.1父组件传参给子组件

在父组件中写入引入:import Child from './Child.vue';
在div中写入<child></child>
组件中的通信通过属性的形式的传递
1.父组件给子组件传递字符串:
<child info="我是曹操" ></child>
2.通过引入组合式api函数动态传递数据

import {ref} from 'vue';
let money = ref(10000);
<child info="我是曹操" :money="money"></child>

前者数据传递较为死板,后者较为灵活

1.2 子组件接收数据

1.选择式api写法

// export default {
// props:[‘info’,‘money’]
// };

<p>{{ info }}</p>

2.组合式api写法 setup
需要使用到defineprops方法去接收父组件传递过来的数据
// defineprops是vue3提供的方法,不需要引入直接使用
let props = defineProps(['info','money']);//数组或者对象写法都可以,与vue2一样的
返回的是一个代理对象,有两个属性,分别为info和money,用于存储父组件给的数组,因此可以在模板中使用这些数组:

	<p>{{props.info }}</p>
    <p>{{ $props.money }}</p>
    <!-- props可以省略前面的名字 -->
    <p>{{ info }}</p>
    <p>{{ money }}</p>

代理对象数组props不可以修改,如果需要修改,在父组件内修改
Tips:1.<button @click.=“updateProps”>修改props数据中@click="updateProps"是事件监听器,用户点击即可触发updateProps方法
2.

const updateProps = () =>{
  // props.money +=10 ; props:只读的
  console.log(props.info)
}

这是用箭头函数定义的事件处理器,是一个新的函数表达方式,不会绑定this
3.const 是一种声明变量的关键字,用于定义一个常量。且常量不可重新赋值

2自定义事件

2.1原生DOM事件

用户与网页进行交互,鼠标点击等方式
vue2框架当中:这种写法自定义事件,可以通过.native修饰符变为原生DOM事件
vue3框架下面写法其实即为原生DOM事件
vue3:原生的DOM事件不管是放在标签身上、组件标签身上都是原生DOM事件

    <pre @click="handler">
      大江东去浪淘尽,千古风流人物
    </pre>
    <button @click="handler1(1,2,3,$event)">点击我传递多个参数</button>
     <Event1 @click="handler2"></Event1>
// 引入子组件
import Event1 from './Event1.vue';
// 事件回调--1
const handler = (event) => {
  // event即为事件对象
  console.log(event);
}
// 事件回调--2
const handler1 = (a,b,c,$event)=>{
console.log(a,b,c,$event);
}
// 事件回调--3
const handler2 =()=>{
  console.log(123);
}

2.2 自定义事件

用于实现组件之间的通信,子组件给父组件传递参数

<!-- 绑定自定义事件xxx:实现子组件给父组件传递数据 -->
    <Event2 @xxx="handler3" @click="handler4"></Event2>
// 引入子组件
import Event2 from './Event2.vue';
// 事件回调--4
const handler3 = (param1,param2)=>{
  console.log(param1,param2);
  
}
// 事件回调--5
const handler4 = (param1,param2)=>{
  console.log(param1,param2);
}

Event2.vue

<template>
  <div class="child">
    <p>我是子组件2</p>
    <button @click="handler">点击我触发自定义事件</button>
    <button @click="$emit('click','AK47','J20')">点击我触发自定义事件click</button>

  </div>
</template>

<script setup lang="ts">
// vue3组合式api写法没有this setup没有this
// 利用defineEmits方法返回函数触发自定义事件
// defineEmits方法不需要引入直接使用
let $emit = defineEmits(['xxx']);

const handler = () => {
//  第一个参数:事件类型 第二个|第三个|n个即为注入数据
$emit('xxx','东风导弹','航母');
}

</script>

<style scoped>
.child {
  width: 400px;
  height: 200px;
  background-color: pink;
}
</style>

3.全局事件总线

全局事件总线可以实现任意组件通信,在vue2中可以根据vm与vc关系推出全局事件总线,但是在vue3中没有vue构造函数,也没有vue.prototype以及组合式api写法没有this
所以vue3实现全局事件总线私用插件mitt
例子:兄弟组件实现通信
在npm官网查看mitt插件
1.新建bus/index.ts封装bus对象

// 引入mitt插件:mitt是一个方法,方法执行会返回一个bus对象
import mitt from "mitt";
const $bus = mitt();
export default $bus;


2.给兄弟组件2绑定事件
接收兄弟组件1发过来的事件

<script setup lang="ts">
import $bus from '../../bus';
// 组合式API函数
import { onMounted } from 'vue';
// 组件挂载完毕的时候,当前组件绑定一个事件,接收将来兄弟组件传递的数组
onMounted(() => {
  // 第一个参数:即为事件的类型 第二个参数:即为事件的回调
  $bus.on('car', (car) => {
    console.log(car);
  });
})

console.log($bus);

import $bus from ‘…/…/bus’; 向上走两级找到bus文件
3.兄弟组件1触发事件

<template>
  <div class="child2">
<h1>我是子组件2:曹丕</h1>
<button @click="handler">点击我给我的兄弟送一台车</button>
  </div>
</template>

<script setup lang="ts">
// 引入$bus对象
import $bus from '@/bus';
// 点击按钮回调
const handler=()=>{
  $bus.emit('car',{car:"法拉利"});

}

</script>

<style scoped>
.child2{
  width: 300px;
  height: 300px;
  background-color: skyblue;
}

</style>

3.父组件

<template>
  <div class="box">
    <h1>全局事件总线$bus</h1>
    <hr>
    <div class="container">
      <Child1></Child1>
      <Child2></Child2>
    </div>

  </div>
</template>

<script setup lang="ts">
// 引入子组件
import Child1 from "./Child1.vue";
import Child2 from './Child2.vue';

</script>

<style scoped>
.box {
  width: 100vw;
  height: 400px;
  background-color: yellowgreen;
}
.container{
  display: flex;
  justify-content: space-between;
}
</style>

样式:1. display: flex;元素的显示方式设置为Flexbox。Flexbox是一个用于在一维空间(行或列)中排列和对齐子元素的布局模型

2 . justify-content: space-between;这是Flexbox的一个属性,用于定义子元素在主轴(默认为水平方向,即行)上的对齐方式。space-between的值意味着子元素之间的空间是平均分配的,并且第一个子元素将靠近容器的开始边界,最后一个子元素将靠近容器的结束边界。

TIPS:为什么有的import引入带花括号,有的引入没有花括号?
没有花括号的是默认导出,有{}是命名导出

// mathOperations.js  
export default function multiply(a, b) {  
  return a * b;  
}  
  
export function divide(a, b) {  
  return a / b;  
}  
  
// main.js  
import multiply from './mathOperations.js';  
import { divide } from './mathOperations.js';  
  
console.log(multiply(2, 3)); // 输出 6  
console.log(divide(6, 2)); // 输出 3

4.v-model

实现父子组件数据同步,方法一:父亲给子组件数据 props,子组件给父组件数据 自定义事件
子组件
// vue3组合式api写法没有this setup没有this
// 利用defineEmits方法返回函数触发自定义事件
// defineEmits方法不需要引入直接使用

<template>
  <div class="child">
    <h3>钱数{{ modelValue }}</h3>
    <button @click="handler">父子组件数据同步</button>

  </div>
</template>

<script setup lang="ts">
// 接收props
let props = defineProps(['modelValue']);
let $emit = defineEmits(['update:modelValue']);
// 子组件内部按钮点击回调
const handler = ()=>{
  // 触发自定义事件
  $emit('update:modelValue',props.modelValue+1000);

}

</script>

<style scoped>
.child{
  width: 600px;
  height: 300px;
  background-color: skyblue;
}

</style>

父组件

<template>
  <div>
    <h1>v-model :钱数{{ money }}</h1>
    <input type="text" v-model="info">
    <hr>
    <!-- props:父亲给儿子数据 -->
    <Child :modelValue="money" @update:modelValue="handler"></Child>
  </div>
</template>

<script setup lang="ts">
// v-model收集表单数据,实现双向绑定
// v-model也可以实现组件之间的通信,实现父子组件数据同步的业务
// 父亲给子组件数据 props
// 子组件给父组件数据 自定义事件
import { ref } from 'vue';
// 引入子组件
import Child from './Child.vue';
let info = ref('');

// 父组件的数据钱数目
let money = ref(10000);
// 自定义事件的回调
const handler = (num :any) =>{
  // 接收子组件传递过来的数据
money.value=num;
}

</script>

<style scoped></style>

v-model实现父子组件事件同步

<!-- <Child :modelValue="money" @update:modelValue="handler"></Child> -->
    <!-- v-model组件身上使用
         第一:相当于给子组件传递props[modelValue] =10000
         第二:相当于给子组件绑定自定义事件update:modelValue-->
    <Child v-model = "money"></Child>
    <hr>
    <Child1 v-model:pageNo="pageNo" v-model:pageSize="pageSize"></Child1>
  </div>

v-model可以同步多个事件
1.给父亲的参数

// 父组件的数据钱数目
let money = ref(10000);
// 父亲的数据
let pageNo = ref(1);
let pageSize = ref(3);

2.父亲的参数传递给子组件

let props = defineProps(['pageNo', 'pageSize'])
let $emit = defineEmits(['update:pageNo','update:pageSize'])

3.子组件绑定事件调用,修改参数

<button @click="handler">pageNo{{ pageNo }}</button>
    <button @click="$emit('update:pageSize',pageSize+3)">pageSize{{ pageSize }}</button>
const handler = ()=>{
  $emit('update:pageNo',props.pageNo+3)
}

4.父组件显示参数

<h1>v-model :钱数{{ money }}{{ pageNo }}{{ pageSize }}</h1>

在这里插入图片描述

5.useAttrs

可以获取组件身上的属性与事件
案例:二次封装el-button组件,并且把鼠标放在上面可以显示文字
新建子组件HintButton.vue

<el-button type="primary" size="small" :icon="Edit" ></el-button>
<!-- 自定义组件 -->
<HintButton type="primary" size="small" :icon="Edit"></HintButton>

type=“primary” size=“small” :icon="Edit"相当于props传参,子组件接受参数

// 接受父组件传递过来的数据
 defineProps(['type','size','icon'])

也可以使用useAttrs拿到父亲传过来的参数

// 引入useAttrs方法:获取组件标签身上的属性与事件
import { useAttrs } from 'vue';
// 此方法执行会返回一个对象
let $attrs = useAttrs();
console.log($attrs);

界面显示
v-band绑定三个属性 type size icon

<el-button :="$attrs"></el-button>
<!-- <h1 v-bind="{a:1,b:2}">123</h1> -->
<!-- v-bind可以省略为: -->

文字提示 :title=“title”

// 万一用props接收title
let props = defineProps(['title']);
// props和useattrs方法都可以获取父组件传递过来的属性和属性值
// 但是props接受了useattrs方法就获取不到了

界面显示

<div :title="title">

useAttrs可以接受事件 @click=“handler”,原生DOM事件以及自定义事件
在这里插入图片描述

6.ref与$parent

ref:获取真实的DOM节点,获取到子组件的实例vc
$parent:可以在子组件的内部获取到父组件的实例
实例1:在父组件设置一个按钮,父亲的钱数+10,子组件的钱数-10
如何在父组件里获取子组件的信息?

<Son ref="son"></Son>
// 获取子组件实例
let son = ref();

但是拿不到子组件的具体数据,要在子组件暴露方法

// 组件内部数据对外关闭的,别人不能访问
// 如果想让外部访问需要通过defineExpose方法对外暴露
defineExpose(
  { 
  money,
  fly 
  })

拿到子组件的实例,可以用子组件的数据和方法

// 父组件内部按钮点击回调
const handler = () => {
  money.value += 10;
  // 儿子的钱数减去10
  son.value.money -= 10;
  son.value.fly();

}

实例2:在子组件女儿设置一个按钮,点击按钮女儿钱数+10000,父组件钱数-10000
在子组件内如何拿到父组件的方法?

 <button @click="handler($parent)">点击我爸爸给我10000元</button>
const handler = ($parent) => {
  money.value += 10000;
  $parent.money-=10000;

}

同样,父组件的钱数也要对外暴露

// 对外暴露
defineExpose({
  money
});

7.provide与inject

vue3提供provide(提供)与inject(注入),可以实现隔辈组件传递数据
祖先组件给后代组件提供数据,可以使用provide组件提供数据
// 两个参数:第一个参数是提供的数据Key
// 第二个参数:祖先组件提供数据

provide('TOKEN',car);

后代组件(儿子或者孙子都可以使用)
孙子组件Grandchild.vue中

import { inject } from 'vue';
// 注入祖先组件提供数据
// 需要参数:即为祖先提供数据的Key
let car = inject('TOKEN');
const updateCar = ()=>{
  car.value = '自行车';
}

孙子组件可以直接修改爷爷组件传过来的数据,因为他们指向的是同一个对象

8.pinia选择式API

vue2一般用到vuex集中式状态管理容器,去实现任意组件的通信,vue3使用大菠萝pinia类似于vuex,不管是vuex还是pinia,他们存储的数据并非持久化
// vuex:集中式管理状态容器,可以实现任意组件的通信!!!
// 核心概念:state(存储数据)、mutation(唯一可以修改数据的地方)、actions(处理业务,异步等)、getters(计算属性)、modules(模块式开发)

// pinia:集中式管理状态容器,可以实现任意组件的通信!!!
// 核心概念:state、actions、getters
// pinia写法:选择式API、组合式API
如何让两个组件水平排列?
1.给两个组件套一个盒子div

<div class="container">
      <Child></Child>
      <Child1></Child1>

    </div>

2.使用flex工具

.container{
  display: flex;
}

在这里插入图片描述
pinia写法有两种,一种是选择式api写法,一种是组合式api写法
选择式api类似于vuex
新建一个仓库store/index.ts

// 创建大仓库
import { createPinia } from "pinia";
// createPinia方法可以用于创建大仓库
let store = createPinia();
// 对外暴露,安装仓库
export default store;

在入口文件main.ts引入仓库
// 引入仓库

import store from './store'
app.use(store)

pinia大菠萝图标就会亮出来
在这里插入图片描述
创建小仓库store/modules/info.ts

// 定义info小仓库
import { defineStore } from "pinia";

// 第一个参数是小仓库的名字,第二个参数是小仓库配置对象
// defineStore方法执行会返回一个函数,函数作用就是让组件可以获取仓库数据
let useInfoStore = defineStore("info", {
    // 存储数据:state
    state: () => {
        return {
            count: 99,
            arr:[1,2,3,4,5,6,7,8,9,10]
        }
    },
    actions: {
        // 注意:函数没有context上下文对象
        // 没有commit、没有mutation去修改数据
        updateNum(a: number, b: number) {
            this.count++;
        }
    },
    getters: {
        total(){
           let result:any =  this.arr.reduce((prev:number,next:number)=>{
            return prev+next;

           },0);
           return result;
        }

    }

});
// 对外暴露方法
export default useInfoStore;

vvue3的state写法是函数的写法
如何更新仓库数据?

<button @click="updateCount">点击我修改仓库数据</button>

1.方法一:infoStore.count++;
2.方法二: infoStore.$patch({
// count:111
// })用一个新的数据替换原来的数据


const updateCount = ()=>{
  // infoStore.count++;
  // infoStore.$patch({
  //   count:111
  // })
  // 仓库调用自身的方法去修改数据
  infoStore.updateNum(66,77);

}

3.类似vuex的方法: infoStore.updateNum(66,77);infostore没有这个方法,要在仓库action里写这个方法

actions: {
        // 注意:函数没有context上下文对象
        // 没有commit、没有mutation去修改数据
        updateNum(a: number, b: number) {
            this.count++;
        }
    },

选择式api不仅可以调用对象也可以传参

const updateCount = ()=>{
  infoStore.updateNum(66,77);
}

actions: {

    updateNum(a: number, b: number) {
        console.log(updateNum);
        this.count+=a;
    }
},

getters方法可以简化数据,计算数据

state: () => {
        return {
            arr:[1,2,3,4,5,6,7,8,9,10]
        }
    },
getters: {
        total(){
           let result:any =  this.arr.reduce((prev:number,next:number)=>{
            return prev+next;

           },0);
           return result;
        }

    }

js中 reduce方法介绍:https://blog.csdn.net/w17624003437/article/details/125858710
educe()方法为归并类方法,最常用的场景就是,计算数组中的每一项的总和。
reduce() 方法会遍历数组的每一项,他接收两个参数:

第一个参数:每次遍历都会调用的函数,而这个函数有接收四个参数,分别是:前一个值、当前项、项目的索引和数组对象,而这个函数的返回值,回传给下一次遍历时,执行的这个方法的第一个参数。
在这里插入图片描述

9pinia组合式api

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值