学习:VueUse (1)

useFullscreen | VueUse 中文网

VueUse简介

VueUse是一个Vue组合式函数(Composables)的集合,为Vue开发者提供了大量实用的工具函数,可以极大地提高开发效率。

  • VueUse是一个Vue组合式函数的集合
  • 提供了大量可重用的逻辑
  • 适用于Vue 2和Vue 3
  • 无需安装整个库,可以按需导入
  • 完全使用TypeScript编写,提供优秀的类型支持

安装VueUse

复制代码
# 使用npm
npm i @vueuse/core

# 使用yarn
yarn add @vueuse/core

# 使用pnpm
pnpm add @vueuse/core

使用VueUse:

javascript 复制代码
// 按需导入
import { useMouse, useLocalStorage } from '@vueuse/core'

export default {
  setup() {
    // 使用组合式函数
    const { x, y } = useMouse()
    const storage = useLocalStorage('my-key', 'default-value')
    
    return {
      x, y,
      storage
    }
  }
}

VueUse生态系统:

javascript 复制代码
@vueuse/core        # 核心库,包含最常用的组合式函数
@vueuse/components  # 组件库
@vueuse/motion      # 动画相关
@vueuse/rxjs        # RxJS集成
@vueuse/firebase    # Firebase集成
@vueuse/math        # 数学相关工具
@vueuse/sound       # 声音相关工具
@vueuse/router      # Vue Router集成
@vueuse/head        # 标题和元信息管理
@vueuse/integrations #为工具库提供集成封装器

浏览器API相关的Composables

useWindowScroll - 监听窗口滚动
javascript 复制代码
import { useWindowScroll } from '@vueuse/core'

export default {
  setup() {
    const { x, y, isScrolling, arrivedState, directions } = useWindowScroll()
    
    console.log(x.value)     // 水平滚动位置
    console.log(y.value)     // 垂直滚动位置
    console.log(isScrolling.value)  // 是否正在滚动
    console.log(arrivedState)  // { top: true, bottom: false, left: true, right: false }
    console.log(directions)  // { top: false, bottom: true, left: false, right: false }
    
    return {
      x, y, isScrolling,
      // 可以使用计算属性创建逻辑
      isAtBottom: computed(() => arrivedState.bottom)
    }
  }
}
useWindowSize - 监听窗口大小
javascript 复制代码
import { useWindowSize } from '@vueuse/core'

export default {
  setup() {
    const { width, height } = useWindowSize()
    
    console.log(width.value)  // 窗口宽度
    console.log(height.value) // 窗口高度
    
    // 响应式逻辑
    const isMobile = computed(() => width.value < 768)
    const isTablet = computed(() => width.value >= 768 && width.value < 1024)
    const isDesktop = computed(() => width.value >= 1024)
    
    return {
      width, height,
      isMobile, isTablet, isDesktop
    }
  }
}
useDark - 暗黑模式切换
javascript 复制代码
import { useDark, useToggle } from '@vueuse/core'

export default {
  setup() {
    // 使用暗黑模式
    const isDark = useDark()
    
    // 创建切换函数
    const toggleDark = useToggle(isDark)
    
    return {
      isDark,
      toggleDark
    }
  }
}
useClipboard - 剪贴板操作
javascript 复制代码
import { useClipboard } from '@vueuse/core'

export default {
  setup() {
    const source = ref('Hello VueUse!')
    const { copy, copied, isSupported } = useClipboard({ source })
    
    // 手动复制
    const copyToClipboard = (text) => {
      source.value = text
      copy()
    }
    
    return {
      source,
      copy,
      copied,
      isSupported,
      copyToClipboard
    }
  }
}
useLocalStorage - 本地存储
javascript 复制代码
import { useLocalStorage } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const storedValue = useLocalStorage('my-key', 'default-value')
    
    // 存储对象
    const user = useLocalStorage('user', {
      name: '',
      email: '',
      preferences: {
        theme: 'light',
        language: 'en'
      }
    })
    
    // 监听变化
    watch(
      () => user.value,
      (newValue) => {
        console.log('用户数据已更新:', newValue)
      },
      { deep: true }
    )
    
    return {
      storedValue,
      user
    }
  }
}
useGeolocation - 地理位置API
javascript 复制代码
import { useGeolocation } from '@vueuse/core'

export default {
  setup() {
    const { 
      coords, 
      locatedAt, 
      error, 
      pause, 
      resume, 
      isLoading 
    } = useGeolocation()
    
    // coords包含经纬度信息
    console.log(coords.value.latitude)  // 纬度
    console.log(coords.value.longitude) // 经度
    
    return {
      coords,
      locatedAt,
      error,
      isLoading,
      pause,    // 暂停位置更新
      resume    // 恢复位置更新
    }
  }
}
useFullscreen - 全屏API
javascript 复制代码
import { useFullscreen } from '@vueuse/core'

export default {
  setup() {
    const { isFullscreen, enter, exit, toggle } = useFullscreen()
    
    // 也可以指定元素
    const el = ref()
    const { isFullscreen: elFullscreen } = useFullscreen(el)
    
    return {
      isFullscreen,
      elFullscreen,
      enter,
      exit,
      toggle,
      el
    }
  }
}

状态管理相关的Composables

useStorage - 通用存储API
javascript 复制代码
import { useStorage } from '@vueuse/core'

export default {
  setup() {
    // 使用localStorage (默认)
    const localData = useStorage('local-key', { foo: 'bar' })
    
    // 使用sessionStorage
    const sessionData = useStorage('session-key', { foo: 'bar' }, sessionStorage)
    
    // 自定义存储实现
    const customStorage = {
      getItem: (key) => myStorageSystem.get(key),
      setItem: (key, value) => myStorageSystem.set(key, value)
    }
    const customData = useStorage('custom-key', { foo: 'bar' }, customStorage)
    
    return {
      localData,
      sessionData,
      customData
    }
  }
}
useTimeoutFn - 延时执行函数
javascript 复制代码
import { useTimeoutFn } from '@vueuse/core'

export default {
  setup() {
    const { 
      start, 
      stop, 
      isPending 
    } = useTimeoutFn(() => {
      console.log('3秒后执行')
    }, 3000)
    
    // 立即启动
    start()
    
    return {
      start,
      stop,
      isPending
    }
  }
}
useIntervalFn - 定时执行函数
javascript 复制代码
import { useIntervalFn } from '@vueuse/core'

export default {
  setup() {
    const count = ref(0)
    
    const { 
      pause, 
      resume, 
      isActive 
    } = useIntervalFn(() => {
      count.value++
      console.log(`计数: ${count.value}`)
    }, 1000)
    
    return {
      count,
      pause,
      resume,
      isActive
    }
  }
}
useDebounceFn - 防抖函数
javascript 复制代码
import { useDebounceFn } from '@vueuse/core'

export default {
  setup() {
    const searchQuery = ref('')
    const results = ref([])
    
    // 创建防抖函数,延迟500ms
    const debouncedSearch = useDebounceFn(() => {
      console.log('执行搜索:', searchQuery.value)
      // 模拟API请求
      fetch(`/api/search?q=${searchQuery.value}`)
        .then(res => res.json())
        .then(data => {
          results.value = data
        })
    }, 500)
    
    // 监听搜索词变化
    watch(searchQuery, () => {
      if (searchQuery.value.trim()) {
        debouncedSearch()
      }
    })
    
    return {
      searchQuery,
      results
    }
  }
}
useThrottleFn - 节流函数
javascript 复制代码
import { useThrottleFn } from '@vueuse/core'

export default {
  setup() {
    const position = ref({ x: 0, y: 0 })
    
    // 创建节流函数,每200ms最多执行一次
    const throttledMouseMove = useThrottleFn((event) => {
      position.value = { x: event.clientX, y: event.clientY }
      console.log('鼠标位置:', position.value)
    }, 200)
    
    const handleMouseMove = (event) => {
      throttledMouseMove(event)
    }
    
    onMounted(() => {
      window.addEventListener('mousemove', handleMouseMove)
    })
    
    onUnmounted(() => {
      window.removeEventListener('mousemove', handleMouseMove)
    })
    
    return {
      position
    }
  }
}

用户交互相关的Composables

useMouse - 鼠标位置追踪
javascript 复制代码
import { useMouse } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const { x, y, sourceType } = useMouse()
    
    // 相对于特定元素
    const el = ref()
    const { x: elX, y: elY } = useMouse({ target: el })
    
    return {
      x, y, sourceType,
      elX, elY,
      el
    }
  }
}
usePointer - 指针位置追踪(支持触摸)
javascript 复制代码
import { usePointer } from '@vueuse/core'

export default {
  setup() {
    const { 
      x, 
      y, 
      pressure, 
      pointerType, 
      isInside 
    } = usePointer()
    
    // 检测设备类型
    const isMouse = computed(() => pointerType.value === 'mouse')
    const isTouch = computed(() => pointerType.value === 'touch')
    const isPen = computed(() => pointerType.value === 'pen')
    
    return {
      x, y, pressure, pointerType, isInside,
      isMouse, isTouch, isPen
    }
  }
}
useKeyboard - 键盘事件监听
javascript 复制代码
import { useKeyboard } from '@vueuse/core'

export default {
  setup() {
    // 监听特定按键
    const pressed = useKeyboard('Enter')
    
    // 监听多个按键
    const ctrlPressed = useKeyboard('Control')
    const spacePressed = useKeyboard(' ')
    
    // 组合键
    const ctrlAPressed = useKeyboard('Control+a')
    const ctrlSPressed = useKeyboard('Control+s')
    
    // 处理组合键
    watch(ctrlSPressed, (newValue) => {
      if (newValue) {
        console.log('Ctrl+S 被按下,执行保存操作')
        // 保存操作
      }
    })
    
    return {
      pressed,
      ctrlPressed,
      spacePressed,
      ctrlAPressed,
      ctrlSPressed
    }
  }
}
useDraggable - 拖拽功能
javascript 复制代码
import { useDraggable } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const el = ref()
    const { x, y, style } = useDraggable(el)
    
    // 限制拖拽范围
    const container = ref()
    const { 
      x: boundedX, 
      y: boundedY, 
      style: boundedStyle 
    } = useDraggable(el, {
      containerElement: container,
      initialValue: { x: 100, y: 100 }
    })
    
    // 只允许水平拖拽
    const { 
      x: horizontalX, 
      style: horizontalStyle 
    } = useDraggable(el, {
      axis: 'x'
    })
    
    return {
      el,
      x, y, style,
      container,
      boundedX, boundedY, boundedStyle,
      horizontalX, horizontalStyle
    }
  }
}
useDropZone - 拖放区域
javascript 复制代码
import { useDropZone } from '@vueuse/core'

export default {
  setup() {
    const dropZoneRef = ref()
    const files = ref([])
    
    const { isOverDropZone } = useDropZone(dropZoneRef, {
      onDrop,
      onOver,
      onLeave,
    })
    
    function onDrop(files) {
      console.log('拖放的文件:', files)
      files.value = Array.from(files)
    }
    
    function onOver(files) {
      console.log('文件进入拖放区域:', files)
    }
    
    function onLeave(files) {
      console.log('文件离开拖放区域:', files)
    }
    
    return {
      dropZoneRef,
      files,
      isOverDropZone
    }
  }
}

动画与过渡相关的Composables

useTransition - 过渡值
javascript 复制代码
import { useTransition } from '@vueuse/core'

export default {
  setup() {
    const source = ref(0)
    const output = useTransition(source)
    
    // 更新源值,会平滑过渡到目标值
    source.value = 100
    
    // 自定义过渡
    const customOutput = useTransition(source, {
      duration: 1000,
      transition: [0.25, 0.1, 0.25, 1] // 贝塞尔曲线
    })
    
    return {
      source,
      output,
      customOutput
    }
  }
}
useTween - 补间动画
javascript 复制代码
import { useTween } from '@vueuse/core'

export default {
  setup() {
    // 从0到100的补间动画,持续1秒
    const tween = useTween(100, 1000)
    
    console.log(tween.value) // 当前值(0-100)
    
    // 使用回调
    const animated = useTween(100, 1000, {
      onUpdate: (value) => {
        console.log('当前值:', value)
      },
      onComplete: () => {
        console.log('动画完成')
      }
    })
    
    return {
      tween,
      animated
    }
  }
}
useMotion - 运动动画
javascript 复制代码
import { useMotion } from '@vueuse/core'
import { ref } from 'vue'

export default {
  setup() {
    const el = ref()
    
    const { apply, stop, instance } = useMotion(el, {
      initial: {
        opacity: 0,
        y: 100
      },
      enter: {
        opacity: 1,
        y: 0,
        transition: {
          duration: 800,
          type: 'spring'
        }
      },
      leave: {
        opacity: 0,
        y: -100,
        transition: {
          duration: 300,
          ease: 'easeIn'
        }
      }
    })
    
    // 手动应用动画
    const applyAnimation = () => {
      apply('enter')
    }
    
    return {
      el,
      applyAnimation
    }
  }
}

网络请求相关的Composables

useFetch - HTTP请求
javascript 复制代码
import { useFetch } from '@vueuse/core'

export default {
  setup() {
    // GET请求
    const { data, error, pending, execute } = useFetch('/api/users')
    
    console.log(data.value)    // 响应数据
    console.log(error.value)  // 错误信息
    console.log(pending.value) // 是否正在请求
    
    // POST请求
    const { data: postData, execute: postExecute } = useFetch('/api/users').post({
      name: 'John Doe',
      email: 'john@example.com'
    }).json()
    
    // 手动执行请求
    const manualRequest = async () => {
      await execute()
      console.log('请求完成:', data.value)
    }
    
    return {
      data,
      error,
      pending,
      execute,
      postData,
      postExecute,
      manualRequest
    }
  }
}
useAsyncState - 异步状态管理
javascript 复制代码
import { useAsyncState } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const { state, isReady, isLoading, error } = useAsyncState(
      fetch('https://api.example.com/data').then(res => res.json()),
      { id: 1, name: 'Loading...' }  // 初始状态
    )
    
    // 使用异步函数
    const fetchUserData = async (userId) => {
      const response = await fetch(`https://api.example.com/users/${userId}`)
      return response.json()
    }
    
    const { 
      state: userState, 
      execute: fetchUser, 
      refresh 
    } = useAsyncState(fetchUserData, null, {
      immediate: false  // 不立即执行
    })
    
    // 获取用户数据
    const getUser = (id) => {
      fetchUser(1001)  // 传入参数
    }
    
    return {
      state,
      isReady,
      isLoading,
      error,
      userState,
      getUser,
      refresh
    }
  }
}

时间与日期相关的Composables

useNow - 当前时间
javascript 复制代码
import { useNow } from '@vueuse/core'

export default {
  setup() {
    // 基本用法 - 每秒更新一次
    const now = useNow()
    
    // 自定义更新间隔
    const slowNow = useNow({ 
      interval: 5000  // 每5秒更新一次
    })
    
    // 计算属性
    const formattedTime = computed(() => {
      return new Intl.DateTimeFormat().format(now.value)
    })
    
    return {
      now,
      slowNow,
      formattedTime
    }
  }
}
useDateFormat - 日期格式化
javascript 复制代码
import { useDateFormat, useNow } from '@vueuse/core'

export default {
  setup() {
    const now = useNow()
    
    // 基本格式化
    const formatted = useDateFormat(now, 'YYYY-MM-DD HH:mm:ss')
    
    // 使用预设格式
    const isoFormat = useDateFormat(now, 'iso')
    const usFormat = useDateFormat(now, 'MM/DD/YYYY')
    
    // 自定义格式
    const customFormat = useDateFormat(now, 'dddd, MMMM Do YYYY')
    
    // 格式化固定日期
    const birthday = useDateFormat('1990-01-01', 'YYYY-MM-DD')
    
    return {
      formatted,
      isoFormat,
      usFormat,
      customFormat,
      birthday
    }
  }
}
useCountdown - 倒计时
javascript 复制代码
import { useCountdown } from '@vueuse/core'

export default {
  setup() {
    // 基本用法 - 从60秒开始倒计时
    const { 
      countdown, 
      isRunning, 
      start, 
      stop, 
      reset 
    } = useCountdown(60, {
      interval: 1000,  // 每秒更新一次
      onFinished: () => {
        console.log('倒计时结束')
      }
    })
    
    // 格式化显示
    const formattedTime = computed(() => {
      const minutes = Math.floor(countdown.value / 60)
      const seconds = countdown.value % 60
      return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`
    })
    
    return {
      countdown,
      isRunning,
      start,
      stop,
      reset,
      formattedTime
    }
  }
}

实用工具类Composables

useToggle - 切换布尔值
javascript 复制代码
import { useToggle } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const [value, toggle] = useToggle(true)
    
    // 手动切换
    const flip = () => {
      toggle()
    }
    
    // 直接设置值
    const setTrue = () => {
      toggle(true)
    }
    
    const setFalse = () => {
      toggle(false)
    }
    
    return {
      value,
      flip,
      setTrue,
      setFalse
    }
  }
}
useArrayFind - 数组查找
javascript 复制代码
import { useArrayFind } from '@vueuse/core'

export default {
  setup() {
    const items = ref([
      { id: 1, name: 'Item 1', category: 'A' },
      { id: 2, name: 'Item 2', category: 'B' },
      { id: 3, name: 'Item 3', category: 'A' }
    ])
    
    // 查找第一个符合条件的项
    const { 
      find, 
      result: foundItem 
    } = useArrayFind(items, item => item.category === 'A')
    
    // 手动触发查找
    const findFirstItem = () => {
      find()
    }
    
    // 带默认值
    const { 
      find: findWithDefault, 
      result: foundItemWithDefault 
    } = useArrayFind(
      items, 
      item => item.category === 'C', 
      { id: -1, name: 'Not Found' }
    )
    
    return {
      items,
      foundItem,
      findFirstItem,
      foundItemWithDefault
    }
  }
}
useTitle - 页面标题管理
javascript 复制代码
import { useTitle } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const title = useTitle('My Awesome App')
    
    // 更新标题
    const updateTitle = (newTitle) => {
      title.value = newTitle
    }
    
    // 恢复原始标题
    const restoreTitle = () => {
      title.value = null
    }
    
    return {
      title,
      updateTitle,
      restoreTitle
    }
  }
}
useFavicon - 网站图标管理
javascript 复制代码
import { useFavicon } from '@vueuse/core'

export default {
  setup() {
    // 基本用法
    const favicon = useFavicon()
    
    // 设置特定图标
    const setLightFavicon = () => {
      favicon.value = '/light-favicon.ico'
    }
    
    const setDarkFavicon = () => {
      favicon.value = '/dark-favicon.ico'
    }
    
    // 使用表情符号作为图标
    const setEmojiFavicon = () => {
      favicon.value = '🚀'
    }
    
    return {
      favicon,
      setLightFavicon,
      setDarkFavicon,
      setEmojiFavicon
    }
  }
}
useToggle - 状态切换
javascript 复制代码
import { useToggle } from '@vueuse/core'

export default {
  setup() {
    // 切换布尔值
    const [isOpen, toggleOpen] = useToggle(false)
    
    // 切换多个状态
    const options = ['Option A', 'Option B', 'Option C']
    const [currentOption, toggleOption] = useToggle(options)
    
    // 自定义初始值
    const [isDark, toggleDark] = useToggle(true)
    
    return {
      isOpen,
      toggleOpen,
      currentOption,
      toggleOption,
      isDark,
      toggleDark
    }
  }
}

创建自定义Composables

VueUse的设计理念鼓励我们创建自己的可重用组合式函数。下面是一些自定义Composables的例子:

自定义API状态管理
javascript 复制代码
// composables/useApiState.js
import { ref, computed } from 'vue'
import { useAsyncState } from '@vueuse/core'

export function useApiState(apiCall, initialData = null, options = {}) {
  const {
    state: data,
    isReady,
    isLoading,
    error,
    execute,
    refresh
  } = useAsyncState(apiCall, initialData, {
    resetOnExecute: false,
    ...options
  })
  
  const hasData = computed(() => !!data.value)
  const hasError = computed(() => !!error.value)
  
  const errorMessage = computed(() => {
    return hasError.value ? error.value.message : ''
  })
  
  return {
    data,
    isReady,
    isLoading,
    error,
    errorMessage,
    hasData,
    hasError,
    execute,
    refresh
  }
}

// 使用自定义组合式函数
export default {
  setup() {
    const fetchUsers = async () => {
      const response = await fetch('/api/users')
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`)
      }
      return response.json()
    }
    
    const {
      data: users,
      isLoading,
      errorMessage,
      hasError,
      refresh
    } = useApiState(fetchUsers, [])
    
    return {
      users,
      isLoading,
      errorMessage,
      hasError,
      refresh
    }
  }
}
自定义验证功能
javascript 复制代码
// composables/useValidation.js
import { ref, computed } from 'vue'

export function useValidation(rules, initialValue = '') {
  const value = ref(initialValue)
  const error = ref('')
  const isDirty = ref(false)
  
  const validate = () => {
    isDirty.value = true
    error.value = ''
    
    for (const rule of rules) {
      const result = rule(value.value)
      if (result !== true) {
        error.value = result
        return false
      }
    }
    
    return true
  }
  
  const isValid = computed(() => {
    if (!isDirty.value) return true
    return !error.value
  })
  
  // 常用验证规则
  const requiredRule = (val) => !!val || '此字段为必填项'
  const emailRule = (val) => {
    const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
    return pattern.test(val) || '请输入有效的邮箱地址'
  }
  const minLengthRule = (min) => (val) => val.length >= min || `最少需要${min}个字符`
  
  return {
    value,
    error,
    isDirty,
    isValid,
    validate,
    rules: {
      required: requiredRule,
      email: emailRule,
      minLength: minLengthRule
    }
  }
}

// 使用自定义验证
export default {
  setup() {
    const {
      value: email,
      error: emailError,
      isDirty: emailDirty,
      isValid: emailValid,
      validate: validateEmail
    } = useValidation([
      value => !!value || '邮箱是必填项',
      value => {
        const pattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
        return pattern.test(value) || '请输入有效的邮箱地址'
      }
    ])
    
    const submitForm = () => {
      validateEmail()
      if (emailValid.value) {
        console.log('表单提交:', email.value)
      }
    }
    
    return {
      email,
      emailError,
      emailDirty,
      emailValid,
      submitForm
    }
  }
}

集成

VueUse最佳实践

  1. 按需导入:只导入需要的功能,减少打包体积

    复制代码
    // ✅ 推荐 - 按需导入
    import { useMouse } from '@vueuse/core'
    
    // ❌ 不推荐 - 导入整个库
    import VueUse from '@vueuse/core'
  2. 合理使用响应式:注意哪些返回值是响应式的,哪些不是

    javascript 复制代码
    const { x, y } = useMouse()  // x和y都是响应式的ref
    const source = ref('text')   // source是响应式的ref
  3. 清理资源:某些Composables需要手动清理资源

    javascript 复制代码
    const { pause, resume } = useIntervalFn(callback, 1000)
    
    onUnmounted(() => {
      pause() // 清理定时器
    })
  4. 组合使用:将多个Composables组合使用,创建更复杂的功能

    javascript 复制代码
    const { x, y } = useMouse()
    const isDark = useDark()
    
    // 根据鼠标位置和主题模式改变样式
    const cursorStyle = computed(() => ({
      left: `${x.value}px`,
      top: `${y.value}px`,
      opacity: isDark.value ? 0.8 : 0.5
    }))
  5. 错误处理:处理Composables可能抛出的错误

    javascript 复制代码
    const { data, error } = useFetch('/api/data')
    
    if (error.value) {
      console.error('请求失败:', error.value)
    }
  6. 性能优化:对于计算密集型的操作,考虑使用防抖或节流

    javascript 复制代码
    const debouncedSearch = useDebounceFn(searchAPI, 500)
相关推荐
西岸行者2 天前
学习笔记:SKILLS 能帮助更好的vibe coding
笔记·学习
悠哉悠哉愿意2 天前
【单片机学习笔记】串口、超声波、NE555的同时使用
笔记·单片机·学习
别催小唐敲代码2 天前
嵌入式学习路线
学习
毛小茛2 天前
计算机系统概论——校验码
学习
babe小鑫2 天前
大专经济信息管理专业学习数据分析的必要性
学习·数据挖掘·数据分析
winfreedoms2 天前
ROS2知识大白话
笔记·学习·ros2
在这habit之下2 天前
Linux Virtual Server(LVS)学习总结
linux·学习·lvs
我想我不够好。2 天前
2026.2.25监控学习
学习
im_AMBER2 天前
Leetcode 127 删除有序数组中的重复项 | 删除有序数组中的重复项 II
数据结构·学习·算法·leetcode
CodeJourney_J2 天前
从“Hello World“ 开始 C++
c语言·c++·学习