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>

最终效果如下:

相关推荐
阿珊和她的猫2 小时前
简述 React 的虚拟 DOM 机制
前端·react.js·前端框架
梵得儿SHI2 小时前
Vue 高级特性:混入(Mixin)使用场景与问题、Vue3 组合式 API 替代方案精讲
前端·javascript·vue.js·组合式api·参数传递·mixin机制·显式调用
qq_336313932 小时前
javaweb-HTML和CSS(2)
前端·css·html
Sapphire~2 小时前
【模板】Jinja风格 Ruby风格
前端·后端
火星数据-Tina2 小时前
体育平台搭建:如何高效引入赛事直播与比分数据
大数据·前端·网络
RichardLau_Cx2 小时前
Google Chrome 浏览器安装「豆包插件」完整教程
前端·chrome·插件·豆包
stereohomology2 小时前
Typora中绕过主题html方式自定义字体的一个设置问题
前端·html
_OP_CHEN2 小时前
【前端开发之CSS】(四)CSS 常用元素属性宝典(下):背景与圆角进阶指南,让页面颜值飙升!
前端·css·html·页面开发·gui开发·css元素属性
光影少年2 小时前
react和vue多个组件在一个页面展示不同内容都是请求一个接口,如何优化提升率性能
前端·vue.js·react.js