vue3 之 商城项目—封装SKU组件

news2024/11/26 8:29:24

认识SKU组件

在这里插入图片描述
SKU组件的作用
在这里插入图片描述
产出当前用户选择的商品规格,为加入购物车操作提供数据信息,在选择的过程中,组件的选中状态要进行更新,组件还要提示用户当前规格是否禁用,每次选择都要产出对应的sku数据

SKU组件的使用
假如你在开发的过程中要使用别人开发好的组件,重点看什么?
props和emit,props决定了当前组件接收什么数据,emit决定了会产出什么数据
在这里插入图片描述

点击规格

在这里插入图片描述
准备模版渲染规格数据

<script setup>
import { onMounted, ref } from 'vue'
import axios from 'axios'
// 商品数据
const goods = ref({})
const getGoods = async () => {
  // 1135076  初始化就有无库存的规格
  // 1369155859933827074 更新之后有无库存项(蓝色-20cm-中国)
  const res = await axios.get('http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1369155859933827074')
  goods.value = res.data.result
}
onMounted(() => getGoods())

</script>

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <!-- 图片类型规格 -->
          <img v-if="val.picture" :src="val.picture" :title="val.name">
          <!-- 文字类型规格 -->
          <span v-else>{{ val.name }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>

<style scoped lang="scss">
@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: #27ba9b;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }
    }
  }
}
</style>

选中和取消选中实现

基本思路:

  1. 每一个规格按钮都拥有自己的选中状态数据-selected,true为选中,false为取消选中
  2. 配合动态class,把选中状态selected作为判断条件,true让active类名显示,false让active类名不显示
  3. 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中;点击的是已选中,直接取消
<script setup>
// 省略代码
// 选中和取消选中实现
const changeSku = (item, val) => {
  // 点击的是未选中,把同一个规格的其他取消选中,当前点击项选中,点击的是已选中,直接取消
  if (val.selected) {
    val.selected = false
  } else {
    item.values.forEach(valItem => valItem.selected = false)
    val.selected = true
  }
}
</script>

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <img v-if="val.picture" 
            @click="changeSku(item, val)" 
            :class="{ selected: val.selected }" 
            :src="val.picture"
            :title="val.name">
          <span v-else 
            @click="changeSku(val)" 
            :class="{ selected: val.selected }">{{ val.name }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>

点击规格更新禁用状态—生成有效路径字典

规格禁用判断的依据是什么?
核心原理:当前的规格sku,或者组合起来的规格sku,在skus数组中对应的库存为0时,当前规格会被禁用,生成路径字典是为了协助和简化这个匹配过程
在这里插入图片描述
实现步骤
1️⃣根据库存字段得到有效的sku数组
2️⃣根据有效的sku数组使用powerSet算法得到所有子集
3️⃣根据子集生成路径字典对象
生成有效路径字典对象
在这里插入图片描述

import powerSet from './power-set'
const getPathMap = (goods) => {
  const pathMap = {}
  // 1. 得到所有有效的Sku集合 
  const effectiveSkus = goods.skus.filter(sku => sku.inventory > 0)
  
  // 2. 根据有效的Sku集合使用powerSet算法得到所有子集 [1,2] => [[1], [2], [1,2]]
  effectiveSkus.forEach(sku => {
    // 2.1 获取匹配的valueName组成的数组
    const selectedValArr = sku.specs.map(val => val.valueName)
    // 2.2 使用算法获取子集
    const valueArrPowerSet = powerSet(selectedValArr)
    // 3. 根据子集生成最终的路径字典对象
    // 3.1 遍历子集 往pathMap中插入数据
    valueArrPowerSet.forEach(arr => {
      // 根据Arr得到字符串的key,约定使用-分割 ['蓝色','美国'] => '蓝色-美国'
      //初始化key 数组join -> 字符串  对象的key
      const key = arr.join('-')
      //如果已经存在当前key了 就往数组中直接添加skuId 如果不存在key 直接做赋值 
      if (pathMap[key]) {
        pathMap[key].push(sku.id)
      } else {
        pathMap[key] = [sku.id]
      }
    })
  })
  return pathMap
}
// 数据获取完毕生成路径字典
let pathMap = {}
const getGoods = async () => {
  // 1135076  初始化就有无库存的规格
  // 1369155859933827074 更新之后有无库存项(蓝色-20cm-中国)
  const res = await axios.get('http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1135076')
  goods.value = res.data.result
  pathMap = getPathMap(goods.value)
  // 初始化更新按钮状态
  initDisabledState(goods.value.specs, pathMap)
}

power-set.js

export default function bwPowerSet (originalSet) {
  const subSets = []

  // We will have 2^n possible combinations (where n is a length of original set).
  // It is because for every element of original set we will decide whether to include
  // it or not (2 options for each set element).
  const numberOfCombinations = 2 ** originalSet.length

  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  // it shows by its bits (0 or 1) whether to include related element from the set or not.
  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  // include only "2" to the current set.
  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = []

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      // Decide whether we need to include current element into the subset or not.
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex])
      }
    }

    // Add current subset to the list of all subsets.
    subSets.push(subSet)
  }
  return subSets
}

点击规格更新禁用状态—初始化规格禁用

思路:遍历每一个规格对象,使用nam字段作为key去路径字典pathMap中做匹配,匹配不上则禁用
怎么做到显示上的禁用呢?
1️⃣通过增加disabled字段,匹配上路径字段,disabled为false,匹配不上路径字段,disabled为true
2️⃣配合动态类名控制禁用类名

// 1. 定义初始化函数
// specs:商品源数据 pathMap:路径字典
const initDisabledState = (specs, pathMap) => {
  // 约定:每一个按钮的状态由自身的disabled进行控制
  specs.forEach(item => {
    item.values.forEach(val => {
      // 路径字典中查找是否有数据 有-可以点击 没有-禁用
      val.disabled = !pathMap[val.name]
    })
  })
}

// 2. 在数据返回后进行初始化处理
let patchMap = {}
const getGoods = async () => {
  // 1135076  初始化就有无库存的规格
  // 1369155859933827074 更新之后有无库存项(蓝色-20cm-中国)
  const res = await axios.get('http://pcapi-xiaotuxian-front-devtest.itheima.net/goods?id=1135076')
  goods.value = res.data.result
  pathMap = getPathMap(goods.value)
  // 初始化更新按钮状态
  initDisabledState(goods.value.specs, pathMap)
}

点击规格更新禁用状态—点击时组合禁用更新

思路(点击规格时)
1️⃣按照顺序得到规格选项中的数组[‘蓝色’,‘20cm’,‘undefined’]
2️⃣遍历每一个规格
把name字段的值填充到对应的位置
过滤掉undefined项使用join方法形成一个有效的key
使用key去pathMap中进行匹配,匹配不删,则当前项禁用
在这里插入图片描述
在这里插入图片描述

结合上面图片,蓝色-20cm-中国 在数组中是没有的,所以中国应该禁用掉

在这里插入图片描述

// 获取选中项的匹配数组
const getSelectedArr = (specs) => {
  const selectedArr = []
  specs.forEach((spec, index) => {
  //目标:找到valus中selected为true的项,然后把它的name字段添加数组对应的位置
    const selectedVal = spec.values.find(val => val.selected)
    if (selectedVal) {
      selectedArr[index] = selectedVal.name
    } else {
      selectedArr[index] = undefined
    }
  })
  return selectedArr
}
// 更新按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 遍历每一种规格
  specs.forEach((item, i) => {
    // 拿到当前选择的项目
    const selectedArr = getSelectedArr(specs)
    // 遍历每一个按钮
    item.values.forEach(val => {
      if (!val.selected) {
        selectedArr[i] = val.name
        // 去掉undefined之后组合成key
        const key = selectedArr.filter(value => value).join(spliter)
        val.disabled = !pathMap[key]
      }
    })
  })
}

产出有效的SKU信息

在这里插入图片描述
什么是有效的SKU?
颜色 尺寸 产地都选择了

如何判断当前用户已经选择了所有有效的规格?
已选择项数组[‘蓝色’,‘20cm’,‘undefined’]中找不到undefined,那么用户已经选择了所有的有效规格,此时可以产出数据

如何获取当前SKU信息对象?
把已选择项数组拼接为路径字典的key,去路径字典pathMap中找即可

//产出SKU对象数据
const index = getSelectedArr(goods.value.specs).findIndex(item=>item === undefined)
if(index>-1){
 console.log('找到了,信息不完整')
 }else{
 console.log('没找到了,信息完整,可以产出')
 //获取SKU对象
 getSelectedArr(goods.value.specs).join('*')
 const skuIds = pathMap[key]
 console.log('sku对象',skuIds)
 //以skuIds作为匹配项去goods.value.skus数组中找
 }

在这里插入图片描述

完整代码

Xtxsku/index.vue

<template>
  <div class="goods-sku">
    <dl v-for="item in goods.specs" :key="item.id">
      <dt>{{ item.name }}</dt>
      <dd>
        <template v-for="val in item.values" :key="val.name">
          <img :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)"
            v-if="val.picture" :src="val.picture" />
          <span :class="{ selected: val.selected, disabled: val.disabled }" @click="clickSpecs(item, val)" v-else>{{
              val.name
          }}</span>
        </template>
      </dd>
    </dl>
  </div>
</template>
<script>
import { watchEffect } from 'vue'
import getPowerSet from './power-set'
const spliter = '★'
// 根据skus数据得到路径字典对象
const getPathMap = (skus) => {
  const pathMap = {}
  if (skus && skus.length > 0) {
    skus.forEach(sku => {
      // 1. 过滤出有库存有效的sku
      if (sku.inventory) {
        // 2. 得到sku属性值数组
        const specs = sku.specs.map(spec => spec.valueName)
        // 3. 得到sku属性值数组的子集
        const powerSet = getPowerSet(specs)
        // 4. 设置给路径字典对象
        powerSet.forEach(set => {
          const key = set.join(spliter)
          // 如果没有就先初始化一个空数组
          if (!pathMap[key]) {
            pathMap[key] = []
          }
          pathMap[key].push(sku.id)
        })
      }
    })
  }
  return pathMap
}

// 初始化禁用状态
function initDisabledStatus (specs, pathMap) {
  if (specs && specs.length > 0) {
    specs.forEach(spec => {
      spec.values.forEach(val => {
        // 设置禁用状态
        val.disabled = !pathMap[val.name]
      })
    })
  }
}

// 得到当前选中规格集合
const getSelectedArr = (specs) => {
  const selectedArr = []
  specs.forEach((spec, index) => {
    const selectedVal = spec.values.find(val => val.selected)
    if (selectedVal) {
      selectedArr[index] = selectedVal.name
    } else {
      selectedArr[index] = undefined
    }
  })
  return selectedArr
}

// 更新按钮的禁用状态
const updateDisabledStatus = (specs, pathMap) => {
  // 遍历每一种规格
  specs.forEach((item, i) => {
    // 拿到当前选择的项目
    const selectedArr = getSelectedArr(specs)
    // 遍历每一个按钮
    item.values.forEach(val => {
      if (!val.selected) {
        selectedArr[i] = val.name
        // 去掉undefined之后组合成key
        const key = selectedArr.filter(value => value).join(spliter)
        val.disabled = !pathMap[key]
      }
    })
  })
}


export default {
  name: 'XtxGoodSku',
  props: {
    // specs:所有的规格信息  skus:所有的sku组合
    goods: {
      type: Object,
      default: () => ({ specs: [], skus: [] })
    }
  },
  emits: ['change'],
  setup (props, { emit }) {
    let pathMap = {}
    watchEffect(() => {
      // 得到所有字典集合
      pathMap = getPathMap(props.goods.skus)
      // 组件初始化的时候更新禁用状态
      initDisabledStatus(props.goods.specs, pathMap)
    })

    const clickSpecs = (item, val) => {
      if (val.disabled) return false
      // 选中与取消选中逻辑
      if (val.selected) {
        val.selected = false
      } else {
        item.values.forEach(bv => { bv.selected = false })
        val.selected = true
      }
      // 点击之后再次更新选中状态
      updateDisabledStatus(props.goods.specs, pathMap)
      // 把选择的sku信息传出去给父组件
      // 触发change事件将sku数据传递出去
      const selectedArr = getSelectedArr(props.goods.specs).filter(value => value)
      // 如果选中得规格数量和传入得规格总数相等则传出完整信息(都选择了)
      // 否则传出空对象
      if (selectedArr.length === props.goods.specs.length) {
        // 从路径字典中得到skuId
        const skuId = pathMap[selectedArr.join(spliter)][0]
        const sku = props.goods.skus.find(sku => sku.id === skuId)
        // 传递数据给父组件
        emit('change', {
          skuId: sku.id,
          price: sku.price,
          oldPrice: sku.oldPrice,
          inventory: sku.inventory,
          specsText: sku.specs.reduce((p, n) => `${p} ${n.name}${n.valueName}`, '').trim()
        })
      } else {
        emit('change', {})
      }
    }
    return { clickSpecs }
  }
}
</script>

<style scoped lang="scss">
@mixin sku-state-mixin {
  border: 1px solid #e4e4e4;
  margin-right: 10px;
  cursor: pointer;

  &.selected {
    border-color: $xtxColor;
  }

  &.disabled {
    opacity: 0.6;
    border-style: dashed;
    cursor: not-allowed;
  }
}

.goods-sku {
  padding-left: 10px;
  padding-top: 20px;

  dl {
    display: flex;
    padding-bottom: 20px;
    align-items: center;

    dt {
      width: 50px;
      color: #999;
    }

    dd {
      flex: 1;
      color: #666;

      >img {
        width: 50px;
        height: 50px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }

      >span {
        display: inline-block;
        height: 30px;
        line-height: 28px;
        padding: 0 20px;
        margin-bottom: 4px;
        @include sku-state-mixin;
      }
    }
  }
}
</style>

Xtxsku/power-set.js


export default function bwPowerSet (originalSet) {
  const subSets = []

  // We will have 2^n possible combinations (where n is a length of original set).
  // It is because for every element of original set we will decide whether to include
  // it or not (2 options for each set element).
  const numberOfCombinations = 2 ** originalSet.length

  // Each number in binary representation in a range from 0 to 2^n does exactly what we need:
  // it shows by its bits (0 or 1) whether to include related element from the set or not.
  // For example, for the set {1, 2, 3} the binary number of 0b010 would mean that we need to
  // include only "2" to the current set.
  for (let combinationIndex = 0; combinationIndex < numberOfCombinations; combinationIndex += 1) {
    const subSet = []

    for (let setElementIndex = 0; setElementIndex < originalSet.length; setElementIndex += 1) {
      // Decide whether we need to include current element into the subset or not.
      if (combinationIndex & (1 << setElementIndex)) {
        subSet.push(originalSet[setElementIndex])
      }
    }

    // Add current subset to the list of all subsets.
    subSets.push(subSet)
  }

  return subSets
}

页面使用

<script setup>
import { onMounted, ref } from 'vue'
import { useRoute } from 'vue-router'
const goods = ref({})
const route = useRoute()
const getGoods = async () => {
  const res = await getDetail(route.params.id)
  goods.value = res.result
}
onMounted(() => getGoods())
// sku规格被操作时
let skuObj = {}
const skuChange = (sku) => {
  console.log(sku)
  skuObj = sku
}
</script>
  <!-- sku组件 -->
  <XtxSku :goods="goods" @change="skuChange" />

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

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

相关文章

每日学习总结20240219

每日总结 20240219 1.文件类型.csv CSV文件是一种以逗号分隔值&#xff08;Comma-Separated Values&#xff09;为标记的文本文件&#xff0c;它可以用来存储表格数据。每一行表示一条记录&#xff0c;而每一条记录中的字段则使用逗号或其他特定的分隔符进行分隔。 常用场景…

Linux第61步_“buildroot”构建根文件系统第3步_烧写根文件系统到EMMC中_并完善开发板配置

烧录到EMMC测试&#xff0c;还需进一步测试和配置。 1、删除rootfs”目录下的“rootfs.tar”压缩包 打开第1个终端 输入“ls回车” 输入“cd linux/回车”&#xff0c;切换到“linux”目录 输入“ls回车”&#xff0c;列出“linux”目录下的文件和文件夹 输入“cd nfs/回…

凌华科技USB-1902数据采集卡功能增强的经典应用DAQWare for USB1902

众所周知&#xff0c;TLA发布了一系列功能增强的基于多功能数据采集卡的课程实验套件。日前&#xff0c;该系列再添新新军DAQWare for USB-1902。该系列基于ADLINK(凌华科技)USB-1902&#xff0c;也适用JYTEK(简仪科技)USB-69102。 USB-1902简要参数&#xff1a; ■ USB2.0高速…

跟无神学AI之一文读尽Sora

openAI发布视频生成模型Sora&#xff0c;意味着人类距离AI模拟世界又近了一步&#xff0c;流浪地球2中数字人女儿也是对未来科技发展的一个缩影。 作为最具有代表性的大模型公司&#xff0c;openAI的任何一个产品都具有一定的价值&#xff0c;代表着AI的前沿发展方向。 博主今…

人工智能算法:推动未来的技术引擎

随着科技的飞速进步&#xff0c;人工智能(AI)已经渗透到我们生活的方方面面&#xff0c;从智能家居到自动驾驶汽车&#xff0c;再到医疗和金融等领域&#xff0c;AI算法的应用正日益广泛。本文将带你深入了解人工智能算法的魅力、种类以及未来趋势&#xff0c;探讨它们如何推动…

林浩然与杨凌云的Java世界奇遇记:垃圾回收大冒险

林浩然与杨凌云的Java世界奇遇记&#xff1a;垃圾回收大冒险 The Java Adventure Chronicles of Lin Haoran and Yang Lingyun: Garbage Collection Odyssey 在一个充满0和1代码森林的世界里&#xff0c;住着两位勇敢的程序员侠侣——林浩然和杨凌云。林浩然是个身怀Java绝技的…

解决 jenkins 插件下载失败问题 配置 jenkins 插件中心为国内镜像地址

从 jenkins 官网上下载的 jenkins&#xff0c;在安装的过程中&#xff0c;会有安装插件一环&#xff1a; 第一个为默认安装&#xff0c;第二个为手动 选择默认安装之后&#xff0c;会遇到&#xff1a; 安装插件失败&#xff0c;或者卡在安装插件这个地方非常久&#xff0c;久…

C++项目 -- 高并发内存池(五)释放内存过程

C项目 – 高并发内存池&#xff08;五&#xff09;释放内存过程 文章目录 C项目 -- 高并发内存池&#xff08;五&#xff09;释放内存过程一、Thread Cache释放内存1.完善FreeList功能2.Thread Cache释放内存 二、Central Cache释放内存三、Page Cache释放内存四、释放内存过程…

电脑开机需要输PIN码?教教你如何取消(Win10/Win11通用教程)

目录 方法一&#xff1a; 取消设置 方法二&#xff1a; 注&#xff1a;此系统为Win 11 方法一&#xff1a; 1.更改为本地用户 win键点击头像选择更改账户设置 在Microsof账户选择更改为本地登录 切换选择下一步&#xff0c;输入当前的账户密码 就能来到创建页面&#xff…

数据库所在服务器磁盘满了怎么办?

大家好&#xff0c;我是G探险者。 给大家拜个晚年哈&#xff0c;节后上班第一天&#xff0c;打开电脑&#xff0c;发现数据库服务器连不上了。 幸亏&#xff0c;节后第一天上班的人不太多&#xff0c;领导还没来&#xff0c;我一番鼓捣解决了这个问题。 所以做个总结&#xff0…

如何应对Android面试官->实战高级UI,用自定义View画一条锦鲤(下)

前言 上一章我们用自定义View绘制了一条小鱼&#xff0c;本章我们让这条小鱼游动起来&#xff1b; 涉及的知识点 小鱼的原地摆动 实现小鱼的摆动&#xff0c;我们可以通过属性动画 ValueAnimator 来实现&#xff0c;这里先简单介绍下属性动画 属性动画&#xff08;ValueAnima…

生成对抗网络----GAN

系列文章目录 文章目录 系列文章目录前言一、基本构成二、应用领域三、基本原理四、如何训练GAN 前言 一、基本构成 GAN (Generative Adversarial Network) : 通过两个神经网络&#xff0c;即生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#…

6.s081 学习实验记录(九)lock parallelism

文章目录 一、Memory allocator简介提示实验代码实验结果 二、Buffer cache简介提示实验代码实验结果 该实验将重构某些代码以提高并发度。 首先切换到lock分支&#xff1a; git fetchgit checkout lockmake clean 一、Memory allocator 简介 user/kalloctest 这个程序会对…

企事业单位 | 公司办公终端、电脑文件数据\资料防泄密软件系统——防止核心数据资料外泄!

天锐绿盾是一款专门设计用于防止公司文件数据泄露的软件。 PC端&#xff1a;https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 以下是该软件的几个关键特点&#xff1a; 文件加密&#xff1a;天锐绿盾使用先进的加密技术&#xff0c;对存储在电脑…

SpringIOC之support模块SimpleThreadScope

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

Dubbo框架admin搭建

Dubbo服务监控平台&#xff0c;dubbo-admin是图形化的服务管理界面&#xff0c;从服务注册中心获取所有的提供者和消费者的配置。 dubbo-admin是前后端分离的项目&#xff0c;前端使用Vue&#xff0c;后端使用springboot。因此&#xff0c;前端需要nodejs环境&#xff0c;后端需…

上百份信任印记,见证我们与客户共赴的数智化征程

回看2023&#xff0c;这注定是不平凡的一年&#xff01; 全国经济加快复苏&#xff0c;中国作为世界经济增长的压舱石&#xff0c;以5.2%的GDP增长成为全球经济发展的稳定力量。 国务院印发《数字中国建设整体布局规划》&#xff0c;从政府到央国企&#xff0c;从行业领头羊到…

【Git】上传本地文件到Git(以Windows环境为例)

Git 的下载参考&#xff1a;Git 安装及配置 一、Git 上传的整体流程 1、工作区 > 本地仓库 将本地文件上传到Git&#xff0c;需要先上传到本地仓库&#xff0c;然后再上传到远程仓库。要上传文件到本地仓库&#xff0c;不是直接拷贝进去的&#xff0c;而是需要通过命令一步…

LLM应用开发与落地:chroma的近似搜索问题

背景 最近开始测试一个游戏客户的RAG模块&#xff0c;发现一个向量数据库中大家容易忽略的一个点&#xff1a;近邻搜索算法。一开始我们选择的是chroma作为向量数据库&#xff0c;因为chroma的用户接口和设计非常简单&#xff0c;而我偏向于简单。创建collection时设置的距离计…

stable-video-diffusion 图生视频模型diffusers使用案例

T4卡16g运行: 参考:https://huggingface.co/docs/diffusers/main/en/using-diffusers/text-img2vid 案例用的google colab T4显卡运行 安装包:pip install diffusers accelerate 代码 import torch from diffusers import StableVideoDiffusionPipeline from diffusers.uti…