vue 3 从零开始到掌握

vue3从零开始一篇文章带你学习

升级vue CLI

  1. 使用命令
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve

nvm管理node版本,区分老旧项目

node版本升级,从卸载到使用nvm管理node版本并配置vue环境(学习趟雷版)

创建vue项目

vite创建vue项目传送门

组合式函数

利用vue组合式API来封装和复用有状态逻辑的函数
1.结合官网 使用鼠标跟踪器来实现组合式API,创建mouse.js 文件,将鼠标跟踪功能给提前出来

// mouse.js
import {ref,onMounted,onUnmounted
} from 'vue'// 封装组合式函数
export function useMouse() {// 管理状态const x = ref(0)const y = ref(0)// 组合函数更改状态function updated(event) {x.value = event.pageXy.value = event.pageY}// 在生命周期商注册和卸载鼠标事件onMounted(() => {window.addEventListener('mousemove', updated)})onUnmounted(() => {window.removeEventListener('mousemove', updated)})//  将管理的状态值暴漏出去return {x,y}
}
  1. 在页面中使用
<template><div class="container">坐标: {{ mouse.x }} , {{ mouse.y }}</div>
</template>
<!-- setup 语法糖 -->
<script setup>
import {useMouse
} from '@/utils/mouse'
import { reactive } from 'vue';
const mouse = reactive(useMouse())
// 或者使用此解构出来
// const {
//  x,
//  y
// } = useMouse()
</script>
  1. 将添加和清除DOM事件的逻辑也给抽离出来,并在mouse里面使用
  • event.js 文件

import {onMounted,onUnmounted
} from 'vue'// 封装组合式函数
export function useEventListener(target, event, callback) {// 在生命周期商注册和卸载鼠标事件// 也可以用字符串形式的 CSS 选择器来寻找目标 DOM 元素onMounted(() => {target.addEventListener(event, callback)})onUnmounted(() => {target.removeEventListener(event, callback)})
}
  • mouse.js 引入使用

import {ref,
} from 'vue'
import { useEventListener } from './event'
// 封装组合式函数
export function useMouse() {// 管理状态const x = ref(0)const y = ref(0)// 组合函数更改状态function updated(event) {x.value = event.pageXy.value = event.pageY}useEventListener(window, 'mousemove', updated)//  将管理的状态值暴漏出去return {x,y}
}

vite项目

:vue3兼容vue2语法,vue2的语法可以在vue3项目内使用,vue3不能读取vue语法内的数据

API

setup组合式 API 的入口
  • setup在生命周期执行时间高于beforeCreate, created,在vue2语法内可以直接this调用setup里面的声明变量

  • setup里面的this不是vue实例,而是undefined ,在vue3中弱化了this的使用

  • 直接声明变量:let const var 的值非响应式数据,修改的话,页面也不会变化的

  • 返回值,可以是值,对象,函数,它会在组件被解析前被调用

  • setup 函数的参数
    setup 函数在组件创建created()之前执行,setup函数是一个函数,它也可以有返回值,类似于Vue 2中的data()和methods()的组合‌,接收两个参数:props 和 context

    • props: 是响应式的,当传入显端prop 时他会进行更新,包含父组件传递给子组件的所有数据
    • context: 是一个普通的js对象,上下文对象,暴漏setup中可用的值
选项式 API 和组合式 API

官方文档传送门

组合式 API

组合式 API 通常会与 <script setup> 搭配使用 vue3.0进行响应式数据操作会使用 ref、reactive、toRef、toRefs四个核心 API 函数

  • ref 通常将基本数据类型(string,Number,Boolean…)转为响应式,也可以将引用类型转为响应式,但引用类型内的数据修改就不会及时通知页面发生变化

  • 配置自动添加value在vscode设置
    在这里插入图片描述

    <template><div>{{ mease }}<div @click="bntFrom">点击</div></div>
    </template><script lang="ts" setup>
    import {ref
    } from 'vue'let mease = ref('张三')引用类型let obj = ref({name: "真实的"})function bntFrom(){mease.value = '李四'obj.value.name = '虚假的'console.log('点击了');}
    </script>
    

在这里插入图片描述

  • reactive 只能定义引用类型(obj,arry),相比较ref可以改变深层次的属性响应式 ,ref也可以改变引用对象,但深层的数据还是建议使用reactive

    <template><div><h1>ref定义属性</h1>{{ mease }}<div @click="bntFrom">点击</div><h1>reactive定义</h1><p v-for="item in arry" :key="item.name">{{ item.age }}</p></div>
    </template><script lang="ts" setup>
    import {ref,reactive
    } from 'vue'let mease = ref('张三')let obj = ref({name: "真实的"})let arry = reactive([{name: '王二',age: 10}])function bntFrom(){mease.value = '李四'obj.value.name = '虚假的'arry[0].age = 30console.log('点击了');}
    </script>
    

    在这里插入图片描述

    • 将reactive定义的响应式重新定义一个对象,就会变成一个非响应式对象,可以使用Object.assign(obj,{name: ‘ssf’})
  • toRefs 将 reactive 定义的对象属性给解构赋值转换为响应式引用,保持对象的响应性,一般reactive 创建的对象,直接解构赋值后会失去响应式,所以就需要torefs将其给解构赋值成响应式

  • 如下面代码,将对象解构赋值直接使用,也可以通过对象使用,只要值改变都会发生改变

<script setup lang="ts">
import { reactive,toRefs
} from 'vue'const parms = reactive({name: '掌声',count: 0
})
const {count
} = toRefs(parms)
</script><template><h1>{{ msg }}</h1><div class="card"><p>parms.count: {{ parms.count }}</p><button type="button" @click="count++">count is {{ count }}</button></div>
</template>

在这里插入图片描述

计算属性computed

  1. 基于缓存: 计算属性是基于它所依赖的响应式进行缓存的,只有当响应式依赖发生变化时,计算属性才会重新计算
  2. 声明式:计算属性根据返回值来定义,代码更清晰,更利于理解
  3. 自动更新:当依赖数据发生变化时,计算属性返回的值也会更新
<script setup lang="ts">
import { reactive, computed } from "vue";// 响应式数据
const state = reactive({name: "手机",price: 2000,
});
// 计算属性
const productName = computed(() => {return `优惠 ${state.name}`;
});const formattedPrice = computed(() => {return `${state.price.toFixed(2)}`;
});// 方法
const increasePrice = () => {state.price += 100;
};
</script><template><div><p>商品名称:{{ productName }}</p><p>商品价格:{{ formattedPrice }}</p><button @click="increasePrice">增加价格</button></div>
</template>

在这里插入图片描述
2. 计算属性默认是只读的,如果你想要更改计算属性的值时,你需要使用getter 和 setter 来创建

  • getter 进行计算,将结果缓存起来,当参与计算的响应数据发生变化时,会触发更新机制,再次调用getter来重新计算属性的值
  • setter 函数会接收一个函数值,即要修改的值
<script setup lang="ts">
import { reactive, computed } from "vue";// 响应式数据
const state = reactive({name: "手机",price: 2000,
});
// 计算属性
const productName = computed(() => {return `优惠 ${state.name}`;
});const formattedPrice = computed(() => {return `${state.price.toFixed(2)}`;
});const formattedNamePrice = computed({// 当依赖发生变化时再次调用,返回新的值get(){return state.name + '-' + state.price.toFixed();},// 接收用户传值并进行修改set(newValue){const [name,price] = newValue.split('-')state.name = namestate.price = Number(price)}});// 方法
const increasePrice = () => {state.price += 100;formattedNamePrice.value = '苹果手机-5600'
};
</script><template><div><p>商品名称:{{ productName }}</p><p>商品价格:{{ formattedPrice }}</p><button @click="increasePrice">增加价格</button><p>商品名称、价格:{{ formattedNamePrice }}</p></div>
</template>

在这里插入图片描述

监听属性

  1. 非缓存:监听属性不会缓存其值,每次依赖发生变化时都会执行回调函数,但他有新值和旧值
  2. 灵活:可以监听一个或者多个数据源,当执行复杂逻辑时,可以进行异步操作
监听ref声明值
  1. watch 监听值发生变化,监听ref声明的值
<script setup lang="ts">
import { ref, watch } from "vue";let couent = ref(0);// 监听
watch(couent, (newValue,oldValue) => {console.log(newValue,oldValue,'值发生变化了');});// 方法
const changeCouent = () => {couent.value +=1 
};
</script><template><div><p>商品价格:{{ couent }}</p><button @click="changeCouent">增加价格</button></div>
</template><style scoped></style>

在这里插入图片描述
2. 监听声明的对象类型,当改变单个值时未曾发生变化,需要使用 deep:tree, 深度监听属性,立即监听的话需要使用immediate: true,

  • 单个监听
watch(() => person.value.price,(newValue, oldValue) => {console.log(newValue, oldValue, "价格发生变化了");}
);
  • 多个监听
watch(() => [person.value.name,person.value.price],(newValue, oldValue) => {console.log(newValue, oldValue, "价格发生变化了");}
);
  • 深度监听,立即执行和监听整个对象
<script setup lang="ts">
import { ref, watch } from "vue";let person = ref({name: "lisd",price: 100,});watch(person,(newValue, oldValue) => {console.log(newValue, oldValue, "值发生变化了");},{deep: true,immediate: true,}
);
// 方法
const changeName = () => {person.value.name = '理想';
};// 方法
const changePrice = () => {person.value.price += 1;
};// 方法
const changeObj = () => {person.value = {name: "宝马",price: 345,};
};
</script><template><div><p>品牌:{{ person.name }}</p><p>价格:{{ person.price }}</p><button @click="changeName">增加价格</button><button @click="changePrice">增加价格</button><button @click="changeObj">修改整个品牌</button></div>
</template><style scoped></style>

在这里插入图片描述

监听 reactive
  1. 当改变单个值时也能监听到变化,reactive声明的对象类型会隐士的开启 deep:tree 深度监听属性,还无法关闭,立即监听的话需要使用immediate: true,
  • 单个监听
watch(() => person.price,(newValue, oldValue) => {console.log(newValue, oldValue, "价格发生变化了");}
);
  • 多个监听
watch(() => [person.name,person.price],(newValue, oldValue) => {console.log(newValue, oldValue, "价格发生变化了");}
);
  • 监听整个对象可以不用函数写法,可以直接监听整个对象
<script setup lang="ts">
import { reactive, watch } from "vue";let person = reactive({name: "lisd",price: 100,
});watch(person,(newValue, oldValue) => {console.log(newValue, oldValue, "值发生变化了");},{immediate: true,}
);
// 方法
const changeName = () => {person.name = "理想";
};// 方法
const changePrice = () => {person.price += 1;
};// 方法
const changeObj = () => {Object.assign(person, {name: "宝马",price: 345,});
};
</script><template><div><p>品牌:{{ person.name }}</p><p>价格:{{ person.price }}</p><button @click="changeName">增加价格</button><button @click="changePrice">增加价格</button><button @click="changeObj">修改整个品牌</button></div>
</template><style scoped></style>

在这里插入图片描述
**注意:**监听时,单个字段时,使用函数监听值的变化,监听对象或数组时,可以直接监听,不用写函数来监听,但最好还是写函数来监听,不管是单个值还是对象

watchEffect监听全局
*  无论是哪个字段发生变化,都会触发,而watch需要写具体监听某个值

计算属性和监听属性两者使用场景

  1. 计算属性:当你基于组件的响应数据,生成一个新的可缓存值时,可以是使用计算属性
  2. 监听属性:当你数据发生变化,并且想要根据这个变化,进行一些复杂逻辑和异步操作时,可以使用监听属性

Class 与 Style 绑定 和vue的写法没什么区别

<template>//对象式绑定<div :class="{ active: isActive, 'text-danger'}">内容</div>//数组式绑定<div :class="['conter',{ active: isActive, 'text-danger'}]">内容</div>//使用对象语法动态绑定行内样式<div :class="{ color: red, fontSize: fontSize}">内容</div>//使用数组语法动态绑定行内样式<div :class="[basStyle]">内容</div>
</template><script>
export default {data() {return {isActive: true,fontSize: '12px',basStyle: {width: '20px'height: '20px'background: 'red'}}}
}
</script>

TS中:接口,泛型,自定义类型

vue 官方文档

  1. 接口:interface,用于定义对象是否符合特定的结构,可以用来定义,props,methods 或者 data的类型
  • 对象的结构,属性名称,类型

  • 定义的对象如果不符合结构,亦或者缺少属性,或者类型不匹配,ts就会报错,当然你也可以添加使其变成一个可选属性,比如以下错误
    在这里插入图片描述

  • 类型声明和组合式声明

    	//类型let test: string | number = 1;组合式APIlet refTest = ref<string | number>("");refTest.value = "123";let reactiveTest = reactive<object>({id: 1,name: "张三",});console.log(reactiveTest);
    
  • 符合定义对象结构写法

    // 定义一个接口,用于限制posen对象的具体属性
    <template><div>姓名:{{ posen.name }}-{{ posen.num }}</div>
    </template><script setup lang="ts">
    import { reactive} from "vue";let posen = reactive<PersonInter>({id: 1,name: "张三",
    });
    export interface PersonInter {id: string | number;name: string;num?: number;
    }
    </script><style></style>
    
  1. 自定义类型 type
    自定义类型允许你为现有的类型创建一个名称,可以组合多个类型,亦或者在类型别名内添加额外的属性
  • 基本类型的别名

    type PersonType = {id: string | number;name: string;num?: number;
    };
    let person: PersonType = {id: 1,name: "张三",
    };
    
  • 联合类型

    type Age = string | number;
    type ID = string | number;
    type PersonType = {id: ID;name: string;num?: Age;
    };let refTest = ref<Age>("");
    refTest.value = "123";type combinationType = PersonType & { age: Age };
    let combination: combinationType = {id: 1,name: "张三",age: 23,
    };
    console.log(combination); // {id: 1, name: '张三', age: 23}
    
  1. 泛型
  • 泛型,允许我们编写可重用的代码,适用于多种类型,在定义函数,接口,类的时候
  • 通过泛型,可以处理任意类型的输入,并确保输入和输出类型一致
// 定义泛型
function generic<T>(arg: T): T {return arg;
}// 使用泛型
let age = generic<number>(23);   // 明确指定类型
let strText = generic("hello");    // 类型推断

ref获取在dom中的使用

vue2的ref和vue3的写法不一样,可以直接声明取值,而不需要使用this.$refs.

  1. 组件直接使用,父组件获取子组件的内容
  • 子组件

    <template><div>我是子组件</div>
    </template><script setup lang="ts">
    import { ref, defineExpose } from "vue";
    let re = ref('我是上三');
    let con = ref(3);
    defineExpose({re,con
    });
    </script><style></style>
    
  • 父组件

    
    <script setup lang="ts">
    import ChildComponent from "./aItem.vue";
    import { ref } from "vue";// 明确 refDom 的类型
    interface ChildComponentInstance {re: string;
    }const refDom = ref<ChildComponentInstance | null>(null);
    /*** changeRef函数用于检查和操作一个名为refDom的引用对象* 此函数旨在演示如何在Vue组件中处理和访问refs引用的元素或组件*/const changeRef = () => {// 检查refDom引用是否已初始化 if (refDom.value) {// 如果refDom已初始化,打印其值和特定属性console.log(refDom.value, refDom.value.re); // Proxy(Object) {re: RefImpl, con: RefImpl, __v_skip: true}[[Handler]]: Object[[Target]]: Proxy(Object)[[IsRevoked]]: false '我是上三'} else {// 如果refDom未初始化,打印提示信息console.log('refDom is not initialized');}
    };
    </script><template><ChildComponent ref="refDom" /><el-button @click="changeRef">点击触发</el-button>
    </template><style scoped></style>
  1. 在 v-for中使用ref时,这个时候返回的 ref 就是一个包含绑定所有元素的数组或者对象了
<template><div :ref="setItemRef" v-for="item in posenList" :key="item.id">{{ item.name }}</div>
</template>
<script setup lang="ts">
import { ref,ComponentPublicInstance } from "vue";let itemRefs = ref<HTMLDivElement[]>([]);
// 设置每个元素的 ref
const setItemRef = (el: Element | ComponentPublicInstance | null) => {if (el instanceof HTMLDivElement) {itemsRef.value.push(el); // 只添加有效的 HTMLDivElement}
};
console.log("itemRefs 绑定", itemRefs.value);
</script>

组件

官方文档
动态组件:当多个组件在一个区域来回切换时,可以使用

<!-- currentTab 改变时组件也改变 -->
<component :is="activeComponentName" />
<component :is="tabs[currentTab]"></component>
组件通信
  1. 父组件给子组件传值
  • Props 是一种特别的 atterbutes 你可以用defineProps函数来定义组件期望接收的props,每个props都可以指定类型、默认值、是否必需等属性,其中包含了组件传递的所有 props

  • defineProps 是一个仅 <script setup> 中可用的编译宏命令,所以不需要显示的导入

  • props官方文档

    • 父组件

      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";
      import { reactive } from "vue";let chPerson = reactive({ id: 1, name: "张三" });
      </script><template><ChildComponent :propsVal="chPerson" car="宝马" ref="refDom" />
      </template><style scoped></style>
    • 子组件

      <template><div><p>子组件数据: {{ person.name }}</p><p>父组件传递数据: 姓名:{{ props.propsVal.name }}-汽车:{{ car }}</p></div>
      </template><script setup lang="ts">
      import {reactive,defineProps } from "vue";let person = reactive({name: "q2",
      });const props = defineProps({propsVal: {type: Object,default: () => {return {name: "q2",};},},car: {type: String,default: "奔驰",},
      });// 解构 props
      // const { propsVal, car } = defineProps({
      //   propsVal: {
      //     type: Object,
      //     default: () => ({
      //       name: "q2",
      //     }),
      //   },
      //   car: {
      //     type: String,
      //     default: "奔驰",
      //   },
      // });
      console.log(props);// 父组件传递数据</script><style></style>

    注意:如果没有在 <script setup> 下,那么 props 就必须以 props选项的方式声明,props 对象会作为 setup()函数的第一个参数被传入

    <template><div><p>父组件传递数据: 姓名:{{ propsVal.name }}-汽车:{{ car }}</p></div>
    </template><script>
    export default {name: "childItem",props: {propsVal: {type: Object,default: () => {return {name: "q2",};},},car: {type: String,default: "奔驰",},},setup(props, context) {console.log(props, props.propsVal.name);// console.log(context.emit);// console.log(context.slots);}
    }
    </script><style></style>
  1. 子组件给父组件传值 defineEmits
  • defineEmits方法返回函数并触发,可以使子组件的值传递到父组件中

  • defineEmits 仅可用于<script setup> 中,可以不需要导入直接使用,它返回一个等同于 $emitemit 函数,可以在组件内抛出事件

    • 子组件

      <template><div><el-button @click="changeName">给父组件传递数据</el-button></div>
      </template><script setup lang="ts">
      import { reactive,defineEmits } from "vue";let person = reactive({name: "q2",
      });let emit = defineEmits(["childEvent"]);
      const changeName = () => {emit("childEvent", person);
      };
      </script><style></style>
    • 父组件

      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";interface ChildEventData {id?: number;name?: string;[key: string]: any; // 允许扩展其他字段
      }const handleChildEvent = (val: ChildEventData | {})=> {console.log(val,'子组件传递的值');
      }
      </script><template><ChildComponent @child-event="handleChildEvent" />
      </template><style scoped></style>
  • 如果你没有在使用 <script setup>,你可以从 setup()函数的第二个参数的emit,抛出事件的

    export default {emits: ['enlarge-text'],setup(props, ctx) {ctx.emit('enlarge-text')}
    }
    
  1. $ref + defineExpose(obj)
  • defineExpos可以用来显式暴露组件内部的属性或方法,使得父组件可以通过 ref 访问子组件的内容

  • 由于子组件的内容不会自动暴露给父组件,所以需要defineExpose 选择性地暴露内部内容,从而避免不必要的属性泄漏,同时提供更好的封装性

  • defineExpose 是专为 <script setup> 设计的,不能用于普通的 <script>setup() 函数中

  • 不建议直接暴露整个组件内部状态,应该只暴露需要的内容,从而保持组件封装性

    • 父组件

      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";
      import { ref } from "vue";const refDom = ref();const changeRef = () => {// 检查refDom引用是否已初始化if (refDom.value) {// 如果refDom已初始化,打印其值和特定属性console.log(refDom.value.messe, "父组件hi", refDom.value);const { btnChild } = refDom.value;btnChild('父组件传递哦')} else {// 如果refDom未初始化,打印提示信息console.log("refDom is not initialized");}
      };
      </script><template><ChildComponent ref="refDom" /><el-button @click="changeRef">调用子组件方法</el-button>
      </template><style scoped></style>
    • 子组件

      <template><div></div>
      </template><script setup lang="ts">
      import { ref, reactive, defineExpose } from "vue";let person = reactive({name: "q2",
      });
      let messe = ref("子组件消息");
      const btnChild = (value: string) => {console.log("子组件按钮", value);
      };defineExpose({person,messe,btnChild,text: "我是子组件的text",
      });
      </script><style></style>
  1. 兄弟组件之间通信 mitt
    安装 mitt

npm install --save mitt

  • 你可以封装成一个xx.ts使用

    import mitt from "mitt";
    export default mitt();
  • 组件内使用

    // 兄弟组件1
    <template><div><el-button @click="btnChild">子组件按钮</el-button></div>
    </template><script setup lang="ts">
    import { ref } from "vue";
    import emittler from "@/utils/emitter";let messe = ref("你好啊");
    const btnChild = (value: string) => {console.log("子组件按钮", value);emittler.emit("myEvent", messe.value);
    };
    </script><style></style>
    // 兄弟组件2
    <template><div></div>
    </template><script setup lang="ts">
    import emittler from "@/utils/emitter";
    emittler.on('myEvent', (message) => {console.log(message) // 输出: "你好啊"
    })</script><style></style>
  1. useAttrs + a t t r s 如果需要在子组件接受很多 p r o p s , 但你又没在 p r o p s 中定义,那么其他传递的值就会放在 ‘ attrs 如果需要在子组件接受很多props, 但你又没在 props中定义,那么其他传递的值就会放在 ` attrs如果需要在子组件接受很多props,但你又没在props中定义,那么其他传递的值就会放在atters`中
    在这里插入图片描述
  • 父组件传值

    <script setup lang="ts">
    import ChildComponent from "./childItem.vue";
    import { reactive } from "vue";let chPerson = reactive({ id: 1, name: "张三" });</script><template><ChildComponent :propsVal="chPerson" :test="234" car="宝马" ref="refDom" />
    </template><style scoped></style>
  • 子组件接收,你可以直接 $atters去取值,也可以声明变量去接值

    <template><div><p>父组件传递数据: 姓名:{{ props.propsVal.name }}-汽车:{{ $attrs.car }}</p></div>
    </template><script setup lang="ts">
    import { defineProps,useAttrs } from "vue";const attrs = useAttrs();
    console.log(attrs.car); // 宝马const props = defineProps({propsVal: {type: Object,default: () => {return {name: "q2",};},},
    });
    </script><style></style>
  1. 双向绑定 v-model + defineModel 官方文档
  • 父子组件数据双向绑定 ,v-model 在组件上实现双向绑定

  • 多个v-model 可以接收一个参数,我们可以通过将这个参数当成字符串给defineModel来接收对应的值

  • 如果声明之后,那么如果你不通过字符串来获取,那你将获取不到值

    • 父组件

      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";
      import { ref,reactive } from "vue";
      let titleString = ref("收到反馈及时");
      let chPerson = reactive({ id: 1, name: "张三" });</script><template><p>{{ chPerson }}</p><p>{{ titleString }}</p><ChildComponent v-model="chPerson" v-model:title="titleString" car="宝马" />
      </template><style scoped></style>
    • 子组件

      <template><div><el-button type="primary" @click="brnHa">点击修改</el-button></div>
      </template><script setup lang="ts">
      import { defineModel } from "vue";
      interface Person {name: string;id: number;
      }const chPerson = defineModel<Person>({default: () => {return {name: "宝马",id: 1,};},
      });
      const stringTitle = defineModel('title',{type: String,default: '中NSA公司',
      });
      console.log(chPerson.value,stringTitle.value); // 宝马
      const brnHa = () => {stringTitle.value = '中发的时间分厘卡'chPerson.value = {name: "奔驰",id: 2,};console.log(chPerson);
      };
      </script><style></style>
  • v-model 可以绑定一些内置修饰符,如.trim,.number,.lazy 等,当然我们也可以自己定义一个修饰符, 通过 解构defineModel的返回值,我们可以在子组件访问时给定义修饰符,基于修饰符可以选择性的调节值的读取和写入,我们给 defineModel传入get,set两个选择,根据判断修饰符来实现我们的代码逻辑,这里使用了set

    • 父组件

      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";
      import { ref } from "vue";let character = ref("dhasdh");</script><template><p>{{ character }}</p><ChildComponent  v-model:character.capitalLetters="character" />
      </template><style scoped></style>
    • 子组件

      <template><div><input type="text" v-model="character"></div>
      </template><script setup lang="ts">
      import { defineModel } from "vue";
      const [character,modifiers] = defineModel('character',{set: (val:string) => {// 含有capitalLetters修饰符if(modifiers.capitalLetters){return val.charAt(0).toUpperCase() + val.slice(1)}console.log(val,character,modifiers);return val}
      });</script><style></style>
  1. provide / Inject(提供/注入)
  • 在父组件中定义值和事件 provide(提供数据)

    <script setup lang="ts">
    import ChildComponent from "./childItem.vue";
    import { reactive,provide } from "vue";let chPerson = reactive({ id: 1, name: "张三" });
    provide('sae',chPerson)const refDom =  ()=>{console.log('234')
    }
    provide('abnt', refDom)</script><template><p>{{ chPerson }}</p><ChildComponent :propsVal="chPerson" :test="234" car="宝马" />
    </template><style scoped></style>
  • 子组件或孙子组件 中使用 inject (获取数据)

    <template><div><el-button type="primary" @click="brnHa">点击修改</el-button></div>
    </template><script setup lang="ts">
    import { inject } from "vue";const car = inject("sae", { name: "未知品牌" }); // 提供默认值避免 undefined
    const abnt = inject("abnt", () => {}); // 提供空函数作为默认值console.log(car); // 宝马
    const brnHa = () =>{car.name = "奔驰";abnt()console.log(car);
    }</script><style></style>
  • 注意:如果在其中一个组件修改,那么所有组件都会同步修改后的数据的

  1. pinia vue官方推荐的状态集中管理工具可以看下面的 vuex => pinia

vuex => pinia的使用

官方文档

  1. Pinia 提供了更简洁直接的 API,并提供了组合式风格的 API,最重要的是,在使用 TypeScript 时它提供了更完善的类型推导

    • state (状态)

      • 应用的数据来源,是一个响应式对象
    • getters (计算属性)

      • 类似于技术属性,getters可以根据state的值来派生出新的值
      • getters是有缓存的,只有所依赖的数据发生改变的时候才会重新计算
    • actions (动作)

      • actions中定义事件函数,来改变state中的值
  2. Pinia 的使用 选项式API

    • 先下载 pinia

      npm install pinia
      # 或者
      yarn add pinia
      
    • 在 mina.ts里引用

      import { createApp } from 'vue'import App from './App.vue'import {  createPinia } from 'pinia'
      let store = createPinia()
      const app = createApp(App);
      app
      .use(store)
      .mount('#app')
    • src/store 目录下创建一个 例如 useStore.ts 文件

      import { defineStore } from "pinia";export const useertStore = defineStore("main", {state: () => {return {// all your data herecount: 0,};},getters: {doubleCount: (state) => state.count * 2,},actions: {// all your methods hereincrement() {this.count++;},},
      });
      
    • 在组件里面使用

      
      // 父组件
      <script setup lang="ts">
      import ChildComponent from "./childItem.vue";import { useertStore } from "@/store/useStore"
      const store = useertStore();
      </script><template><p>{{ store.count }}</p><ChildComponent />
      </template><style scoped></style>// 子组件
      <template><div><el-button type="primary" @click="btnAdd">点击添加{{store.count}}</el-button><p>{{ store.doubleCount }}</p></div>
      </template><script setup lang="ts">
      import { useertStore } from "@/store/useStore"
      const store = useertStore();const btnAdd = () => {store.increment();console.log(store.count)
      }
      </script><style></style>
  3. pinia 的使用 组合式API 在组件内用法和选项式API一样

    import { defineStore } from "pinia";
    import { ref, computed } from "vue";
    export const useertStore = defineStore("main", () => {let count = ref(0);let doubleCount = computed(() => count.value * 2);const increment = () => {count.value++;};return { doubleCount, count, increment };
    });

插槽使用slot

  • 默认插槽:用于在子组件模板中定义一个位置,父组件可以在该位置插入自己的内容。

  • 具名插槽:允许你在子组件模板中定义多个插槽位置,每个位置可以有自己的名字。在父组件中,你可以指定内容应该插入到哪个具名插槽。你可以 v-slot:header也可以简写#header

  • 条件插槽:我们可以通过 $slotsv-if来实现

  • 作用域插槽:允许子组件数据传递给父组件,以便父组件可以自定义如何渲染这些数据,你可以这样写 v-slot:name="slotProps"也可以这样简写#name="slotProps"

  • 动态插槽:允许插槽的名称是动态的,以满足更多的业务需求

    • 子组件声明插槽
    <template><div><slot></slot><div class="container"><header><slot name="header"></slot></header><main><slot name="main" maintext="主要内容头部"></slot><div class="list"><div class="item" v-for="item in list"><slot name="item" :item="item">默认信息</slot></div></div></main><footer><template v-if="$slots.footer"><slot name="footer">我是底部</slot></template></footer></div></div>
    </template><script setup lang="ts">
    import { reactive } from 'vue';let list = reactive([1, 2, 3]);
    </script><style></style>
    • 父组件使用
    <script setup lang="ts">
    import ChildComponent from "./childItem.vue";
    </script><template><ChildComponent>发生的<template #header><div>我是具名插槽</div></template><!-- 作用域插槽 --><template #main="props"><div>{{ props.maintext }}</div></template><!-- 动态插槽 --><template #item="items"><div>{{items.item}}</div></template></ChildComponent>
    </template><style scoped></style>

生命周期

  1. Vue2 的生命周期钩子代码更新到 Vue3 官方文档
  • setup 是vue 3 新增的钩子函数,位于组件创建实例之前,适用于进行异步数据获取,状态管理,逻辑代码封装
    • beforeCreate -> 使用 setup(): 实例创建前
    • created -> 使用 setup():实例创建完毕,可以用于访问和修改数据,但还未挂载到dom元素上
  • beforeMount -> onBeforeMount: 挂载前,可以用于修改dom解构
    mounted -> onMounted:挂载完毕,也就是组件渲染你完成,可以进行dom的操作和事件调用和监听
    beforeUpdate -> onBeforeUpdate: 组件将要更新到dom树之前,可以在vue更新dom之前访问dom状态
    updated -> onUpdated: 组件更新到dom树之后,用于执行依赖dom的更新操作
    beforeDestroy -> onBeforeUnmount:销毁前->卸载前, 用于清理资源
    destroyed -> onUnmounted:销毁完毕->卸载完毕,用于清理资源
    errorCaptured -> onErrorCaptured:捕获错误,在错误发生时调用
  1. 组件缓存 <KeepAlive>
  • <KeepAlive>是一个内置组件,它可以在多个人组件动态切换时缓存被移除的组件实例

    <!-- 非活跃的组件将会被缓存! -->
    <KeepAlive><component :is="activeComponent" />
    </KeepAlive>
    
    • 我们可以通过 include来制定是否需要缓存,当名称匹配时组件才会被缓存

      <!-- 以英文逗号分隔的字符串 -->
      <KeepAlive include="a,b"><component :is="view" />
      </KeepAlive><!-- 正则表达式 (需使用 `v-bind`) -->
      <KeepAlive :include="/a|b/"><component :is="view" />
      </KeepAlive><!-- 数组 (需使用 `v-bind`) -->
      <KeepAlive :include="['a', 'b']"><component :is="view" />
      </KeepAlive>
      
    • exclude来排除不缓存的组件,当匹配时不缓存,用法和 include一样

    • max 可以设置缓存组件的最大值,当缓存组件数量达到最大数值时,那么在新组件创建之前,已缓存组件中很久未曾访问的组件就会被销毁掉

  • 生命周期

    • onActivated 在组件挂载时也会调用(组件从缓存中被激活时触发)
    • onDeactivated 在组件卸载时也会调 (组件切换到其他页面时触发)
  1. 父子组件生命周期的先后顺序,vue2 和 vue3 变化不大,只是`beforeCreate ,created 被 setup() 取代
  • 加载渲染依次顺序:

    父组件:beforeCreate => 父组件: created => 父组件:beforeMount(onBeforeMount)=> 子组件:beforeCreate => 子组件:created => 子组件:beforeMount(onBeforeMount) =>子组件:mounted(onMounted) => 父组件:`mounted(onMounted)

  • 更新过程中依次顺序:

    父组件:beforeUpdate(onBeforeUpdate) => 子组件: beforeUpdate(onBeforeUpdate) => 子组件:updated(onUpdated)=> 父组件:updated(onUpdated)

  • 销毁过程中依次顺序:

    父组件:父组件:beforeDestroy(onBeforeUnmount) => 子组件: beforeDestroy(onBeforeUnmount) => 子组件:destroyed(onUnmounted)=> 父组件:destroyed(onUnmounted)

hooks

  1. vue hooks 是一个遵循特点规则的函数,命名以use起始,依托于vue 的组合式API构建,将组件逻辑拆分为独立,可复用的小块
  • useCount.ts 一个简单的计算属性

    import { ref } from "vue";
    export const useCount = () => {const count = ref(0);const increment = () => {count.value++;};return { count, increment };
    };
    <template><div><div> 计算结果:{{ count }}</div><el-button type="primary" @click="increment">添加</el-button></div>
    </template><script setup lang="ts">
    import { useCount } from "@/hooks/useCount";
    const { count, increment } = useCount();
    </script><style></style>
  • 多个嵌套使用

    import { ref } from "vue";
    export const useRide = () => {const rideNum = ref(2);const ride = (num: number) => {return rideNum.value * num;};return { rideNum, ride };
    };
    <template><div><div>计算结果:{{ count }}</div><el-button type="primary" @click="increment">添加</el-button><p>{{ result }}</p></div>
    </template><script setup lang="ts">
    import { useCount } from "@/hooks/useCount";
    import { useRide } from "@/hooks/useRide";
    import { ref, watch } from "vue";
    const { count, increment } = useCount();
    const {  ride } = useRide();
    let result = ref(0)
    watch(() => count.value,(newValue, oldValue) => {console.log(newValue, oldValue);result.value = ride(newValue);}
    );
    </script><style></style>

自定义指令

传送门

其他API

  • shallowRef : 创建一个响应式数据,但只对顶层属性进行响应式处理,只跟踪引用值变化,不关心值内部属性变化
  • shallowReactive:创建一个浅层响应式对象,但只对对象顶层属性进行响应式处理,对象内部属性变化不会做任何响应
  • readonly:创建一个对象,对象的所以属性包括嵌套属性都只能读,不能修改
  • shallowReadonly::和readonly相似,创建一个对象,对象的顶层属性只能读,不能修改,但嵌套属性是可以更改的

其他组件

  • teleport:是一种能够将我们组件的HTML结构一定到指定位置的技术
<teleport to="body">html内容
</teleport>
  • Suspense

安装路由

Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举

  1. 安装路由

    npm install vue-router@4
    # 或者
    yarn add vue-router@4
    
  2. 在src/router/index.ts创建路由实例

    import {createRouter,createWebHistory,type RouteRecordRaw,
    } from "vue-router";
    export const Layout = () => import("@/layout/index.vue");
    // 静态路由
    export const constantRoutes: RouteRecordRaw[] = [{path: "/",component: Layout,meta: { hidden: true },children: [{path: "/",component: () => import("@/views/index.vue"),},{path: "/aItem",component: () => import("@/views/aItem.vue"),},],},
    ];
    const router = createRouter({history: createWebHistory(), routes: constantRoutes,});export default router;
  3. 在main.ts内挂载使用

    import router from './router'const app = createApp(App);
    app
    .use(router)
    .mount('#app')
    
  4. 路由工作模式

  • history模式(HTML5 模式):createWebHistory

    • 优点:不含有#,显得更优雅

    • 缺点:项目上线,需要服务端配合处理路径问题,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误

      const router = createRouter({history: createWebHistory(),routes: constantRoutes,});
      
  • hash模式

    • 优点:不需要服务端进行特殊的处理

    • 缺点:url上会出现一个#,在seo中影响不好

      const router = createRouter({history: createWebHashHistory(), //history: createWebHashHistory(),routes: constantRoutes,
      });
      
  1. RouterLink 和 RouterView
  • RouterLink : 创建导航链接

  • RouterView : 渲染组件,也就是当前路由显示匹配的组件

     <RouterLink to="/">Go to Home</RouterLink><RouterLink to="/aItem">Go About</RouterLink><RouterView />
    
  • 携带参数跳转

    
    <RouterLink to="/aItem?id:3">跳转</RouterLink>
    // 或
    <router-link :to="{ path: '/aItem', params: { id: '12' } }">跳转
    </router-link>
    
  1. 嵌套路由
  • <router-view>嵌套一个 <router-view>,如果渲染到这个嵌套的 router-view 中,我们需要在路由中配置 children
  • children 配置只是另一个路由数组,就像 routes 本身一样。因此,你可以根据自己的需要,不断地嵌套视图
    
    import {createRouter,createWebHashHistory,type RouteRecordRaw,
    } from "vue-router";
    export const Layout = () => import("@/layout/index.vue");
    // 静态路由
    export const constantRoutes: RouteRecordRaw[] = [{path: "/",component: Layout,meta: { hidden: true },children: [{path: "/",component: () => import("@/views/index.vue"),},{path: "/aItem/:id",name: "aItem",component: () => import("@/views/aItem.vue"),},],},
    ];
    const router = createRouter({history: createWebHashHistory(),routes: constantRoutes,
    });export default router;
  1. 命名路由
  • 当创建路由时我们可以给路由一个name
const routes = [{path: '/user/:username',name: 'profile', component: User}
]
  1. 动态路由
  • 通过路径传递参数

    <script setup lang="ts">
    </script><template>页面二<router-link :to="{ name: 'aItem', params: { id: '12' } }">跳转aItem</router-link>
    </template><style scoped></style>
    
  • 需要路由配置支持动态路径参数

    import { createRouter, createWebHistory } from 'vue-router';const routes = [{path: '/aItem/:id',name: 'aItem',component: () => import('@/views/aItem.vue'),},
    ];const router = createRouter({history: createWebHistory(),routes,
    });export default router;
    
  1. 编程时导航
    我们可以通过useRouter来访问路由
  • 导航到不同位置

    • 使用router.push方法,会给 history 栈添加一个新的记录,当用户点击返回,即返回上一页时就会回到之前的URL,此方法相当于点击<router-link :to="...">
      <script setup lang="ts">
      import { useRouter } from 'vue-router'
      const router = useRouter()
      const goAitem = () => {router.push({name: 'aItem',params: {id: '12'}})
      }
      </script><template>页面二<router-link :to="{ name: 'aItem', params: { id: '12' } }">跳转aItem</router-link><el-button type="primary" @click="goAitem">跳转aItem</el-button>
      </template><style scoped></style>
      
  • 替换当前位置

    • router.replace,它不会向history添加新的记录,会直接替换当前条目,亦或者router.push 中添加一个 replace: true

      <script setup lang="ts">
      import { useRouter } from 'vue-router'
      const router = useRouter()
      const goAitem = () => {router.replace({name: 'aItem',params: {id: '12'}})// 亦或者 添加 replace: true,// router.push({//   name: 'aItem',//   replace: true,//   params: {//     id: '12'//   }// })
      }
      </script><template>页面二<router-link :to="{ name: 'aItem', replace: true, params: { id: '12' } }">跳转aItem</router-link><el-button type="primary" @click="goAitem">跳转aItem</el-button>
      </template><style scoped></style>
  1. 路由组件传参
  • 传递参数

    • params:是URL的一部分,通常用于传递静态数据,若使用 to的对象写法时,必须使用 name配置项,在路由里面配置,也就是动态路由
    • query :参数也会附加在URL后面,用于传递敏感数据
    <script setup lang="ts">
    import { useRouter } from 'vue-router'
    const router = useRouter()
    const goAitem = () => {// paramsrouter.push({name: 'aItem',params: {id: '12'}})// queryrouter.push({name: 'aItem',query: {id: '12'}})
    }
    </script><template>页面二<router-link :to="{ name: 'aItem', replace: true, params: { id: '12' } }">跳转aItem</router-link><router-link :to="{ name: 'aItem', replace: true, query: { id: '12' } }">跳转aItem</router-link><el-button type="primary" @click="goAitem">跳转aItem</el-button>
    </template><style scoped></style>
  • 接收参数

    • 通过 useRoute来获取 query 参数,useRoute 返回的是响应式的路由对象,其中 query包含了所以查询参数
      <script setup lang="ts">
      import { useRoute } from 'vue-router';
      const route = useRoute(); 
      console.log(route,' `query`');
      </script>
      
  • 路由 props 配置

    • 当 props 设置为 true 时,route.params 将被设置为组件的 props

      const routes = [{ path: '/aItem/:id',name: 'aItem',component: User, props: true }
      ]
      
    • 函数模式下无论是动态路由参数还是查询参数,params, query 都可以方便地作为 props 传递到组件中

      • 配置
      const routes = [{path: '/aItem',component: SearchUser,props: route => ({ query: route.query.q })}
      ]
      
      • 组件接收
      <script setup>
      defineProps({id: {type: String,default: "奔驰",}
      })
      </script>
      

部署服务器

传送门

vue创建项目使用element-plus

  • 下载引用element-plus
# 选择一个你喜欢的包管理器# NPM
npm install element-plus --save# Yarn
yarn add element-plus# pnpm
pnpm install element-plus
  • 在main.js内引用
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'// 引入 Element-Plus 依赖
import ElementPlus from 'element-plus'
// 引入全局 cSS 样式
import 'element-plus/dist/index.css'createApp(App)
.use(store)
.use(router)
.use(ElementPlus)
.mount('#app')
  • 页面中使用,这里实现element-plus中英文切换 结合 vuex切换中英文
<template><div class='about'><el-select @change="handleClear" v-model="selectValue" placeholder="选择语言" style="width: 240px"><el-option v-for="item in langOptions" :key="item.value" :label="item.label" :value="item.value"><span style="float: left">{{ item.label }}</span><span style="float: right;color: var(--el-text-color-secondary);font-size: 13px;">{{ item.value }}</span></el-option></el-select></div>
</template><script>
import { useStore } from "vuex";
import {reactive, ref 
} from 'vue'
export default {name: 'about',setup() {const selectValue = ref('')const langOptions = reactive([{value: 'en',label: 'English'},{value: 'zhCn',label: '中文'}])const store = useStore()const handleClear = (value) => {store.dispatch('provider/updateLanguage', value)}return {selectValue,langOptions,handleClear}}
};
</script>
<style lang='less' scoped></style>
  • 全局实现中英文
<template><el-config-provider :locale="locale"><el-table mb-1 :data="[]" /><router-view /></el-config-provider>
</template><script>
import {computed,
} from 'vue'
import { useStore } from "vuex";export default {name: 'App',setup() {const store = useStore()const locale = computed(() => store.state.provider.language);// 返回数据return {locale,}}
}
</script>
  • vuex 配置与使用
import { createStore } from 'vuex'
import provider  from './modules/provider'
export default createStore({state: {},mutations: {},actions: {},modules: {provider }
})
  • modules的创建provider文件
// 导入 Element Plus 中英文语言包
import zhCn from "element-plus/es/locale/lang/zh-cn";
import en from "element-plus/es/locale/lang/en";
const user = {namespaced: true,state: {language: zhCn,},mutations: {setLanguage(state, language) {if (language == "en") {state.language = en;} else {state.language = zhCn;}}},actions: {/*** 根据语言标识读取对应的语言包*/updateLanguage({ commit }, language) {commit('setLanguage', language)}},getters: {language(state) {return state.language}}
}
export default user
  • 最终实现效果
    在这里插入图片描述
  • 启动项目报错
  • 预转换错误:未找到预处理器依赖项“sas-embedded”。你安装了吗?尝试npm install-D sass-embedded
    在这里插入图片描述
  • 按照提示安装重新启动就好

按需引入

  • 按需导入,下载两款插件 unplugin-vue-componentsunplugin-auto-import这两款插件

npm install -D unplugin-vue-components unplugin-auto-import

  • 在vite.config.ts 中配置
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
// https://vite.dev/config/
export default defineConfig({plugins: [vue(),AutoImport({resolvers: [ElementPlusResolver()],}),Components({resolvers: [ElementPlusResolver()],}),],
})
  • 重启项目接下来直接引用就行了

组件名称的单个配置

  • vue3 会根据组件文件名称自动推导出name属性,item.vue name 名为item ,但当我们起个文件夹名称,但文件夹内容的文件是index.vue时就无法推导出文件内名称了
    在这里插入图片描述

    • 这在我们调试和定位问题时就不太方便了,当然我们也可以单独添加一个scrit 来去写name名称,但这种方法有点过于繁琐

      ```
      <script lang="ts">export default {name: 'pramas'}
      </script>
      ```
      
    • 社区推出了 unplugin-vue-define-options 来简化该操作

      npm i unplugin-vue-define-options -D

      // vite.config.ts
      import DefineOptions from 'unplugin-vue-define-options/vite'
      import Vue from '@vitejs/plugin-vue'export default defineConfig({plugins: [Vue(), DefineOptions()],
      })
      
    • 页面中使用

      <script setup lang="ts">
      defineOptions({name: "pramas"  
      })
      <script>
      
    • 三方插件在 <script lang="ts" name="pramas"> 上添加name

    <script setup name="pramas">let a = '虑是否'
    </script>
    
    • 下载此插件可以动态修改vue文件名称

    npm i vite-plugin-vue-setup-extend -D

  • 在 vite.config.ts内引用

    import { defineConfig } from 'vite'
    import vue from '@vitejs/plugin-vue'
    import vueDefineNmae from 'vite-plugin-vue-setup-extend'
    export default defineConfig({plugins: [vue(),vueDefineNmae()],
    })
    
  • 代码运行就可以看见我们自定义的name名称了

在这里插入图片描述

遇到问题

1. 淘宝镜像过期,更改淘宝镜像

在这里插入图片描述

  • 在这里插入代码片

1.查看当前npm镜像
npm config get
2.配置新的镜像
npm config set registry https://registry.npmmirror.com
3.再次查看镜像配置情况
npm config get

2.npm run dev` 无法启动项目,显示vite不是内部或外部命令,这是系统启动vite项目,但找不到vite,意味着你未曾安装vite,你可以执行以下命令全局安装,再执行之前命令

npm install -g vite

  • node 和 npm 版本不兼容,官网需要18.3或更高版本的
    在这里插入图片描述

3.vscode打开vite创建项目引入组件报错解决

在这里插入图片描述

  • 在src下创建此文件xxx.d.ts在你的 src 目录中,填入以下内容,帮助 TypeScript 理解 .vue 文件

    	declare module "*.vue" {import { defineComponent } from "vue";const Component: ReturnType<typeof defineComponent>;export default Component;}
    
  • 如果未曾解决,将.vue 改为vue并重新打开项目

  • 如果还未解决可以看看官网的方法
    在这里插入图片描述

4.vue3+vite3+ts使用@alias路径别名爆红报错解决

在这里插入图片描述

  1. vite.config.ts 中配置以下内容
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from "path";
// https://vite.dev/config/
export default defineConfig({plugins: [vue()],resolve: {alias: {"@": path.resolve(__dirname, "./src"),},},
})
  1. 如果显示找不到 path 按照以下命令安装

npm install --save-dev @types/node

  1. tsconfig.app.json 中配置以下内容,然后重启项目
{"compilerOptions": {"baseUrl": ".","paths": {"@/*": ["src/*"],}},"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
}

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

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

相关文章

Mysql专题篇章

一、事务的四大特性&#xff1f; 1、原子性&#xff1a;是指事务包含的所有操作要么全部成功&#xff0c;要么全部失败回滚。 2、一致性&#xff1a;是指一个事务执行之前和执行之后都必须处于一致性状态。比如a与b账户共有100块&#xff0c;两人之间转账之后无论成功还是失败…

CAD插件实现:自动递增编号(前缀、后缀、位数等)——CADc#实现

cad中大量输入一定格式的递增编号时&#xff0c;可用插件实现&#xff0c;效果如下&#xff1a; ①本插件可指定数字位数、起始号码、加前缀、后缀、文字颜色等&#xff08;字体样式和文字所在图层为cad当前图层和当前字体样式&#xff09;。 ②插件采用Jig方式&#xff0c;即…

k8s1.24升级1.28

0、简介 这里只用3台服务器来做一个简单的集群&#xff0c;当前版本是1.24.17目标升级到1.28.17 地址主机名192.168.160.40kuber-master-1192.168.160.41kuber-master-2192.168.160.42kuber-node-1 因为1.24已经更换过了容器运行时&#xff0c;所以之后的升级相对就会简单&am…

4.3-2 jenkins

一.登录jenkins 二.修改密码 三.配置节点 新建节点 编辑节点名称 编辑节点配置 激活节点 将jar下载到指定的路径 再到dos命令下的路径 E:\az\wx 执行 配置节点成功 四. 安全设置中&#xff0c;勾选代理 五.新建项目 编辑项目名称 编辑项目执行的 路径&#xff1a;C:\Users\Ad…

js对象与数组的互转

js对象与数组的互转 文章目录 js对象与数组的互转一、数组转对象1.使用forEach,for in,es6展开运算符,assign2. 使用 Object.fromEntries()3. 将数组转为键值对对象4. 使用 reduce()4. 数组元素为对象时提取属性 二、对象转数组1. 提取键/值/键值对2. 转换为特定结构的数组 三、…

HTTPS在信息传输时使用的混合加密机制,以及共享、公开密钥加密的介绍。

HTTPS在信息传输时使用的混合加密机制&#xff0c;其中包括了共享密钥加密和公开密钥加密&#xff0c;我们先来介绍一下这两种加密方式。 共享密钥加密&#xff08;对称密钥&#xff09; 对称加密是指加密和解密使用的是同一个密钥。就像家里的门锁&#xff0c;钥匙只有一把&…

Oracle 23ai Vector Search 系列之4 VECTOR数据类型和基本操作

文章目录 Oracle 23ai Vector Search 系列之4 VECTOR数据类型和基本操作VECTOR 数据类型基本语法Vector 维度限制和向量大小向量存储格式&#xff08;DENSE vs SPARSE&#xff09;1. DENSE存储2. SPARSE存储3. 内部存储与空间计算 Oracle VECTOR数据类型的声明格式VECTOR基本操…

机器学习——ROC曲线、PR曲线

一、ROC曲线简介 1.1 ROC曲线的构成 1.横轴&#xff08;假正率&#xff0c;FPR&#xff09;&#xff1a; 表示负样本被错误分类为正的比例&#xff08;越小越好&#xff09; 2.纵轴&#xff08;真正率&#xff0c;TPR&#xff0c;即召回率&#xff09;&#xff1a; 表示正样…

IntelliJ IDEA下开发FPGA——FPGA开发体验提升__上

前言 由于Quartus写代码比较费劲&#xff0c;虽然新版已经有了代码补全&#xff0c;但体验上还有所欠缺。于是使用VS Code开发&#xff0c;效果如下所示&#xff0c;代码样式和基本的代码补全已经可以满足开发&#xff0c;其余工作则交由Quartus完成 但VS Code的自带的git功能&…

昂贵的DOM操作:一次DOM导致的性能问题排查记录

公司来了一个前端实习生&#xff0c;踏实&#xff0c;勤快&#xff0c;很快得到老大的认可&#xff0c;分配给她一个需求&#xff0c;大概如下&#xff1a;构建一个公司产品的评论展示页面&#xff0c;页面可以滚动加载新的内容&#xff0c;同时如果已经加载的内容发生变化&…

前端服务配置详解:从入门到实战

前端服务配置详解&#xff1a;从入门到实战 一、环境配置文件&#xff08;.env&#xff09; 1.1 基础结构 在项目根目录创建 .env 文件&#xff1a; # 开发环境 VUE_APP_API_BASE_URL http://localhost:3000/api VUE_APP_VERSION 1.0.0# 生产环境&#xff08;.env.produc…

【学习笔记】计算机网络(七)—— 网络安全

第7章 网络安全 文章目录 第7章 网络安全7.1 网络安全问题概述7.1.1 计算机网络面临的安全性威胁7.1.2 安全的计算机网络7.1.3 数据加密模型 7.2 两类密码体制7.2.1 对称密钥密码体制7.2.2 公钥密码体制 7.3 鉴别7.3.1 报文鉴别7.3.2 实体鉴别 7.4 密钥分配7.4.1 对称密钥的分配…

我用Cursor + DeepSeek + Claude-3.7-Sonnet + DevBox,10分钟开发了一个系统

大家好&#xff0c;我是袁庭新。Cursor最近可谓是火的一塌糊涂&#xff0c;于是我深度体验了一波。我用的环境是Cursor Claude-3.7-Sonnet DevBox&#xff0c;整个过程我一行代码都没有写&#xff0c;10分钟帮我开发了一个系统&#xff0c;且前后端联调一把通过。惊出一身冷汗…

SpringBoot企业级开发之【用户模块-登录】

开发之前我们先看一下接口文档的要求&#xff1a; 开发思路&#xff1a; 开发实操&#xff1a; 因为我们之前开发注册的时候&#xff0c;就有了一些相关的操作&#xff0c;所以在这里我们只需要定义登录的controller即可&#xff1a; //用户登录PostMapping("/login"…

mysql 8.0.27-docker

安装 可以略过本步 https://dev.mysql.com/downloads/https://dev.mysql.com/downloads/ 镜像查询与安装 先查询&#xff1a; docker search mysql 明显会报错 Error response from daemon: Get "https://index.docker.io/v1/search?qmysql&n25": dial tcp…

Pgvector的安装

Pgvector的安装 向量化数据的存储&#xff0c;可以为 PostgreSQL 安装 vector 扩展来存储向量化数据 注意&#xff1a;在安装vector扩展之前&#xff0c;请先安装Postgres数据库 vector 扩展的步骤 1、下载vs_BuildTools 下载地址&#xff1a; https://visualstudio.microso…

Python高阶函数-sorted(深度解析从原理到实战)

一、sorted()函数概述 sorted()是Python内置的高阶函数&#xff0c;用于对可迭代对象进行排序操作。与列表的sort()方法不同&#xff0c;sorted()会返回一个新的已排序列表&#xff0c;而不改变原数据。 基本语法 sorted(iterable, *, keyNone, reverseFalse)二、核心参数详…

ArcGIS Pro/GeoScene Pro AI 助手 2.1

引言 面对ArcGIS Pro/GeoScene Pro复杂的操作界面和脚本开发需求&#xff0c;你是否还在为功能定位、代码调试和效率优化而烦恼&#xff1f;今天&#xff0c;推出自制的Pro AI助手2.0版本&#xff0c;七大核心功能将革新你的GIS工作方式&#xff01;无论是界面操作指引、一键生…

如何将本地更改的README文件同步到自己的GitHub项目仓库

如何将本地更改的 README 文件同步到 GitHub 仓库 在你 git clone 下来的工程目录下&#xff1a; 先使用 robocopy YOUR\SOURCE\CODE\DIR YOUR\GIT\CLONE\DIR /E /XD .git /DCOPY:T 将你的更改Copy到你git下来的工程中&#xff08;上面的命令会自动处理&#xff0c;例如只会C…

PostIn V1.0.8版本发布,IDEA 插件支持一键扫描上报,让接口定义不再繁琐

PostIn是一款国产开源免费的接口管理工具&#xff0c;包含项目管理、接口调试、接口文档设计、接口数据MOCK等模块&#xff0c;支持常见的HTTP协议、websocket协议等&#xff0c;支持免登陆本地接口调试&#xff0c;同时可以对项目进行灵活的成员权限、消息通知管理等。本周Pos…