【Vue3】(三)vue3中的pinia状态管理、组件通信
目录
一、vue3的pinia
二、【props】传参
三、【自定义事件】传参
四、【mitt】传参
五、【v-model】传参(平常基本不写)
六、【$attrs】传参
七、【$refs和$parent】传参
八、provide和inject
一、vue3的pinia
1、什么是pinia?
pinia 是一个 Vue3 的状态管理库,它的 API 设计和 Vuex 有很大的相似之处,但是它的实现方式和 Vuex 完全不同,它是基于 Vue3 的新特性 Composition API
实现的,所以它的使用方式和 Vuex 也有很大的不同。
Pinia | The intuitive store for Vue.js值得你喜欢的 Vue Storehttps://pinia.vuejs.org/zh/
2、为什么Vue3选择pinia?
在构建大型或中型Vue应用时,组件之间的状态共享和管理是一个不可避免的挑战。Vue.js的官方状态管理库Vuex在过去几年里一直是解决这个问题的主流方案。但是,Vuex的复杂性和对TypeScript支持的限制促使社区寻找更简洁、更灵活的解决方案。这就是Pinia应运而生的背景。
Pinia是Vue.js的一个全新状态管理库库,由同一个团队编写,旨在提供一个更轻量级和用户友好的状态管理体验。它以简单直观的API、完全的TypeScript支持和更好的开发体验而受到欢迎。
3、使用pinia的好处
简化的API、更好的TypeScript集成、开箱即用的DevTools集成、模块化和灵活性、易于测试、轻量级、持久化和插件支持
Pinia提供了一个更加直观和简洁的API,使得状态管理变得更加容易理解和实施。对于开发者来说,这意味着更少的学习曲线和更快的开发速度。由于Pinia自底向上设计了对TypeScript的支持,使用TypeScript的开发者将会享受到无缝的类型推导和更少的类型断言。Pinia与Vue DevTools的集成提供了更好的调试体验,允许开发者轻松追踪和操作状态,从而提高开发效率。Pinia支持将状态分割为不同的模块,使得状态管理在大型应用中更加清晰和可维护。此外,它的灵活性允许你根据需要轻松地添加插件和中间件。由于Pinia的设计,编写单元测试变得更加直观。你可以轻松地模拟actions和测试state的变更。Pinia的代码库比Vuex更小,对于注重应用大小的项目来说,这是一个明显的优势。Pinia支持通过插件来扩展其功能,例如状态持久化,这使得在浏览器刷新或关闭后恢复用户状态变得简单。
综上所述,Pinia为开发Vue应用的状态管理提供了一个现代化、高效和灵活的解决方案。随着Vue 3的推进,Pinia正在成为越来越多Vue开发者的首选状态管理库。
4、安装pinia
1、安装依赖
安装pinia依赖:npm i pinia
2、项目配置
目录:main.ts
// 引入pinia
import { createPinia } from "pinia";
// 创建pinia
const pinia = createPinia()
// 安装pinia
app.use(pinia)
3、存储/读取pinia中的数据
(1)在src下创建store目录
(2)在store目录下创建ts文件(最好能明确地看出属于哪个组件使用)
例如:count.ts
import { defineStore } from "pinia"; // 官方推荐使用Hooks的方式命名 export const useCountStore = defineStore('count',{// 状态/数据(官方要求必须写成一个函数)// state: 真正存储数据的地方(类似于Vue2中的data)state(){return{sum: 6}} })
(3)读取pinia中的值
// 类似Hooks的思想 import { useCountStore } from "@/store/count";const countStore = useCountStore()// 以下两种方式都可以拿到state中的数据 console.log('countStore', countStore.sum) console.log('countStore', countStore.$state.sum)
4、修改pinia中的数据
(1)修改单个数据:直接修改
countStore.sum += 1
(2)修改多个数据:$patch 批量修改
countStore.$patch({sum:888,address:'陕西',city:'西安'
})
(1)和(2)的区别:方法(1)在修改多个数据的时候,会触发多个mutatuons事件,但是方法(2)在修改数据的时候,只会触发一个$patch事件
(3)使用action修改数据:处理复杂数据时使用
- 需要在pinia中定义action函数
export const useCountStore = defineStore('count',{// actions里面放置的是一个一个的方法,用于响应组件中的动作actions:{increment(value){console.log('increment被调用了',value)// 修改数据// this是当前的storeconsole.log('this.sum', this.sum)this.sum += value}},// 状态/数据(官方要求必须写成一个函数)// state: 真正存储数据的地方(类似于Vue2中的data)state(){return{sum: 6,city:'山西',address: '未知'}}
})
- 使用action中定义的修改数据的函数
// 第三种修改数据的方式:使用action属性修改数据countStore.increment(n.value)
5、storeToRefs(保持store中数据的响应式)
- toRefs会将所包裹的数据全部变成ref对象,包括数据和方法,在这里不适用(vue3自带的)
- storeToRefs只会关注store中的数据,不会对方法进行ref包裹(pinia自带的)
import { storeToRefs } from "pinia";
// 解构赋值countStore中的数据
// 1、为了保证数据的响应式,需要使用storeToRefs
// 2、storeToRefs只会关注store中的数据,不会对方法进行ref包裹
const {sum,city,address} = storeToRefs(countStore)
6、getters
概念:当state中的数据,需要经过处理后再使用,可以使用getters配置。
在store中追加getters配置
export const useCountStore = defineStore('count',{// state: 真正存储数据的地方(类似于Vue2中的data)state(){return{sum: 6,city:'山西',address: 'chinese'}},// 配置gettersgetters:{// 写法一:bigSum:(state)=>{return state.sum * 10},// 写法二:upperaddress(){// this可以拿到当前这个store对象console.log('this', this)return this.address.toUpperCase()}}
})
使用getters处理后的数据
<template><div class="count"><h2>当前求和为:{{ sum }},放大10倍后:{{ bigSum }}</h2><h2>当前地址为:{{ address }},转换成大写后:{{ upperaddress }}</h2></div>
</template><script setup lang="ts">
import { ref } from "vue";
// Hooks的思想
import { useCountStore } from "@/store/count";
import { storeToRefs } from "pinia";const countStore = useCountStore();// 解构赋值countStore中的数据
// 1、为了保证数据的响应式,需要使用storeToRefs
// 2、storeToRefs只会关注store中的数据,不会对方法进行ref包裹
const { sum, city, address, bigSum, upperaddress } = storeToRefs(countStore);</script>
7、监听store中数据的变化:$subscribe
- 订阅方法的使用:类似watch属性,可以监听state及其变化
- 两个参数:本次修改的信息;真正的数据
talkStore.$subscribe((mutate, state) => {console.log("$subscribe监听事件的变化", mutate, state);// 实现一个无感刷新数据的方法localStorage.setItem('talkList',JSON.stringify(state.talkList)) // 将数据存到本地存储
});
8、store的组合式写法
export const useTalkStore = defineStore('talk', () => {// 直接定义的数据,相当于stateconst talkList = reactive(JSON.parse(localStorage.getItem('talkList') as string) || [])// 直接定义的方法,就相当于actionasync function getATalk() {// 发请求// {data:{content:title}} => 这个写法的意思是:将返回的结果对象赋值给data,然后再结构data给content,最后再把content赋值给titlelet {data: { content: title },} = await axios.get("https://api.uomg.com/api/rand.qinghua?fromat=json");// 将请求回来的字符串包装成一个对象let obj = { id: nanoid(), title };console.log("obj", obj);talkList.unshift(obj);}// 注意:最后一定要return,要不然没法使用return {talkList,getATalk}
})
二、【props】传参
概述:props是使用频率最高的一种通信方式。作用:父传子、子传父
- 若父传子:属性值是非函数(变量)
- 若子传父:属性值是函数(方法)
父组件:
<template><div class="father"><h3>父组件1</h3><h4>父亲的车:{{ car }}</h4><!-- 父传子【参数】:使用 属性传参 的方式传递参数 --><!-- 父传子【方法】:使用 属性传参 的方式传递参数--><h5>父组件接收到子组件的参数:{{ sonParams }}</h5><Child :dirver="car" :sendSon="getSonParams"/></div>
</template>
<script setup lang="ts" name="father">
import Child from "./Child.vue";
import { ref } from "vue";let car = ref('小米')
let sonParams = ref()// 方法
function getSonParams(params:type) {console.log('params', params)sonParams.value = params
}
</script>
子组件:
<template><div class="child"> <h3>子组件2</h3><h4>儿子的玩具:{{ toy }}</h4><!-- 子组件使用父组件参数 --><h5>子组件拿到父组件的参数:{{ dirver }}</h5><!-- 复杂写法 --><button @click="handleFatherFun">方法1:触发父组件的方法实例</button><br /><button @click="sendSon(toy)">方法2:把子组件的参数传递给父组件</button></div>
</template>
<script setup lang="ts" name="Child">
import { ref } from "vue";let toy = ref('奥特曼') // 子组件接收:声名接收函数:defineProps 数组
let props = defineProps(['dirver','sendSon'])function handleFatherFun(params:type) {// 使用props.拿到父组件传递的参数props.sendSon(toy.value)
}
</script>
图解代码:
三、【自定义事件】传参
在 Vue3 中,自定义事件是一种常用的机制,用于在组件之间传递数据。通过自定义事件,子组件可以向父组件发送数据,从而实现组件间的通信。
父组件:
<template><div><h3>父组件</h3><!-- 给子组件Child绑定事件 --><h4 v-show="toy">子给的玩具:{{ toy }}</h4><!-- 官方推荐:自定义事件使用kabab-case的事件名(a-b) --><Child @send-toy="saveToy"/></div>
</template><script setup lang="ts">
import Child from "./child.vue";
import { ref } from "vue";let toy = ref('')
// 用于处理子组件传递过来的数据
function saveToy(value:any) {console.log('saveToy', value)toy.value = value
}
</script>
子组件:
<template><div class="child"><h3>子组件</h3><h4>玩具:{{ toy }}</h4><button @click="emit('send-toy',toy)"></button></div>
</template><script setup lang="ts">
import { ref } from "vue";let toy = ref('奥特曼')
// 声明事件
let emit = defineEmits(['send-toy'])
</script>
图解代码:
四、【mitt】传参
1、认识mitt
mitt是vue3提供的一个工具,能够实现跨组件通信
下载mitt依赖:npm i mitt
① 创建mitt文件目录
目录地址:src/utils/emitter.ts
② 创建mitt对象
src/utils/emitter.ts
// 引入itt
import mitt from 'mitt'
// 调用mitt,得到emitter,emitter能:绑定事件,触发事件
const emitter = mitt()
// 暴露emitter
export default emitter
③ 项目引入mitt(例如:main.ts)
// 引入mitt
import emitter from "@/utils/emitter";
④ mitt语法介绍
// 绑定事件
emitter.on('tast1',()=>{console.log('tast1被触发了')
})emitter.on('tast2',()=>{console.log('tast2被触发了')
})// 触发事件
setTimeout(() => {emitter.emit('tast1')emitter.emit('tast2')
}, 1000);// 解除事件
setTimeout(() => {// 清除单个事件emitter.off('tast1')// 清除所有事件emitter.all.clear()
}, 3000);
2、使用mitt
组件1:
<template><div class="child1"><h2>子组件1</h2><h3>玩具:{{ toy }}</h3><button @click="emitter.emit('send-toy',toy)">玩具给Childe2玩</button></div>
</template><script setup lang="ts">
import { ref } from "vue";
import emitter from "@/utils/emitter";let toy = ref('奥特曼')
</script>
组件2:
<template><div class="child2"><h2>子组件2</h2><h3>电脑:{{ computer }}</h3><h4>Child1传递的玩具{{ toy }}</h4></div>
</template><script setup lang="ts">
import { ref,onUnmounted } from "vue";
import emitter from "@/utils/emitter";
// 数据
let computer = ref('联想')
let toy = ref()// 给emitter绑定send-toy事件
emitter.on('send-toy',(value:any)=>{console.log('send-toy',value)toy.value = value
})
// 在组件卸载时,解绑emitter
onUnmounted(()=>{emitter.all.clear()
})
</script>
图解代码:
注意:当绑定事件的组件卸载时,最好清除掉emitter绑定的事件,防止内存占用
五、【v-model】传参(平常基本不写)
v-model传参方式一般适用于UI组件库底层的传参使用,所以,这里不做具体介绍,只说明底层原理,平常用的时候还是使用v-model即可
父组件:
<template><div class="father"><h3>父组件</h3><!-- v-model用在html标签上 --><!-- <input type="text" v-model="userName"/> --><!-- v-model的底层原理: --><!-- <input type="text" :value="userName" @input="userName = (<HTMLInputElement>$event.target).value"> --><!-- v-model用在组件标签上 --><!-- <Zhang v-model="userName"/> --><!-- v-model实现组件传参的基本原理: --><Zhang :modelValue="userName" @update:modelValue="userName = $event"/></div>
</template><script setup lang="ts">
import { ref } from "vue";
import Zhang from "./zhang.vue";
// 数据
let userName = ref('张三')
</script>
子组件:
<template><div><h2>子组件</h2><input type="text" :value="modelValue"@input="emits('update:modelValue',(<HTMLInputElement>$event.target).value)"/></div>
</template><script setup lang="ts">
defineProps(['modelValue'])
const emits = defineEmits(['update:modelValue'])
</script>
拓展:
修改v-model的事件名称
六、【$attrs】传参
1、概述:$attrs用于实现当前组件的父组件,向当前组件的子组件通信(祖→孙)
2、具体说明:$attrs是一个对象,包含所有父组件传入的标签属性
注意:$attrs会自动排除props中声明的属性(可以任务声明过的props被子组件自己“消费”了),也就是说:当父(祖-父-子)组件中以props的方式使用了某个属性,在子组件中就不能使用这个属性了
// 如果在父组件中用defineProps接收了a参数,那么a参数就没法继续传递了 defineProps(['a'])
祖组件:
<template><div class="father"><h2>父组件</h2><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>c:{{ c }}</h4><h4>d:{{ d }}</h4><Child :a="a":b="b":c="c":d="d"v-bind="{x:200,y:100}":updateA="updateA" /></div>
</template><script setup lang="ts">
import Child from "./child.vue";
import { ref } from "vue";let a = ref(1);
let b = ref(2);
let c = ref(3);
let d = ref(4);function updateA(value) {a.value += value
}
</script>
父组件:
<template><div class="child"><h2>子组件</h2><GrandChild v-bind="$attrs"/></div>
</template><script setup lang="ts">
import GrandChild from "./grandChild.vue";
// 如果这里在defineProps接收了a参数,那么a参数就没法继续传递了
defineProps(['a'])
</script>
孙组件:
<template><div class="grand-child"><h2>孙组件</h2><h4>a:{{ a }}</h4><h4>b:{{ b }}</h4><h4>c:{{ c }}</h4><h4>d:{{ d }}</h4><button @click="updateA(6)">点我将爷爷组件中的a更新</button></div>
</template><script setup lang="ts">
defineProps(['a','b','c','d','x','y','updateA'])
</script>
七、【$refs和$parent】传参
1、概述
- $refs:用于父→子
- $parent:用于子→父
2、原理
属性 | 说明 |
---|---|
$refs | 值为对象,包含所有ref属性标识的DOM元素或组件实例 |
$parent | 值为对象,当前组件的父组件实例对象 |
3、组件使用实例
父组件:
<template><div class="father"><h2>父组件</h2><h4>房产:{{ house }}</h4><button @click="changeToy">修改Child1的玩具</button><button @click="changeComputer">修改Child2的电脑</button><button @click="getAllChild($refs)">所有孩子的书增加</button><Child1 ref="c1" /><Child2 ref="c2" /></div>
</template><script setup lang="ts">
import { ref } from "vue";
import Child1 from "./child1.vue";
import Child2 from "./child2.vue";// 数据
let house = ref(4);
let c1 = ref();
let c2 = ref();function changeToy() {console.log("c1.value", c1.value);c1.value.toy = "小猪佩奇";
}function changeComputer() {console.log("c2.value", c2.value);c2.value.toy = "华为";
}function getAllChild(refs: { [key:string]: any }) {console.log("所有子组件", refs);for (const key in refs) {console.log("refs", refs[key]);refs[key].book += 3;}
}defineExpose({house})
</script>
子组件1:
<template><div class="child1"><h2>子组件1</h2><h4>玩具:{{ toy }}</h4><h4>书籍:{{ book }}本</h4><button @click="minusHouse($parent)">干掉父组件的一套房产</button></div>
</template><script setup lang="ts">
import { ref } from "vue";// 数据
let toy = ref('奥特曼')
let book = ref(3)function minusHouse(parent:any) {console.log('parent', parent)parent.house -= 1
}// 把数据交给外部
defineExpose({toy,book})
</script>
子组件2:
<template><div class="child2"><h2>子组件2</h2><h4>电脑:{{ computer }}</h4><h4>玩具:{{ book }}</h4></div>
</template><script setup lang="ts">
import { ref } from "vue";// 数据
let computer = ref('联想')let book = ref('奥特曼')// 把数据交给外部
defineExpose({computer,book})
</script>
4、$refs和$parent使用精髓
- 在父组件中,给子组件绑定ref属性,通过$refs可以获取到所有的子组件实例
- 在子组件,只有通过defineExpose宏函数,将想要暴露的数据暴露出去,父组件才能拿到数据
八、provide和inject
能够完全实现不借助于中间组件跨组件通信
父组件:
<template><div class="father"><h2>父组件</h2><h3>银子:{{ money }}元</h3><h3>车子:一辆{{car.brand}},价值:{{car.price}}万元</h3><Child /></div>
</template><script setup lang="ts">
import Child from "./child.vue";
import { ref, reactive, provide } from "vue";let money = ref(100);
let car = reactive({brand: "奔驰",price: 1000,
});
// 孙组件修改祖先组件的money数据
function updateMoney(value: number) {money.value -= value;
}// provide传参:向后代提供数据
provide("moneyContext", { money, updateMoney });
provide("car", car);
</script>
子组件:
<template><div class="grandChild"><h2>孙组件</h2><h3>父组件【银子】:{{ fatherMoney }}</h3><h3>父组件【车子】:一辆{{fatherCar.brand}},价值:{{fatherCar.price}}万元</h3><button @click="updateMoney(6)">修改money</button></div>
</template><script setup lang="ts">
import { inject } from "vue";let { fatherMoney, updateMoney } = inject("moneyContext", {fatherMoney: 0,updateMoney: (value:number) => {},
});
let fatherCar = inject("car", { brand: "未知", price: "未知" });
</script>
相关文章:

【Vue3】(三)vue3中的pinia状态管理、组件通信
目录 一、vue3的pinia 二、【props】传参 三、【自定义事件】传参 四、【mitt】传参 五、【v-model】传参(平常基本不写) 六、【$attrs】传参 七、【$refs和$parent】传参 八、provide和inject 一、vue3的pinia 1、什么是pinia? pinia …...
ingress-nginx 开启 Prometheus 监控 + Grafana 查看指标
环境已经部署了 ingress-nginx(DaemonSet 方式),并且 Prometheus Grafana 也已经运行。但之前 /metrics 端点没有暴露 Nginx 核心指标(如 nginx_ingress_controller_requests_total),经过调整后现在可以正…...
SQL进阶之旅 Day 21:临时表与内存表应用
【SQL进阶之旅 Day 21】临时表与内存表应用 文章简述 在SQL开发过程中,面对复杂查询、数据预处理和性能优化时,临时表和内存表是不可或缺的工具。本文深入讲解了临时表(Temporary Table)和内存表(Memory Table&#x…...

Jenkins自动化部署Maven项目
Jenkins自动化部署Maven项目 一、环境准备(Prerequisites) SpringBoot项目 确保项目根目录有标准Maven结构(pom.xml)且包含Dockerfile: # Dockerfile 示例 FROM openjdk:11-jre-slim VOLUME /tmp ARG JAR_FILE=target/*.jar COPY ${JAR_FILE} app.jar ENTRYPOINT ["j…...

LeetCode 高频 SQL 50 题(基础版)之 【高级字符串函数 / 正则表达式 / 子句】· 上
题目:1667. 修复表中的名字 题解: select user_id, concat(upper(left(name,1)),lower(right(name,length(name)-1))) name from Users order by user_id题目:1527. 患某种疾病的患者 题解: select * from Patients where con…...

Python 中 Django 中间件:原理、方法与实战应用
在 Python 的 Web 开发领域,Django 框架凭借其高效、便捷和功能丰富的特点备受开发者青睐。而 Django 中间件作为 Django 框架的重要组成部分,犹如 Web 应用的 “交通枢纽”,能够在请求与响应的处理流程中,实现对请求和响应的拦截…...

深入浅出玩转物联网时间同步:基于BC260Y的NTP实验与嵌入式仿真教学革命
在万物互联的时代,精准的时间戳是物联网系统的神经节拍器,而NTP协议正是维持这一节律的核心技术。 一、时间同步:物联网世界的隐形基石 在智慧城市、工业4.0等场景中,分散的设备需要毫秒级的时间协同。网络时间协议(N…...
数学建模期末速成 主成分分析的基本步骤
设有 n n n个研究对象, m m m个指标变量 x 1 , x 2 , ⋯ , x m x_1,x_2,\cdots,x_m x1,x2,⋯,xm,第 i i i个对象关于第 j j j个指标取值为 a i j a_{ij} aij,构造数据矩阵 A ( a i j ) n m A\left(\begin{array}{c}a_{ij}\end{array}\right)_{…...
视频音频去掉开头结尾 视频去掉前n秒后n秒 电视剧去掉开头歌曲
视频音频去掉开头结尾 视频去掉前n秒后n秒 视频音频去掉开头结尾 视频去掉前n秒后n秒 电视剧去掉开头歌曲 如果你有一些视频或者音频,你想去掉开头或结尾的几秒钟,那么你可以尝试一下这个工具,首先,我们来看一下,我们以…...

【在线五子棋对战】二、websocket 服务器搭建
文章目录 Ⅰ. WebSocket1、简介2、特点3、原理解析4、报文格式 Ⅱ. WebSocketpp1、认识2、常用接口3、websocketpp库搭建服务器搭建流程主体框架填充回调函数细节 4、编写 makefile 文件5、websocket客户端 Ⅰ. WebSocket 1、简介 WebSocket 是从 HTML5 开始支持的一种网页端…...

C++课设:从零开始打造影院订票系统
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、项目背景与需求分析二、系统架构设计…...

【计算机网络】数据链路层-滑动窗口协议
数据链路层滑动窗口协议 1. 三种协议对比表 特性停止-等待协议GBN协议SR协议窗口大小发送 1,接收 1发送 W (1<W≤2ⁿ-1),接收 1发送 C,接收 R确认方式单个确认累积确认选择性确认重传策略超时重传回退N帧重传选择性重传接收缓冲区…...

在linux系统上,如何安装Elasticsearch?
1.问题描述 当尝试连接时报错,报错内容为: elastic_transport.ConnectionError: Connection error caused by: ConnectionError(Connection error caused by: NewConnectionError(<urllib3.connection.HTTPConnection object at 0x7fd808b179d0>:…...

wpf Behaviors库实现支持多选操作进行后台绑定数据的ListView
<ListView ItemsSource"{Binding SchemeItems}" SelectionMode"Extended" VerticalAlignment"Stretch" HorizontalAlignment"Stretch"><ListView.ContextMenu><ContextMenu><MenuItem Header"删除" …...
【HarmonyOS 5】拍摄美化开发实践介绍以及详细案例
以下是 HarmonyOS 5 拍摄美化功能的简洁介绍,整合核心能力与技术亮点: 一、AI 影像创新 AI 魔法移图 系统级图像分层技术实现人物/物体自由拖拽、缩放与复制,突破传统构图限制。自动分离主体与背景,一键生成错位创意照&…...

《Vuejs设计与实现》第 8 章(挂载与更新)
目录 8.1 挂载子节点与属性 8.2 HTML Attributes 与 DOM Properties 8.3 设置元素属性的正确方式 8.4 处理 class 属性 8.5 卸载操作 8.6 区分 vnode 类型 8.7 事件处理优化 8.8 事件冒泡与更新时机问题 8.9 子节点的更新 8.10 文本节点和注释节点 8.11 片段…...

Ubuntu20.04中 Redis 的安装和配置
Ubuntu20.04 中 Redis 的安装和配置 Ubuntu 安装 MySQL 及其配置 1. Redis 的安装 更新系统包列表并安装 Redis : # 更新包管理工具 sudo apt update# -y:自动确认所有提示(非交互式安装) sudo apt install -y redis-server测…...
从游戏到自动驾驶:互联网时代强化学习如何让机器学会自主决策?
一、为什么机器需要“试错学习”?——强化学习的核心秘密 你有没有玩过《超级马里奥》?当你操控马里奥躲避乌龟、跳过悬崖时,其实就在用一种“试错”的方法学习最优路径。强化学习(Reinforcement Learning, RL)就是让…...

实验四:图像灰度处理
实验四 图像处理实验报告 目录 实验目的实验内容 原理描述Verilog HDL设计源代码Testbench仿真代码及仿真结果XDC文件配置下板测试 实验体会实验照片 实验目的 在实验三的基础上,将图片显示在显示器上,并进行灰度处理。 实验内容 原理描述 1. 图片的…...
asp.net mvc如何简化控制器逻辑
在ASP.NET MVC中,可以通过以下方法简化控制器逻辑: ASP.NET——MVC编程_aspnet mvc-CSDN博客 .NET/ASP.NET MVC Controller 控制器(IController控制器的创建过程) https://cloud.tencent.com/developer/article/1015115 【转载…...

解析“与此站点的连接不安全”警告:成因与应对策略
一、技术本质:SSL/TLS协议的信任链断裂 现代浏览器通过SSL/TLS协议建立加密通信,其核心在于证书颁发机构(CA)构建的信任链。当用户访问网站时,浏览器会验证服务器证书的有效性,包括: 证书链完…...
PyCharm和VS Code哪个更适合初学者
对于 Python 初学者来说,选择 VS Code 还是 PyCharm 取决于你的具体需求和使用场景。以下是两者的详细对比和推荐建议: VS Code 优点: 轻量级:启动速度快,占用资源少,适合在低端设备上运行。高度可定制&am…...

⚡️ Linux Docker 基本命令参数详解
🐳 Linux Docker 基本命令参数详解 📘 1. Docker 简介 Docker 是一个开源的容器化平台,它通过将应用及其依赖打包到一个轻量级、可移植的容器中,从而实现跨平台运行。Docker 采用 C/S 架构,服务端称为 Docker Daemon&a…...

做题笔记(ctfshow)
一。ctfshow web13 文件扫描 存在upload.php.bak <?php header("content-type:text/html;charsetutf-8");$filename $_FILES[file][name];$temp_name $_FILES[file][tmp_name];$size $_FILES[file][size];$error $_FILES[file][error];$arr pathinfo($fi…...
Linux 用户层 和 内核层锁的实现
目录 一、系统调用futex介绍1. 核心机制2. 常见操作3. 工作流程示例(互斥锁)4. 优势5. 注意事项6. 典型应用 二、Linux中用户态的锁和内核的锁不是同一个实现吗?2.1 本质区别2.2 用户态锁如何工作(以 pthread_mutex 为例ÿ…...
Android第十五次面试总结(第三方组件和adb命令)
Android 第三方组件转为系统组件核心流程 这通常是在进行 Android 系统定制(如 ROM 开发、固件制作)时完成,目的是让第三方应用拥有更高的权限和系统身份。主要过程如下: 核心准备:签名!赋予系统身份 …...

Agent短期记忆的几种持久化存储方式
今天给大家讲一下关于Agent长期对话的几种持久化存储方式,之前的文章给大家说过短期记忆和长期记忆,短期记忆基于InMemorySaver做checkpointer(检查点),短期记忆 (线程级持久性) 使代理能够跟踪…...

Git 常见操作
目录 1.git stash 2.合并多个commit 3. git commit -amend (后悔药) 4.版本回退 5.merge和rebase 6.cherry pick 7.分支 8.alias 1.git stash git-stash操作_git stash 怎么增加更改内容-CSDN博客 2.合并多个commit 通过git bash工具交互式操作。 1.查询commit的c…...

从 ClickHouse、Druid、Kylin 到 Doris:网易云音乐 PB 级实时分析平台降本增效
网易云音乐基于 Apache Doris 替换了早期架构中 Kylin、Druid、Clickhouse、Elasticsearch、HBase 等引擎,统一了实时分析架构,并广泛应用于广告实时数仓、日志平台和会员报表分析等典型场景中,带来导入性能提升 3~30 倍ÿ…...
隐函数 因变量确定标准
涉及多元隐函数求导法的逻辑本质:当我们对隐函数关系 F ( x , y , z ) 0 F(x, y, z) 0 F(x,y,z)0 使用偏导法求 ∂ z ∂ x \frac{\partial z}{\partial x} ∂x∂z时,为什么「偏导」能确定谁是因变量?为什么只有当对 z z z 的偏导 F z…...