Vue2基础

数据驱动视图(vue 会监听数据变化,自动渲染 dom,是单向的数据绑定)

双向数据绑定(在网页中 form 负责采集数据,ajax 负责提交数据,不需要操作 dom 来获取表单最新的值,最新的数据会自动更新到 js 数据中)

MVVM 是 vue 实现数据驱动视图和双向数据绑定的核心原理,MVVM 指的是 ModelViewViewModel,它把每个 html 分成这三个部分

Model 是数据源,View 是所渲染的 Dom,ViewModel 是 Vue 的实例,将 Model 和 View 连接起来

Vue 基础使用

注: 不借助脚手架

1、导入 vue.js 的脚本

2、在页面中声明一个将要被 vue 控制的 Dom

3、创建 vm 实例对象(vue 实例对象)

<div id="app" >{{usernane}}</div>
<scrit>
Const vm = new Vue{
//el是固定写法,表示要控制的区域,接收一个选择器
el:'#app',
data:{
usernae:'zhangsan'
}
}
</script>

vue.cli

vue.js 开发的标准工具,简化了 webpack 创建工程化 vue 项目的功能

安装npm install -g@ vue/cli

创建项目 vue create 项目名

src 目录构成

assets 文件夹:存放项目中用到的静态资源文件,例如:css 样式表、图片资源

components 文件夹:程序员封装的、可复用的组件,都要放到 components 目录下

main.js 是项目的入口文件。整个项目的运行,要先执行 main.js

App.vue 是项目的根组件

运行流程

整个 vue 项目是通过 main.js 将 app.vue 渲染到 index.html 页面

vue 实例下的$mount('#app')方法和 el 属性功能一样

Vue 指令

指令是 vue 的模板语法,用来渲染页面结构

内容渲染指令

v-text 将覆盖元素内部原有的内容 <p v-text="username"></p>

v-html 渲染为带标签的的 html 元素

const username = '<p>{{ username }}</p>'
<div v-html={{username}}"></div>

双大括号插值表达式,将数据渲染到大括号的位置,内部支持简单的 js 运算和方法

属性绑定指令

v-bind 为元素属性动态绑定值,可以简写为:

<input type="text" v-bind:placeholder="tips" >
<input type="text" :placeholder="tips" >

事件绑定指令

v-on 绑定事件监听,可以简写为@

<button @click = "add">+1</button>
<scrit>
Const vm = new Vue{
//el 是固定写法,表示要控制的区域,接收一个选择器
el:'#app',
//要渲染的数据
data:{
usernae:'zhangsan',
count:0
}
//定义处理事件的函数
method:{
//()内可以传参
add(){
this.count++;
}
}
}
</script>

vue 提供了内置变量$event,就是原生的 dom 对象 e,放置传参导致覆盖掉 e,所以传参之后可以使用

@click=show(参数,$event)

vue 提供了阻止默认跳转的事件修饰符 @click.prevent="xxx"

.prevent 阻止默认行为

.stop 阻止冒泡、

vue 提供了键盘事件的按键修饰符 @keyup.enter="xxx"

enter 代表回车键

esc 代表 esc 键

双向绑定指令

v-model 会实时渲染数据,是双向的,只能和表单元素进行绑定,v-bind 是单向的

对数据进行处理的专用修饰符

将输入的数据转换为数字 v-model.number='xxx'

去除首尾空格 v-model.trim='xxx'

在修改的过程中不双向更新,只有修改完毕才进行更新 v-model.lazy='xxx'

条件渲染指令

v-if 会动态的移除和创建元素,如果元素默认是不显示的且用户在离开页面都不会触发显示这个元素用 v-if

v-show 只是隐藏元素,设置 display 属性,如果要频繁切换元素,用 v-show 性能更好

绝大多数不考虑性能问题,直接使用 v-if

v-else 必须配合 v-if 使用,除此之外还有 v-else-if

列表渲染指令

v-for 基于一个数组渲染一个列表结构,需要使用 item in list 的形式(item 是被循环的一项,list 是数组)

data:{
list:[
{id:1,name:'zs'},
{id:2,name:'ls'}
]
}
<li v-for="item in list" :key="item.id" >{{item.name}}</li>

v-for 支持可选第二个参数 v-for="(item,index) in list"即取出数组的索引

在使用 v-for,需要绑定:key="item.id",尽量将 id 作为 key 的值(key 的值只能是字符串或数字且不能重复)

vue 中列表循环需加:key="唯一标识" ,唯一标识一般是 item 里面 id ,因为 vue 组件高度复用增加 Key 可以标识组件的唯一性 ,key 的作用主要是为了高效的更新虚拟 DOM

过滤器 侦听器 计算属性

过滤器

过滤器常用于文本格式化,用于插值表达式和 v-bind 属性绑定

过滤器要被添加在 js 表达式的尾部,通过管道符|进行调用

过滤器函数要被定义在 filters 节点下,和 datamethods 同级

过滤器中的函数一定要有一个返回值 过滤器中的形参永远是管道符前面的值

私有过滤器和全局过滤器

filters 节点下的过滤器是私有过滤器,如果需要在多个 vue 实例中共享过滤器,可以通过 Vue.filter()定义全局过滤器

// 私有过滤器
filters:{
//(使用时没有参数,即{{msg|filterA}})
filterA(value){
return '¥'+value
}
}
// 全局过滤器
Vue.filter('cap', function (str) {
str.charAt(0).toUpperCase()
})

格式化时间可以使用第三方包 day.js

连续调用过滤器 item.time|xxx|xxx|xxx

过滤器本身是 js 函数,可以传参,但注意第一个参数永远是管道符前的数据

侦听器

watch 侦听器可以监视数据变化并做出对应操作,本质是一个函数,要监视哪个数据就把数据名作为方法名,新值在前,旧值在后

data: { username: '' },
watch: {
usename(newVal, oldVal){
console.log(newVal, oldVal)
}
}

方法格式侦听器和对象格式侦听器

方法格式侦听器不会在进入页面的时候立刻触发,且如果侦听的是对象也无法侦听对象的变化

watch:{
usename(newVal, oldVal){
console.log(newVal, oldVal)
}
}

对象格式侦听器可设置 immediate 属性为 true 即可自动触发一次,设置 deeptrue 可监听对象的变化,handler 是监听数据变化

watch: {
usename: {
handler(newVal, oldVal){
console.log(newVal, oldVal)
},
immediate: true
deep: true
}
}

如果需要侦听对象的单个属性变化则使用对象.属性,需要单引号包裹

watch: {
'info.usename': {
handler(newVal, oldVal){
console.log(newVal, oldVal)
},
immediate: true
deep: true
}
}

计算属性

通过一系列的运算得到一个属性值,通过 computed 节点声明,实现了代码的复用,且依赖的数据变化了,会重新求值

computed: {
// 计算属性的 getter
reversedMessage() {
// 这个函数只会在 `message` 发生变化时才会重新执行
return this.message.split('').reverse().join('');
}
}

组件

组件是对 UI 结构的复用,vue 组件是以.vue 为后缀的,每个组件由 template+script+style 三部分组成,template 内只能有一个根元素 div,style 内想要使用 less 语法需要在 style 内加 lang='less'

//script的默认写法,默认导出
<script>
export default{
// data 是数据源但不能指向对象
// data必须是一个函数
// 注:Vue 实例中的 data 是对象,Vue 组件中的 data 必须是函数返回值,vue 实例一般情况不会复用,所以 vue 实例 data 可以是一个对象。但是设计组件的目的就是为了复用,所以组件内的 data 不能是对象。
data(){
//通过return将数据返回出去
return{
username:'admin'
}
}
}
</script>

使用组件的三个步骤

1、使用 import 导入组件

2、在 script 中使用 components 节点注册组件

3、以标签的形式在 template 中使用

全局组件

在 maim.js 内通过 import 导入组件

Vue.component('xxx',import 的组件)

组件的 Props

props 是组件的自定义属性,合理使用 props 可以提高组件的复用性,props 属性和 data 平级

porps 属性是只读的,尽量避免直接修改 props 的值,如果需要修改就把 props 重新赋值放到 data 内

props 可以使用 default 设置默认值

props:{
init:{
default: 0
}
}

props 传入的默认是字符串,type 可指定 props 的属性,可以是数字、字符串或布尔值 require 设置是否必传

props:{
init:{
default: 0,
type: Number
require: true,
}
}

组件中的样式冲突

默认情况下,.vue 的组件样式是全局生效的

解决方法:在 style 标签加 scope 属性

如果父组件中要改子组件的样式,需要在样式前加

/deep/::v-deep多用于修改第三方库组件(vant、element-ui)样式的需求

组件的生命周期

组件从创建运行销毁的过程是组件的生命周期

组件创建阶段

beforeCreat 创建之前

created 已被创建(用来发起 ajax 请求)

beforeMount 被渲染之前

mounted 已被渲染(可以操作 dom)

组件运行阶段

beforeUpdate 运行之前

updated 已被运行(拿到最新的数据)

组件销毁阶段

beforeDestory 销毁之前

destoryed 已被销毁

组件之间的数据共享

1、父向子组件数据传递,使用自定义属性

// 父组件
<template>
<div class="left">
<p>我是父组件</p>
<MySon :msg = "message"></MySon>
</div>
</template>
<script>
import MySon from '@/components/MySon'
export default {
name: "Father",
components: { MySon },
data(){
return {
message: '我是父组件给子组件的消息'
}
}
}
</script>
// 子组件Son
<template>
<div>
<p>父组件向count子组件传的值:{{msg}}</p>
</div>
</template>
<script>
export default {
name: "Son",
props:{
msg:{
type:String
}
},
}
</script>

2、子组件向父组件传数据,使用自定义事件 this.$emit('change',this,count)

// 父组件
<template>
<div>
<p>我是父组件 子组件传的值是{{num}} </p>
<MySon @change = "changeNumber">+1</MySon>
</div>
</template>
<script>
import MySon from '@/components/MySon'
export default {
name: "Father",
components: { MySon },
data(){
return {
num: ''// 用于接收子组件的值
}
},
methods:{
changeNumber(num){
this.num = num
}
}
}
</script>
// 子组件
<template>
<div>
<p>我是子组件</p>
<button @click = "send">传值</button>
</div>
</template>
<script>
export default {
name: "Son",
data(){
return {
number:5
}
},
methods:{
send(){
this.$emit('change',this.number)
}
}
}
</scrip>

3、兄弟组件之间的数据共享是 EventBus

创建一个 eventBus.js 模块,并向外共享实例 vue

import Vue from 'vue'
export default new Vue()

在发送方使用 methods 调用 bus.$emit 方法

<button @click = "share">点击把数据发送给right.vue</button>
<script>
import bus from '../assets/eventBus';
export default {
name: "Left",
data(){
return {
brother:'兄弟组件的信息'
}
},
methods:{
share() {
bus.$emit('share',this.brother)
}
}
}
</script>

在接受方的 created 生命周期中调用 bus.$on 方法

<p>收到的数据:{{str}}</p>
<script>
import bus from '../assets/eventBus';
export default {
name: "Right",
data(){
return {
str:''
}
},
created() {
bus.$on('share',(val) => {
this.str = val;
})
},
}

ref 引用

在不依赖 jquery 和操作 API 的情况下,获取 dom 元素

在每个 vue 组件的实例上,都包含一个$ref 对象

给要操作的 dom 加 ref 属性,在方法内使用 this.$refs.属性名 可以获取 dom

<template>
<div ref="ref1">我是div标签</div>
</template>
<script>
export default {
mounted() {
this.$refs.ref1.style.color = 'red'
}
}
</script>

此方法同样可用以用在子组件上

如果某个组件是动态生成的,不能直接使用 ref 获取到 dom,要等 dom 被渲染完成才能获取到 dom,使用 this.$nextTick()函数,相当于一个延时函数

动态组件

动态切换组件的显示和隐藏

vue 提供了<component is='Left'>标签使用组件,is的属性是需要渲染的组件

要渲染的组件可以通过键值对放在 data 中,通过 comName 声明 comName:'Left',之后通过动态属性绑定到 is 上

在 component 外可以使用<keep-alive>标签将组件进行缓存,防止被销毁

<keep-alive>
<component :is = "comName"></component>
</keep-alive>

keep-alive 有自己的生命周期

当组件被激活时,会自动触发组件的 activated 生命周期函数。

当组件被隐藏时,会自动触发组件的 deactivated 生命周期函数。

keep-alive 可以指定缓存的组件,通过 include 指定,如果不指定就缓存标签下的所有组件,也可以指定排除性 exclude,但不能和 include 同时使用

<keep-alive inclued='Left'>
<component :is = "comName"></component>
</keep-alive>

inclued 缓存的值可以在组件内部可以通过 name 声明组件名称,主要配合 keep-alive 缓存使用

插槽

插槽 Slot 可以将不确定的、希望用户指定的定义为插槽

具名插槽

声明一个插槽区,vue 官方规定每个 slot 插槽都要有一个 name 名称,如果没有 name 属性则 name 默认为 default,带有 name 的插槽为具名插槽

注意:需要指定插槽插入的位置要借助 template 标签或 component 标签,使用 v-slot 绑定插槽的名字

v-slot:可简写为#

子组件中可以有默认后备内容,当父组件有内容,会覆盖子组件的默认内容

//在子组 Left 中
<slot name='default'>默认内容</slot>
//在父组件中
<Left>
<template #default >
<p>123</p>
</template>
</Left>

最后 left 会渲染出 123

作用域插槽

在封装组件时为预留的插槽可以提供其他属性,通过#插槽名='scope'接收 这种插槽叫作用域插槽

通过 slot-scope.其他属性可以访问这个属性

<template slot="default" slot-scope="slotProps">
{{ slotProps.msg }}
</template>
//在子组 Left 中
<slot name='default' msg='hello' :user = 'userInfo'></slot>
//在父组件中
<Left>
<template #default = "{msg , user}" > // scope = "{msg , user}"
<p>123</p>
<p>{{user}}</p>
<p>{{msg}}</p>
</template>
</Left>

自定义指令

私有自定义指令

在组件中通过 directives 节点声明自定义指令,如 v-color 指令,指令内的 bind 函数会自动触发

v-color='red',通过传值传的方式传给 color,在 bind 内通过 binding 接收

directive:{
color:{
bind(el , binding) {
el.style.color=bindind.value
}
}
}

bind 只会在第一次被绑定的时候自动触发所以需要 updeate 函数进行更新

directive:{
color:{
bind(el,binding){
el.style.color=bindind.value
},
update(el,binding){
el.style.color=bindind.value
}
}
}

如果 bind 和 update 函数的内容相同,可以简写

directive:{
color(el,binding){
el.style.color=bindind.value
}
}

全局自定义指令

在 main.js 使用 Vue.directive()声明,和过滤器 filter 一样,在实际开发中多用全局的自定义过滤器和指令

Vue.directive('color', function (el, binding) {
el.style.color = bindind.value
})

防抖指令

// 1.设置 v-debounce 自定义指令
Vue.directive('debounce', {
bind: (el, binding) => {
let debounceTime = binding.value; // 防抖时间
if (!debounceTime) { // 用户若不设置防抖时间,则默认 2s
debounceTime = 2000;
}
let cbFun;
el.addEventListener('click', event => {
if (!cbFun) { // 第一次执行
cbFun = setTimeout(() => {
cbFun = null;
}, debounceTime);
} else {
// 阻止事件冒泡并且阻止该元素上同事件类型的监听器被触发
event && event.stopImmediatePropagation();
}
}, true);
},
});
// 2.为 button 标签设置 v-debounce 自定义指令
<button @click = "sayHello" v-debounce='1000'>提交</button>

图片懒加载指令

const LazyLoad = {
// install 方法
install(Vue, options) {
// 代替图片的 loading 图
let defaultSrc = options.default
Vue.directive('lazy', {
bind(el, binding) {
LazyLoad.init(el, binding.value, defaultSrc)
},
inserted(el) {
// 兼容处理
if ('IntersectionObserver' in window) {
LazyLoad.observe(el)
} else {
LazyLoad.listenerScroll(el)
}
}
})
},
// 初始化
init(el, val, def) {
// data-src 储存真实 src
el.setAttribute('data-src', val)
// 设置 src 为 loading 图
el.setAttribute('src', def)
},
// 利用 IntersectionObserver 监听 el
observe(el) {
let io = new IntersectionObserver(entries => {
let realSrc = el.dataset.src
if (entries[0].isIntersecting) {
if (realSrc) {
el.src = realSrc
el.removeAttribute('data-src')
}
}
})
io.observe(el)
},
// 监听 scroll 事件
listenerScroll(el) {
let handler = LazyLoad.throttle(LazyLoad.load, 300)
LazyLoad.load(el)
window.addEventListener('scroll', () => {
handler(el)
})
},
// 加载真实图片
load(el) {
let windowHeight = document.documentElement.clientHeight
let elTop = el.getBoundingClientRect().top
let elBtm = el.getBoundingClientRect().bottom
let realSrc = el.dataset.src
if (elTop - windowHeight < 0 && elBtm > 0) {
if (realSrc) {
el.src = realSrc
el.removeAttribute('data-src')
}
}
},
// 节流
throttle(fn, delay) {
let timer
let prevTime
return function (...args) {
let currTime = Date.now()
let context = this
if (!prevTime) prevTime = currTime
clearTimeout(timer)
if (currTime - prevTime > delay) {
prevTime = currTime
fn.apply(context, args)
clearTimeout(timer)
return
}
timer = setTimeout(function () {
prevTime = Date.now()
timer = null
fn.apply(context, args)
}, delay)
}
}
}
export default LazyLoad

一键 Copy 指令

import { Message } from 'ant-design-vue'
const vCopy = {
// bind 钩子函数,第一次绑定时调用,可以在这里做初始化设置
// el: 作用的 dom 对象
// value: 传给指令的值,也就是我们要 copy 的值
bind(el, { value }) {
el.$value = value // 用一个全局属性来存传进来的值,因为这个值在别的钩子函数里还会用到
el.handler = () => {
if (!el.$value) {
// 值为空的时候,给出提示
Message.warning('无复制内容')
return
}
// 动态创建 textarea 标签
const textarea = document.createElement('textarea')
// 将该 textarea 设为 readonly 防止 iOS 下自动唤起键盘,同时将 textarea 移出可视区域
textarea.readOnly = 'readonly'
textarea.style.position = 'absolute'
textarea.style.left = '-9999px'
// 将要 copy 的值赋给 textarea 标签的 value 属性
textarea.value = el.$value
// 将 textarea 插入到 body 中
document.body.appendChild(textarea)
// 选中值并复制
textarea.select()
// textarea.setSelectionRange(0, textarea.value.length);
const result = document.execCommand('Copy')
if (result) {
Message.success('复制成功')
}
document.body.removeChild(textarea)
}
// 绑定点击事件,就是所谓的一键 copy 啦
el.addEventListener('click', el.handler)
},
// 当传进来的值更新的时候触发
componentUpdated(el, { value }) {
el.$value = value
},
// 指令与元素解绑的时候,移除事件绑定
unbind(el) {
el.removeEventListener('click', el.handler)
}
}
export default vCopy

关于自定义指令还有很多应用场景,如:拖拽指令、页面水印、权限校验等等应用场景

路由

router就是地址和组件的对应关系

hash 地址本质是锚链接,通过 a 标签指向 ID 访问,但会产生浏览历史即浏览器的前进后退可用,在 url 内#号和后面的地址为 hash 地址

onhashchange 事件可以监听路由发生变化

vue-route 是 vue.js 官方给出的路由解决方案

基本用法

安装 vue-route npm i vue-route -S

在 src 下创建一个 router 文件夹 并创建 index.js 内进行路由配置

import Vue from 'vue'
import VueRoute from 'vue-router'
//导入需要的组件
import Home form '@/components/Home.Vue'
//调用 Vue.use(),把 VueRouter 安装为 Vue 插件
Vue.use(VueRouter)
//创建路由实例,并进行配置
const router = new VueRouter(
//定义 hash 地址和组件之间的对应关系
routes:[
//路由规则
{path:'/home',component: Home}
]
)
//导出 router
export default router

在 Vue 中要使用路由需要在 main.js 内进行挂载

//在导入模块的时候,如果是给定的是文件夹,则默认导入文件夹的 index.js
//在 new Vue 中挂载 router
import router from @/router/index.js
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')

使用 router-view 组件,本质是一个占位符

<router-view></router-view>

使用 router-link to='xxx'代替 a 标签

<router-link to="/home"></router-link>

路由重定向

使用 redirect 属性重定向路由

const router = new VueRouter(
routes:[
//路由重定向
{path:'/',redirect:'/home'}
//路由规则
{path:'/home',component:Home}
]
)

嵌套路由

即子组件中的路由,在子组件中使用 router-link 添加路由并使用 router-view 占位符

<router-link to="/home/tab1"></router-link>

在 router 的 index.js 内对应的组件添加 children 属性

const router = new VueRouter(
routes:[
//路由重定向
{path:'/',redirect:'/home'}
//路由规则
{
path:'/home',
component:Home,
children: [
{path:'tab1',component:Tab1}
]
}
]
)

如果子组件中有一个 path 为空字符串,则它是默认子路由

动态路由匹配

在路由规则内可以使用英文的:来定义路由的参数

{path:'/home/:id',component:'Home'}

在对应组件中使用 this.$route.params.id 可以访问到对应参数

通过 this.$route.query 可以访问带?传的查询参数

通过 this.$route 的 path 可以访问路径,通过 fullpath 可以访问完整路径

或在路由中开启 props 传参

{path:'/home/:id',component:'Home',props:true}

就可以在 props 内拿到 id

常见用法

vue 常用的编程式导航this.$router

this.$router.path('hash 地址')

跳转到对应 hash 地址,并增加一条历史记录

this.$router.replace('hash 地址')

跳转到对应 hash 地址,不增加历史记录

this.$router.go(数值 n)

数值为正代表前进,为负代表后退,一般只会前进和后退一层

前进 this.$router.forward()

后退 this.$router.back()

vue 路由传参

项目中很多情况下都需要进行路由之间的传值,可以使用 sessionstorage/localstorage/cookie 进行离线缓存存储也可以,用 vuex 也可以,如果只是简单的传值可以使用 vue 自带的路由传参方法

参考官方文档:https://router.vuejs.org/zh/guide/essentials/passing-props.html

想要实现点击当前页的某个按钮或链接跳转到另外一个页面去,并将某个参数带过去

页面刷新数据不会丢失

<div @click = "insurance(123)">我要传参</div>
methods:{
insurance(id) {
//直接调用$router.push 实现携带参数的跳转
this.$router.push({
path: `/particulars/${id}`,
})
}
}
// 需要对应路由配置如下:可以看出需要在 path 中添加/:id 来对应 $router.push 中 path 携带的参数。
{
path: '/particulars/:id',
name: 'particulars',
component: particulars
}

目标页面获取参数方法:this.$route.params.id

页面刷新数据会丢失

类似 post 请求 通过路由属性中的 name 来确定匹配的路由,通过 params 来传递参数。

methods:{
insurance(id) {
this.$router.push({
name: 'particulars',
params: {
id: id
}
})
}

对应路由配置正常配置即可

目标页面获取参数方法:this.$route.params.id

query 传参

参数会显示在 url 后面以?拼接的形式,类似 get 请求

使用 path 来匹配路由,然后通过 query 来传递参数

methods:{
insurance(id) {
this.$router.push({
path: '/particulars',
query: {
id: id
}
})
}

对应路由配置正常配置即可

目标页面获取参数方法:'this.$route.query.id'

导航守卫

导航守卫可以控制路由的访问权限

每次发路由跳转时,通过 router.beforeEach(fn)调用一个回调函数

const router = new VueRouter(
routes:[
//路由重定向
{path:'/',redirect:'/home'}
//路由规则
{path:'/home',component:Home,
children: [
{path:'tab1',component:Tab1}
]
}
]
)
router.beforeEach(function(to,from,next){
//to 是要去的路由
//from 是要离开的路由
//next()是放行函数
//next('/login')hash 地址强制跳转
//next(false)禁止跳转
if(to.path==='/main'){
//访问的是主页
const token = localStroage.getItem('token')
//查看是否登录即是否有 token
if(token){
next()//如果有直接放行
}else{
next('/login')//没有就强制跳转到登录
}
}else{
next()//访问的不是主页,直接放行
}
})

其他

常见 vuter 报错解决 在 eslintrc.js 的 rules 内新增规则并重启服务器
'space-before-function-paren':['error','never']

vue.config.jsapi 文档

vue.config.js 内配置跨域

module.exports = {
publicPath: './',
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000', // 要请求的 API
changeOrigin: true, // 是否开启跨域
pathRewrite: {
'^/api': '' // 重写路由
}
}
}
}
}
posted @   有些东西学不会  阅读(343)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css
点击右上角即可分享
微信分享提示