uniapp 选择城市区号索引列表实现

最近接到一个注册支持各国手机号的需求,需要进行区号的选择,于是我想到了索引列表,但是我们的项目是 uniapp 项目,找了一下,没有现成的组件,一番挠头,经过查资料,最终实现如下组件。

  1. 再 components 文件夹下创建 citySelect.vue 组件,代码如下:
javascript 复制代码
<template>
  <view>
    <uni-popup
      ref="popup"
      background-color="#fff"
      border-radius="20px 20px 0 0"
    >
      <view style="height: 88vh">
        <view class="wrapper">
          <view class="header">
            <!-- 这里可以换成一个图片 -->
            <text class="icon-close" @click="close">X</text>
          </view>
          <scroll-view
            class="calendar-list"
            scroll-y="true"
            :scroll-into-view="scrollIntoId"
            @scroll="onScroll"
          >
            <!-- 最近访问的城市 -->
            <view id="hot">
              <view class="hot_wrapper" v-if="Visit.length > 0">
                <view class="hot_city hot_city_zuijin">
                  <view
                    class="hot_city_one toright"
                    v-for="(item, index) in Visit"
                    :key="index"
                    v-show="index < 2"
                    @click="back_city(item)"
                  >
                    {{ item.cityName }}(+{{ item.code }})
                  </view>
                </view>
              </view>
            </view>

            <!-- 城市列表 -->
            <view v-for="(item, index) in list" :id="getId(index)" :key="index">
              <view class="letter-header" v-if="item[0]">{{
                getId(index)
              }}</view>
              <view
                class="city-div"
                v-for="(city, i) in item"
                :key="i"
                @click="back_city(city)"
              >
                <text class="city">{{ city.cityName }} (+{{ city.code }})</text>
              </view>
            </view>
          </scroll-view>

          <!-- 右侧字母栏 -->
          <view
            class="letters"
            @touchstart="onTouchStart"
            @touchmove="onTouchMove"
            @touchend="onTouchEnd"
          >
            <view
              v-for="item in letter"
              :key="item"
              class="letters-item"
              @click.stop="scrollTo(item)"
              :class="{ 'letters-item--active': selectedLetter === item }"
            >
              {{ item }}
            </view>
          </view>

          <!-- 选中之后字母 -->
          <view class="mask" v-if="showMask && selectedLetter">
            <view class="mask-r">{{ selectedLetter }}</view>
          </view>
        </view>
      </view>
    </uni-popup>
  </view>
</template>
<script>
import cityAreaList from "@/components/city";
import pinyin from "pinyin";
export default {
  data() {
    return {
      letter: [],
      scrollIntoId: "",
      list: [],
      showMask: false,
      Visit: [], // 最近访问
      selectedLetter: "", // 存储当前选中的字母
      letterOffsets: [], // 存储每个字母区的偏移量
      touchActive: false, // 标记是否正在触摸
    };
  },
  created() {
    this.getPhonePrefix();
    // 获取存储的最近访问
    uni.getStorage({
      key: "Visit_key",
      success: (res) => {
        this.Visit = res.data || [];
      },
    });
  },
  mounted() {
    // 初始化后计算每个字母区的偏移量
    this.$nextTick(() => {
      this.calculateLetterOffsets();
    });
  },
  watch: {
    list: {
      handler(newVal) {
        if (newVal && newVal.length > 0) {
          this.$nextTick(() => {
            this.calculateLetterOffsets();
          });
        }
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    getPhonePrefix() {
      // 这里可以换成你的获取城市区域的接口
      setTimeout(() => {
        this.citys = cityAreaList.map((v) => ({
          cityName: v.areaName,
          code: v.areaCode,
          py: this.getFirstLetter(v.areaName),
        }));
        // 初始化字母列表和城市列表
        const mu = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'q', 'r', 's', 't', 'w', 'x', 'y', 'z'];
        this.letter = mu.map((item) => item.toUpperCase());
        this.list = Array.from({ length: mu.length }, () => []);
        mu.forEach((item, i) => {
          this.citys.forEach((city) => {
            if (city.py && city.py.substring(0, 1).toLowerCase() === item) {
              this.list[i].push(city);
            }
          });
        });
      });
    },
    getFirstLetter(chineseText) {
      const pinyinArray = pinyin(chineseText, {
        style: pinyin.STYLE_FIRST_LETTER,
      });
      return pinyinArray.flat().join("").toLowerCase();
    },
    toggle() {
      this.$refs.popup.open("bottom");
    },
    close() {
      this.$refs.popup.close();
    },
    getId(index) {
      return this.letter[index];
    },
    scrollTo(letterItem) {
      this.showMask = true;
      this.selectedLetter = letterItem; // 更新选中的字母
      setTimeout(() => {
        this.showMask = false;
      }, 300);
      const index = this.letter.findIndex((v) => v == letterItem);
      if (!this.list[index]?.length) return;
      this.scrollIntoId = letterItem;
    },
    query(source, text) {
      return source.filter((item) => {
        return Object.values(item).some((val) =>
          String(val).toLowerCase().includes(text.toLowerCase())
        );
      });
    },
    back_city(item) {
      if (item) {
        this.$emit("back_city", item);
        this.Visit.unshift(item); // unshift 把数据插入到首位,与 push 相反
        const distinctArr = [...new Set(this.Visit)]; // 数组去重
        this.Visit = distinctArr;
        // 存储最近访问的城市
        uni.setStorage({
          key: "Visit_key",
          data: this.Visit,
        });
      } else {
        this.$emit("back_city", "no");
      }
    },
    // 计算每个字母区的偏移量
    calculateLetterOffsets() {
      this.letterOffsets = [];
      // 获取所有字母区块
      this.letter.forEach((letter) => {
        const sectionElement = this.$el.querySelector(`#${letter}`);
        if (sectionElement && sectionElement.offsetHeight) {
          this.letterOffsets.push({
            id: letter,
            offset: sectionElement.offsetTop,
          });
        }
      });
      // 按偏移量排序
      this.letterOffsets.sort((a, b) => a.offset - b.offset);
    },
    // 监听滚动事件
    onScroll(event) {
      if (this.touchActive) return; // 如果正在触摸,不触发自动高亮
      const scrollTop = event.detail.scrollTop;
      // 查找当前滚动位置对应的字母
      let matchedLetter = null;
      for (let i = this.letterOffsets.length - 1; i >= 0; i--) {
        if (scrollTop >= this.letterOffsets[i].offset) {
          matchedLetter = this.letterOffsets[i].id;
          break;
        }
      }
      // 如果没有匹配的字母,则取消高亮
      if (matchedLetter) {
        if (this.selectedLetter !== matchedLetter) {
          this.selectedLetter = matchedLetter;
        }
      } else {
        if (this.selectedLetter !== "") {
          this.selectedLetter = "";
        }
      }
    },
    // 触摸开始
    onTouchStart(event) {
      this.touchActive = true;
      this.handleTouch(event);
    },
    // 触摸移动
    onTouchMove(event) {
      event.preventDefault(); // 阻止默认行为,防止页面滚动
      this.handleTouch(event);
    },
    // 触摸结束
    onTouchEnd(event) {
      this.touchActive = false;
    },
    // 处理触摸事件,计算对应的字母
    handleTouch(event) {
      const touches = event.touches;
      if (touches.length > 0) {
        const touch = touches[0];
        const lettersElement = this.$el.querySelector(".letters");
        const lettersRect = lettersElement.getBoundingClientRect();
        const relativeY = touch.clientY - lettersRect.top;
        const lettersHeight = lettersRect.height;
        const totalItems = this.letter.length + 1;
        const itemHeight = lettersHeight / totalItems;
        const index = Math.floor(relativeY / itemHeight);
        if (index >= 0 && index < totalItems) {
          const targetLetter = this.letter[index - 1];
          this.scrollTo(targetLetter);
        }
      }
    },
  },
};
</script>
<style scoped>
.wrapper {
  position: fixed;
  z-index: 999999;
  background: #ffffff;
  height: 100%;
  width: 100%;
  top: 0px;
  left: 0px;
  border-radius: 20px 20px 0 0;
}

.mask {
  position: absolute;
  bottom: 0upx;
  top: 83upx;
  left: 0upx;
  right: 0upx;
  width: 750upx;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgba(0, 0, 0, 0);
}

.mask-r {
  height: 120upx;
  width: 120upx;
  border-radius: 60upx;
  display: flex;
  background: rgba(0, 0, 0, 0.5);
  justify-content: center;
  align-items: center;
  font-size: 40upx;
  color: #ffffff;
}

.header {
  height: 85upx;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 20upx;
  box-sizing: border-box;
}

.calendar-list {
  position: absolute;
  top: 83upx;
  bottom: 0upx;
  width: 100%;
  background-color: #ffffff;
}

.letters {
  position: absolute;
  right: 30upx;
  bottom: 0px;
  width: 50upx;
  top: 290upx;
  color: #2f9bfe;
  text-align: center;
  font-size: 24upx;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 增加触摸区域 */
  height: fit-content;
}

.letters-item {
  margin-bottom: 5upx;
  cursor: pointer;
  transition: background-color 0.2s;
  width: 32upx;
  height: 32upx;
  line-height: 32upx;
  text-align: center;
  border-radius: 50%;
}

.letters-item--active {
  background-color: #2f9bfe;
  color: #ffffff;
}

.letter-header {
  height: 45upx;
  font-size: 22upx;
  color: #333333;
  padding-left: 24upx;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  background-color: #ebedef;
}

.city-div {
  width: 660upx;
  height: 85upx;
  margin-left: 24upx;
  border-bottom-width: 0.5upx;
  border-bottom-color: #ebedef;
  border-bottom-style: solid;
  display: flex;
  align-items: center;
  margin-right: 35upx;
}

.city {
  font-size: 28upx;
  color: #000000;
  padding-left: 30upx;
}

.hot_wrapper {
  width: 100%;
  padding-top: 10upx;
  box-sizing: border-box;
  margin-bottom: 26upx;
}

.hot_city {
  width: 100%;
  height: 60upx;
  padding-left: 55upx;
  padding-right: 70upx;
  box-sizing: border-box;
  display: flex;
  justify-content: space-between;
}

.hot_city_one {
  width: auto;
  min-width: 130upx;
  padding: 0 8upx;
  background-color: #f5f5f5;
  border-radius: 10upx;
  font-size: 24upx;
  color: #333333;
  display: flex;
  justify-content: center;
  align-items: center;
}

.hot_city_zuijin {
  display: flex;
  justify-content: flex-start;
}

.toright {
  margin-right: 25upx;
}

.icon-close {
  width: 50upx;
  height: 50upx;
  position: absolute;
  top: 30upx;
  right: 5upx;
}
.uni-popup {
  z-index: 1000;
}
</style>
  1. 为了方便演示,我直接再 components 文件夹下放了一个 city.js 文件,用来存放城市区号的 json 数据,如下:
javascript 复制代码
export default [
    { "areaName": "中国", "areaCode": "86" },
    { "areaName": "日本", "areaCode": "81" },
    { "areaName": "韩国", "areaCode": "82" },
    { "areaName": "朝鲜", "areaCode": "850" },
    { "areaName": "蒙古国", "areaCode": "976" },
    { "areaName": "越南", "areaCode": "84" },
    { "areaName": "老挝", "areaCode": "856" },
    { "areaName": "柬埔寨", "areaCode": "855" },
    { "areaName": "泰国", "areaCode": "66" },
    { "areaName": "缅甸", "areaCode": "95" },
    { "areaName": "马来西亚", "areaCode": "60" },
    { "areaName": "新加坡", "areaCode": "65" },
    { "areaName": "印度尼西亚", "areaCode": "62" },
    { "areaName": "菲律宾", "areaCode": "63" },
    { "areaName": "文莱", "areaCode": "673" },
    { "areaName": "东帝汶", "areaCode": "670" },
    { "areaName": "印度", "areaCode": "91" },
    { "areaName": "巴基斯坦", "areaCode": "92" },
    { "areaName": "孟加拉国", "areaCode": "880" },
    { "areaName": "斯里兰卡", "areaCode": "94" },
    { "areaName": "尼泊尔", "areaCode": "977" },
    { "areaName": "不丹", "areaCode": "975" },
    { "areaName": "马尔代夫", "areaCode": "960" },
    { "areaName": "伊朗", "areaCode": "98" },
    { "areaName": "伊拉克", "areaCode": "964" },
    { "areaName": "叙利亚", "areaCode": "963" },
    { "areaName": "约旦", "areaCode": "962" },
    { "areaName": "沙特阿拉伯", "areaCode": "966" },
    { "areaName": "阿联酋", "areaCode": "971" },
    { "areaName": "卡塔尔", "areaCode": "974" },
    { "areaName": "阿曼", "areaCode": "968" },
    { "areaName": "以色列", "areaCode": "972" },
    { "areaName": "土耳其", "areaCode": "90" },
    { "areaName": "黎巴嫩", "areaCode": "961" },
    { "areaName": "也门", "areaCode": "967" },
    { "areaName": "塞浦路斯", "areaCode": "357" },
    { "areaName": "巴勒斯坦", "areaCode": "970" },
    { "areaName": "哈萨克斯坦", "areaCode": "7" },
    { "areaName": "乌兹别克斯坦", "areaCode": "998" },
    { "areaName": "土库曼斯坦", "areaCode": "993" },
    { "areaName": "吉尔吉斯斯坦", "areaCode": "996" },
    { "areaName": "塔吉克斯坦", "areaCode": "992" },
    { "areaName": "英国", "areaCode": "44" },
    { "areaName": "法国", "areaCode": "33" },
    { "areaName": "德国", "areaCode": "49" },
    { "areaName": "荷兰", "areaCode": "31" },
    { "areaName": "比利时", "areaCode": "32" },
    { "areaName": "瑞士", "areaCode": "41" },
    { "areaName": "奥地利", "areaCode": "43" },
    { "areaName": "爱尔兰", "areaCode": "353" },
    { "areaName": "卢森堡", "areaCode": "352" },
    { "areaName": "挪威", "areaCode": "47" },
    { "areaName": "瑞典", "areaCode": "46" },
    { "areaName": "丹麦", "areaCode": "45" },
    { "areaName": "芬兰", "areaCode": "358" },
    { "areaName": "冰岛", "areaCode": "354" },
    { "areaName": "法罗群岛", "areaCode": "298" },
    { "areaName": "俄罗斯", "areaCode": "7" },
    { "areaName": "波兰", "areaCode": "48" },
    { "areaName": "捷克", "areaCode": "420" },
    { "areaName": "斯洛伐克", "areaCode": "421" },
    { "areaName": "匈牙利", "areaCode": "36" },
    { "areaName": "罗马尼亚", "areaCode": "40" },
    { "areaName": "保加利亚", "areaCode": "359" },
    { "areaName": "希腊", "areaCode": "30" },
    { "areaName": "意大利", "areaCode": "39" },
    { "areaName": "西班牙", "areaCode": "34" },
    { "areaName": "葡萄牙", "areaCode": "351" },
    { "areaName": "克罗地亚", "areaCode": "385" },
    { "areaName": "斯洛文尼亚", "areaCode": "386" },
    { "areaName": "塞尔维亚", "areaCode": "381" },
    { "areaName": "黑山", "areaCode": "382" },
    { "areaName": "阿尔巴尼亚", "areaCode": "355" },
    { "areaName": "马耳他", "areaCode": "356" },
    { "areaName": "圣马力诺", "areaCode": "378" },
    { "areaName": "梵蒂冈", "areaCode": "379" },
    { "areaName": "摩纳哥", "areaCode": "377" },
    { "areaName": "安道尔", "areaCode": "376" },
    { "areaName": "列支敦士登", "areaCode": "423" },
    { "areaName": "波黑", "areaCode": "387" },
    { "areaName": "北马其顿", "areaCode": "389" },
    { "areaName": "摩尔多瓦", "areaCode": "373" },
    { "areaName": "白俄罗斯", "areaCode": "375" },
    { "areaName": "乌克兰", "areaCode": "380" },
    { "areaName": "埃及", "areaCode": "20" },
    { "areaName": "摩洛哥", "areaCode": "212" },
    { "areaName": "阿尔及利亚", "areaCode": "213" },
    { "areaName": "突尼斯", "areaCode": "216" },
    { "areaName": "利比亚", "areaCode": "218" },
    { "areaName": "苏丹", "areaCode": "249" },
    { "areaName": "南苏丹", "areaCode": "211" },
    { "areaName": "尼日利亚", "areaCode": "234" },
    { "areaName": "加纳", "areaCode": "233" },
    { "areaName": "科特迪瓦", "areaCode": "225" },
    { "areaName": "塞内加尔", "areaCode": "221" },
    { "areaName": "喀麦隆", "areaCode": "237" },
    { "areaName": "刚果(布)", "areaCode": "242" },
    { "areaName": "刚果(金)", "areaCode": "243" },
    { "areaName": "肯尼亚", "areaCode": "254" },
    { "areaName": "坦桑尼亚", "areaCode": "255" },
    { "areaName": "埃塞俄比亚", "areaCode": "251" },
    { "areaName": "索马里", "areaCode": "252" },
    { "areaName": "乌干达", "areaCode": "256" },
    { "areaName": "卢旺达", "areaCode": "250" },
    { "areaName": "莫桑比克", "areaCode": "258" },
    { "areaName": "马达加斯加", "areaCode": "261" },
    { "areaName": "南非", "areaCode": "27" },
    { "areaName": "博茨瓦纳", "areaCode": "267" },
    { "areaName": "纳米比亚", "areaCode": "264" },
    { "areaName": "津巴布韦", "areaCode": "263" },
    { "areaName": "赞比亚", "areaCode": "260" },
    { "areaName": "毛里求斯", "areaCode": "230" },
    { "areaName": "塞舌尔", "areaCode": "248" },
    { "areaName": "圣赫勒拿", "areaCode": "290" },
    { "areaName": "厄立特里亚", "areaCode": "291" },
    { "areaName": "吉布提", "areaCode": "253" },
    { "areaName": "乍得", "areaCode": "235" },
    { "areaName": "尼日尔", "areaCode": "227" },
    { "areaName": "布基纳法索", "areaCode": "226" },
    { "areaName": "几内亚", "areaCode": "224" },
    { "areaName": "贝宁", "areaCode": "229" },
    { "areaName": "多哥", "areaCode": "228" },
    { "areaName": "冈比亚", "areaCode": "220" },
    { "areaName": "佛得角", "areaCode": "238" },
    { "areaName": "赤道几内亚", "areaCode": "240" },
    { "areaName": "加蓬", "areaCode": "241" },
    { "areaName": "圣多美和普林西比", "areaCode": "239" },
    { "areaName": "马拉维", "areaCode": "265" },
    { "areaName": "莱索托", "areaCode": "266" },
    { "areaName": "斯威士兰", "areaCode": "268" },
    { "areaName": "科摩罗", "areaCode": "269" },
    { "areaName": "留尼汪", "areaCode": "262" },
    { "areaName": "马约特", "areaCode": "262" },
    { "areaName": "英属印度洋领地", "areaCode": "246" },
    { "areaName": "阿森松岛", "areaCode": "247" },
    { "areaName": "美国", "areaCode": "1" },
    { "areaName": "加拿大", "areaCode": "1" },
    { "areaName": "墨西哥", "areaCode": "52" },
    { "areaName": "古巴", "areaCode": "53" },
    { "areaName": "海地", "areaCode": "509" },
    { "areaName": "牙买加", "areaCode": "1-876" },
    { "areaName": "巴哈马", "areaCode": "1-242" },
    { "areaName": "巴巴多斯", "areaCode": "1-246" },
    { "areaName": "安提瓜和巴布达", "areaCode": "1-268" },
    { "areaName": "格林纳达", "areaCode": "1-473" },
    { "areaName": "圣卢西亚", "areaCode": "1-758" },
    { "areaName": "特立尼达和多巴哥", "areaCode": "1-868" },
    { "areaName": "波多黎各", "areaCode": "1-787/939" },
    { "areaName": "开曼群岛", "areaCode": "1-345" },
    { "areaName": "百慕大", "areaCode": "1-441" },
    { "areaName": "美属维尔京群岛", "areaCode": "1-340" },
    { "areaName": "英属维尔京群岛", "areaCode": "1-284" },
    { "areaName": "蒙特塞拉特", "areaCode": "1-664" },
    { "areaName": "荷属圣马丁", "areaCode": "1-721" },
    { "areaName": "特克斯和凯科斯群岛", "areaCode": "1-649" },
    { "areaName": "圣基茨和尼维斯", "areaCode": "1-869" },
    { "areaName": "圣文森特和格林纳丁斯", "areaCode": "1-784" },
    { "areaName": "多米尼克", "areaCode": "1-767" },
    { "areaName": "安圭拉", "areaCode": "1-264" },
    { "areaName": "多米尼加", "areaCode": "1-809/829/849" },
    { "areaName": "关岛", "areaCode": "1-671" },
    { "areaName": "北马里亚纳群岛", "areaCode": "1-670" },
    { "areaName": "美属萨摩亚", "areaCode": "1-684" },
    { "areaName": "阿根廷", "areaCode": "54" },
    { "areaName": "巴西", "areaCode": "55" },
    { "areaName": "智利", "areaCode": "56" },
    { "areaName": "哥伦比亚", "areaCode": "57" },
    { "areaName": "秘鲁", "areaCode": "51" },
    { "areaName": "委内瑞拉", "areaCode": "58" },
    { "areaName": "玻利维亚", "areaCode": "591" },
    { "areaName": "厄瓜多尔", "areaCode": "593" },
    { "areaName": "巴拉圭", "areaCode": "595" },
    { "areaName": "乌拉圭", "areaCode": "598" },
    { "areaName": "圭亚那", "areaCode": "592" },
    { "areaName": "苏里南", "areaCode": "597" },
    { "areaName": "法属圭亚那", "areaCode": "594" },
    { "areaName": "澳大利亚", "areaCode": "61" },
    { "areaName": "新西兰", "areaCode": "64" },
    { "areaName": "巴布亚新几内亚", "areaCode": "675" },
    { "areaName": "斐济", "areaCode": "679" },
    { "areaName": "所罗门群岛", "areaCode": "677" },
    { "areaName": "瓦努阿图", "areaCode": "678" },
    { "areaName": "汤加", "areaCode": "676" },
    { "areaName": "萨摩亚", "areaCode": "685" },
    { "areaName": "基里巴斯", "areaCode": "686" },
    { "areaName": "密克罗尼西亚联邦", "areaCode": "691" },
    { "areaName": "马绍尔群岛", "areaCode": "692" },
    { "areaName": "瑙鲁", "areaCode": "674" },
    { "areaName": "帕劳", "areaCode": "680" },
    { "areaName": "图瓦卢", "areaCode": "688" },
    { "areaName": "纽埃", "areaCode": "683" },
    { "areaName": "库克群岛", "areaCode": "682" },
    { "areaName": "法属波利尼西亚", "areaCode": "689" },
    { "areaName": "新喀里多尼亚", "areaCode": "687" },
    { "areaName": "托克劳", "areaCode": "690" },
    { "areaName": "皮特凯恩群岛", "areaCode": "64" }
]
  1. 最后,再页面中进行组件的使用,代码如下:
javascript 复制代码
<template>
  <view>
    <view class="nationalAreaCode">
      <text @click="$refs.popupRef.toggle('bottom')">
        +{{nationalAreaCode}}
        <uni-icons type="down" size="30" style="display:inline-block;font-size:28rpx"></uni-icons>
      </text>
    </view>
    <citySelect @back_city="back_city" ref="popupRef"/>
  </view>
</template>
<script>
	import citySelect from '../../components/citySelect.vue';
  export default {
    components: { citySelect },
    data() {
			return {
        nationalAreaCode: '86',
			}
		},
    methods: {
			back_city(e) { 
				if (e !== 'no') { 
					this.nationalAreaCode = e.code 
					this.$refs.popupRef.close(); 
				} else { 
					this.$refs.popupRef.close(); 
				} 
			},
    }
  }
</script>
<style scoped>
.nationalAreaCode{
  padding: 40rpx;
  background: #fff;
}
</style>

最终效果如下:

相关推荐
大圣编程13 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang13 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆13 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜14 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞15 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农18 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_9437823518 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq18 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net
吠品18 小时前
LangChain 里 tool_call_id 为空?一次 MCP 工具集成的排查记录
前端