【Vue3】(三)vue3中的pinia状态管理、组件通信方式及总结、插槽

目录

一、vue3的pinia

1、什么是pinia?

2、为什么Vue3选择pinia?

3、使用pinia的好处

4、安装pinia

 2、项目配置

3、存储/读取pinia中的数据

4、修改pinia中的数据

 5、storeToRefs(保持store中数据的响应式)

 6、getters

 7、监听store中数据的变化:$subscribe

8、store的组合式写法

 二、【props】传参

三、【自定义事件】传参

四、【mitt】传参

1、认识mitt

2、使用mitt

 五、【v-model】传参(平常基本不写)

六、【$attrs】传参

七、【$refs和$parent】传参

1、概述

2、原理

3、组件使用实例

4、$refs和$parent使用精髓

 八、provide和inject

九、slot插槽

1、默认插槽

2、具名插槽

 3、作用域插槽

十、Vue3组件通信总结


一、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>

九、slot插槽

        插槽的用途就和它的名字一样:有一个缺槽,我们可以插入一些东西。

        插槽 slot 通常用于两个父子组件之间,最常见的应用就是我们使用一些 UI 组件库中的弹窗组件时,弹窗组件的内容是可以让我们自定义的,这就是使用了插槽的原理。

1、默认插槽

        父组件:

<template><div class="father"><h2>父组件</h2><div class="content"><!-- 默认插槽 --><Category title="热门游戏列表"><ul><li v-for="item in games":key="item.id">{{ item.name }}</li></ul></Category></div></div>
</template><script setup lang="ts">
import Category from "./category.vue";
import { ref, reactive } from "vue";let games = reactive([{ id: "adadada01", name: "英雄联盟" },{ id: "adadada02", name: "穿越火线" },{ id: "adadada03", name: "红色警戒" },{ id: "adadada04", name: "王者农药" },
]);let imgUrl = ref("https://z1.ax1x.com/2023/11/19/piNxLo4.jpg");let videoUrl = ref("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
</script>

        子组件:

<template><div class="category"><h2>{{ title }}</h2><!-- 默认插槽 --><slot>默认插槽</slot></div>
</template><script setup lang="ts" name="Category">
defineProps(["title"]);
</script>

2、具名插槽

        父组件:

<template><div class="father"><h2>父组件</h2><div class="content"><!-- 具名插槽 --><Category title="热门游戏列表"><template v-slot:s2><ul><li v-for="item in games":key="item.id">{{ item.name }}</li></ul></template><template v-slot:s1><h3>描述信息</h3></template></Category></div></div>
</template><script setup lang="ts">
import Category from "./category.vue";
import { ref, reactive } from "vue";let games = reactive([{ id: "adadada01", name: "英雄联盟" },{ id: "adadada02", name: "穿越火线" },{ id: "adadada03", name: "红色警戒" },{ id: "adadada04", name: "王者农药" },
]);let imgUrl = ref("https://z1.ax1x.com/2023/11/19/piNxLo4.jpg");let videoUrl = ref("http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4");
</script><style lang="scss" scoped>

        子组件:

<template><div class="category"><h2>{{ title }}</h2><!-- 具名插槽 --><slot name="s1"></slot><slot name="s2"></slot></div>
</template><script setup lang="ts" name="Category">
defineProps(["title"]);
</script>

 3、作用域插槽

         父组件:

<template><div class="father"><h2>父组件</h2><div class="content"><Game><template v-slot="games"><ul><li v-for="g in games.youxi":key="g.id">{{ g.name }}</li></ul></template></Game><Game><template v-slot="games"><ol><li v-for="g in games.youxi":key="g.id">{{ g.name }}</li></ol></template></Game><!-- 简写 --><Game><template #default="{youxi}"><div><h3 v-for="g in youxi":key="g.id">{{ g.name }}</h3></div></template></Game></div></div>
</template><script setup lang="ts">
import Game from "./game.vue";
</script>

        子组件:

<template><div class="game"><h2>游戏列表</h2><!-- 作用域插槽 --><slot :youxi="games"></slot></div>
</template><script setup lang="ts">
import { reactive } from "vue";let games = reactive([{ id: "adadada01", name: "英雄联盟" },{ id: "adadada02", name: "穿越火线" },{ id: "adadada03", name: "红色警戒" },{ id: "adadada04", name: "王者农药" },
]);
</script>

十、Vue3组件通信总结

组件关系传递方式
父传子

1、props

2、v-model

3、$refs

4、默认插槽、具名插槽

子传父

1、props

2、自定义事件

3、v-model

4、$parent

5、作用域插槽

祖传孙、孙传祖

1、$attrs

2、provide、inject

兄弟间、任意组件间

1、mitt

2、pinia

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/83406.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WEB3全栈开发——面试专业技能点P1Node.js / Web3.js / Ethers.js

一、Node.js 事件循环 Node.js 的事件循环&#xff08;Event Loop&#xff09;是其异步编程的核心机制&#xff0c;它使得 Node.js 可以在单线程中实现非阻塞 I/O 操作。 &#x1f501; 简要原理 Node.js 是基于 libuv 实现的&#xff0c;它使用事件循环来处理非阻塞操作。事件…

大数据学习栈记——Neo4j的安装与使用

本文介绍图数据库Neofj的安装与使用&#xff0c;操作系统&#xff1a;Ubuntu24.04&#xff0c;Neofj版本&#xff1a;2025.04.0。 Apt安装 Neofj可以进行官网安装&#xff1a;Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…

web架构4------(nginx常用变量,nginx中英文自动匹配,lnmp网站架构,正向代理,反向代理,负载均衡)

一.前言 本期来介绍nginx最后几个知识点&#xff0c;看着要说的内容很多&#xff0c;其实一点也不多&#xff0c;都是所见即所得的东西。 二.nginx常用变量 2.1 常用变量 $args 请求中的参数&#xff0c;也叫查询参数&#xff0c;如www.123.com/1.php?a1&b2的$args就是…

openeuler系统(CentOs)图形化桌面黑屏/丢失(开启VNC服务冲突)

1. VNC服务开启如下&#xff1a; https://zhuanlan.zhihu.com/p/5049263261 在centos8系统上使用tigervnc-server搭建VNC_centos8 tigervnc-server-CSDN博客 2. 上述操作完成后&#xff0c;连接VNC仍会出现黑屏&#xff0c;则需要编辑/root/.vnc/xstartup&#xff1a; [运维…

MySQL:Prepared Statement 预处理语句

预处理语句&#xff08;Prepared Statements&#xff09;是 MySQL 中一种用于执行 SQL 查询的高效、安全的方法。通过使用预处理语句&#xff0c;可以显著提升查询性能&#xff0c;并防止 SQL 注入攻击。本文将详细介绍 MySQL 预处理语句的概念、使用方法及其优势。 一、预处理…

EPPLUS——CAD c#读写EXCEL的第三方库

EPPLUS(可支持NET35) 在 CAD 的 C# 二次开发中&#xff0c;使用 EPPLUS 库处理 Excel 文件具有以下显著优点&#xff0c;尤其在兼容性、便捷性和性能等方面契合 CAD 项目的需求&#xff1a; 1. 跨.NET 版本兼容性强&#xff0c;适配 CAD 多环境部署 多框架支持&#xff1a;EP…

Linux知识回顾总结----进程状态

本章将会介绍进程的一些概念&#xff1a;冯诺伊曼体系结构、进程是什么&#xff0c;怎么用、怎么表现得、进程空间地址、物理地址、虚拟地址、为什么存在进程空间地址、如何感性得去理解进程空间地址、环境变量是如何使用的。 目录 1. 冯诺伊曼体系结构 1.1 是什么 1.2 结论 …

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…

Android Test3 获取的ANDROID_ID值不同

Android Test3 获取的ANDROID_ID值不同 这篇文章来说明上一篇文章中说到的一个现象&#xff1a;在同一个项目中&#xff0c;创建不同的 app module&#xff0c;运行同一段测试代码&#xff0c;获取到的 ANDROID_ID 的值不同。 我也是第一次认真研究这个现象&#xff0c;这个还…

JSON 和 LabVIEW Data Types 互相转换

使用JSONtext C:\Program Files (x86)\National Instruments\LabVIEW 2021\examples\JDP Science\JSONtext JSONtext LabVIEW Data Types.vi

docker和docker-compose的版本对应关系怎么看?

docker和docker-compose的版本对应关系怎么看&#xff1f;最近在安装这两个工具&#xff0c;像知道他们的版本对应关系&#xff0c;查了不少资料才找到。 虽然 Docker 和 Docker Compose 的版本并不严格绑定&#xff0c;但是在某些情况下&#xff0c;新版本的 Docker Compose …

邮科ODM摄像头:多维度护航高铁安全系统方案解析

‌高铁作为现代交通的重要支柱&#xff0c;其安全稳定运行依赖于高效的监控体系。摄像头系统作为高铁安全管理的“视觉感知中枢”&#xff0c;凭借多场景覆盖、智能分析以及环境适应性设计&#xff0c;在行车安全、设备维护、乘客服务等方面发挥着不可或缺的作用。本文将从技术…

盒模型小全

CSS盒子模型详解 1. 定义 CSS盒子模型是用于描述HTML元素在页面中布局和表现的核心概念之一。在CSS中&#xff0c;所有HTML元素都被视为一个矩形的盒子&#xff0c;这些盒子封装了周围的HTML元素&#xff0c;并允许在其他元素和周围元素边框之间的空间放置内容。 2. 组成部分…

自定义鼠标效果 - 浏览器扩展使用教程

自定义鼠标效果 - 浏览器扩展使用教程 这里写目录标题 自定义鼠标效果 - 浏览器扩展使用教程功能特点安装方法Chrome/Edge浏览器 使用指南1. 更改鼠标光标样式2. 启用鼠标轨迹效果3. 自定义轨迹效果点状/彩虹/渐隐轨迹&#xff1a;表情轨迹&#xff1a; 管理自定义光标支持的文…

基于SpringBoot实现的课程答疑系统设计与实现【源码+文档】

基于SpringBootVue实现的课程答疑系统采用前后端分离架构方式&#xff0c;系统设计了管理员、学生、老师三种角色&#xff0c;系统实现了用户登录与注册、个人中心、学生管理、老师管理、科目类型管理、学生问题管理、老师回答管理、老师信息管理、关注列表管理、交流区、轮播图…

御微半导体面试总结

前一阵子在公司干的难受&#xff0c;所以再合肥这边面试了几家公司&#xff0c;挑一个御微半导体来说一下吧&#xff0c;公司主要是做半导体晶元测量的&#xff0c;具体啥我也不太明白。 公司产品线多&#xff0c;每条产品线配有独立的软件、结构、光学控制等人员开发语言和框…

Android Compose 自定义圆形取色盘

val Dp.toPx: Floatget() {var scale 3f // MyApplication.context.resources.displayMetrics.apply { // scale density // }return value * scale}val colors List(360) { i ->Color.hsv(360f - i, 1f, 1f) // 360到1的所有HSV颜色 }Preview …

vscode 配置 latex

下载插件 安装插件前自行安装 texlive, 按照 https://tug.org/texlive/ 要求安装 找到 settings 打开 json 文件 在 json 文件中添加如下配置 "latex-workshop.latex.tools": [{"name": "latexmk","command": "latexmk",&qu…

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(质检)

船舶质检管理现状&#xff1a;质检环节部分依赖人工检测&#xff0c;质检员依据质量标准对产品进行抽检或全检。人工质检受质检员主观因素影响较大&#xff0c;不同质检员对标准的把握可能存在差异。 一、痛点与需求 1 Arbigtec 人工经验依赖严重&#xff1a; 质检员的检测准确…

jenkins gerrit-trigger插件配置

插件gerrit-trigger下载好之后要在Manage Jenkins -->Gerrit Trigger-->New Server 中新增Gerrit Servers 配置好保存后点击“状态”查看是否正常