去哪儿项目

本文详细介绍了如何在Vue中封装组件,包括头部组件、轮播图组件和图标列表组件,并展示了它们的父子组件交互。同时,文章还涵盖了城市选择页面的实现,包括搜索组件和城市列表组件,以及滚动监听和定位功能。此外,还涉及到了详情页的布局设计,如轮播图、标题栏和详情列表。
摘要由CSDN通过智能技术生成

首页

封装头部子组件,需要用到插槽

子组件:

<div class="top">
      <slot name="left"></slot>
      <slot name="center"></slot>
      <slot name="right"></slot>
 </div>
<style lang="stylus" scoped>
@import '~styles/minxins.styl';
.top{
    align-items center
    height 1rem
    width 100%
    display flex
    color #fff
    bg()
    .left{
        width .8rem
        text-align center
    }
    .con{
        flex 1
    }
    .right{
        padding 0 .2rem
    }
}
</style>

父组件引入使用

<script>
import mytop from '@/components/mytop'
components: {
   mytop,
 },
</script>
 <mytop class="mtop">
      <template v-slot:left>
        <span class="left iconfont">
         &#xe605;
        </span>
      </template>
      <template v-slot:center>
        <div class="con">
          <i class="iconfont search">
            &#xe634;
          </i>
          <input type="text" placeholder="输入城市/景点/游玩主题">
        </div>
      </template>
      <template v-slot:right>
        <div class="right" @click="gocity">
          {{cityval}}
          <i class="iconfont icon-jiantouxia"></i>
        </div>
      </template>
    </mytop>
.mtop{
  .left{
    font-size .6rem
  }
  .con{
    // flex 1
    color #ccc
    position relative
    .search{
      position absolute
      font-size .4rem
      left .2rem
      margin-top .1rem
    }
    input{
      padding-left .8rem
      height .6rem
      width 100%
      border-radius .1rem 
      box-sizing border-box
      font-size .28rem
    }
  }
}

封装swipers子组件

子组件:

<template>
  <div>
      <div class="warp">
          <swiper :options="swiperOption">
	<swiper-slide v-for="item in swiperList" :key="item.id">
    <img :src="item.imgUrl" alt="">
	</swiper-slide>
	<div class="swiper-pagination"  slot="pagination"></div>
</swiper>
</div>
 </div>
</template>

<script>
export default {
  props: ["swiperList"],
  data() {
    return {
      swiperOption: {
        autoplay: 5000,
        initialSlide: 1,
        pagination: ".swiper-pagination",
        observeParents: true,
        observer: true
      }
    };
  },
  methods: {},
  created() {},
  mounted() {},
  components: {},
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
.warp {
  overflow: hidden;
  width: 100%;
  height: 0;
  padding-bottom: 26.67%;
  background: pink;
}

.warp>>>img {
  width: 100%;
  height: 2rem;
}
</style>

封装iconlist子组件

子组件:

<template>
  <div>
        <div class="icons">
    <swiper >
      <swiper-slide v-for="(page,index) in pages" :key="index">
        <div class="icon" v-for="item in page" :key="item.id">
          <div class="icon-img">
            <img class="icon-img-content" :src="item.imgUrl" >
          </div>          
          <p class="icon-desc">{{item.desc}}</p>
        </div>
      </swiper-slide>
    </swiper> 
</div>
 </div>
</template>

<script>
export default {
  data() {
    return {
      swiperOption: {
        autoplay: 5000,
        initialSlide: 1,
        pagination: ".swiper-pagination",
        observeParents: true,
        observer: true
      },
      iconList:[]
    };
  },
  methods: {},
  created() {
    this.$axios.get("/static/index.json").then(res => {
      console.log(res);
      this.iconList = res.data.data.iconList;
    });
  },
  mounted() {},
  components: {},
  computed: {
    pages() {
      const pages = [];
      this.iconList.forEach((item, index) => {
        const page = Math.floor(index / 8);
        if (!pages[page]) {
          pages[page] = [];
        }
        pages[page].push(item);
      });
      return pages;
    }
  },
  watch: {}
};
</script>

<style lang='stylus' scoped>
.icons >>> .swiper-container {
    height: 0;
    padding-bottom: 50%;
}

.icon {
    position: relative;
    overflow: hidden;
    float: left;
    width: 25%;
    height: 0;
    padding-bottom: 25%;

    .icon-img {
        position: absolute;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0.44rem;
        // background :blue
        box-sizing: border-box;
        padding: 0.05rem;

        .icon-img-content {
            display: block;
            margin: 0 auto;
            height: 100%;
        }
    }

    .icon-desc {
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        height: 0.44rem;
        line-height: 0.44rem;
        text-align: center;
        color: #333;
    }
}
</style>

父组件:

<script>
import iconlist from '@/components/iconlist/iconlist.vue'
components: {
   mytop,
   iconlist
 },
</script>

父传子

需要给子组件标签定义自定义属性绑定需要传递的数据进行传递,在子组件中通过props接收

子传父

需要给子组件标签定义自定义事件,子组件中通过this.$emit(‘父组件中自定义事件名’,需要传递的值)传递,父组件中接收到的数据在自定义事件的参数中 : 方法名(子组件传过来的参数){}

详情页

详情页主页

<template>
  <div>
<banner :gallaryImgs="gallaryImgs"></banner>
<myheader ></myheader>
<div class="conter">
  <detailList :categoryList="categoryList"></detailList>
</div>
 </div>
</template>

<script>
import banner from "@/components/detail/Banner";
import myheader from "@/components/detail/myheader";
import detailList from "@/components/detail/detailList";
export default {
  data() {
    return {
      info: {},
      flag: false,
      gallaryImgs: [],
      categoryList:[]
    };
  },
  methods: {
  
  },
  created() {
    this.$axios.get("/static/detail.json").then(res => {
      console.log(res);
      this.info = res.data.data;
      this.gallaryImgs = res.data.data.gallaryImgs;
      this.categoryList=res.data.data.categoryList
    });

  },
  mounted() {

  },
  components: {
    banner,
    myheader,
    detailList
  },
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
.conter {
  height: 50rem;
}
</style>

myheader子组件

<template>
  <div >

<div>
	<router-link  to="/" class="top" v-show="!flag">
		<div class="iconfont con">&#xe605;</div>
	</router-link> 

	<div class="header-fixed" v-show="flag" :style="opacityStyle">
	<router-link to="/">
		<div class="iconfont header-fixed-back">&#xe624;</div>
	</router-link>
	景点详情
</div>  
</div>
 </div>
</template>

<script>
export default {
  data() {
    return {
      flag: false,
      opacityStyle: {
        opacity: 0
      }
    };
  },
  methods: {
    handleScroll() {
      const top = window.pageYOffset;
      if (top > 50) {
        let opacity = top / 140;
        opacity = opacity > 1 ? 1 : opacity;
        this.opacityStyle = { opacity };
      
        this.flag = true;
      } else {
        this.flag = false;
      }
    }
  },
  created() {},
  mounted() {
    window.addEventListener("scroll", this.handleScroll);
  },
  components: {},
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
@import '~styles/minxins.styl';

.top {
  position: absolute;
  left: 0.2rem;
  top: 0.2rem;
  width: 0.8rem;
  line-height: 0.8rem;
  border-radius: 0.4rem;
  text-align: center;
  background: rgba(0, 0, 0, 0.8);

  .con {
    color: #fff;
    font-size: 0.4rem;
  }
}

.header-fixed {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  text-align: center;
  color: #fff;
  background: $bgColor;
  font-size: 0.32rem;
  height: 1rem;
  line-height: 1rem;
  bg();

  .header-fixed-back {
    position: absolute;
    top: 0;
    left: 0;
    width: 0.64rem;
    text-align: center;
    font-size: 0.4rem;
    color: #fff;
  }
}
</style>

banner子组件


      <template>
    <div class="banner">
        <img @click="flag=true" class="banner-img" :src="gallaryImgs[0]" >
        <div class="banner-con">
            <div class="banner-title">
                大连圣亚海洋世界(AAAA景区)
            </div>
            <div class="banner-number">
                <span class="iconfont" >&#xe618;</span>
                {{gallaryImgs.length}}
            </div>
        </div>
    <gallary v-if="flag" :gallaryImgs="gallaryImgs" @ShutDown="ShutDown"></gallary>
 </div>
</template>

<script>
import gallary from "@/components/detail/Gallary";
export default {
  props: ["gallaryImgs"],
  data() {
    return {
        flag:false
    };
  },
  methods: {
      ShutDown(){
          this.flag=false
      }
  },
  created() {},
  mounted() {},
  components: {
      gallary
  },
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>

.banner {
    position: relative;
    overflow: hidden;
    height: 0;
    padding-bottom: 55%;
    
    .banner-img {
        width: 100%;
        margin-top: -1.4rem;
        height: 5.6rem;
    }
    .banner-con {
        display: flex;
        align-items center
        justify-content space-between
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
        line-height: 0.6rem;
        color: #fff;
        background-image: linear-gradient(top, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.8));

        .banner-tittle {
            flex: 1;
            font-size: 0.32rem;
            padding: 0 0.2rem;
        }

        .banner-number {
            height: .4rem;
            display flex
            
            align-items center
            padding: 0 0.4rem;
            border-radius: 0.2rem;
            background: rgba(0, 0, 0, 0.8);
            font-size: 0.24rem;
            .banner-icon {
                font-size: 0.24rem;
            }
        }
    }
}
</style>

Gallary子组件

<template>
  <div>
      <div class="gallary">
	<div @click="ShutDown" class="wrap">
		<swiper :options="swiperOption">               
			<swiper-slide v-for="(item, index) in gallaryImgs" :key="index">    
				<img  class="swiper-img" :src="item" >
			</swiper-slide>
			<div class="swiper-pagination"  slot="pagination"></div>      
		</swiper>   
	</div>
</div>
 </div>
</template>

<script>
export default {
  props: ["gallaryImgs"],
  data() {
    return {
      swiperOption: {
        autoplay: 5000,
        initialSlide: 1,
     
        paginationType: 'fraction',
        pagination: ".swiper-pagination",
        observeParents: true,
        observer: true 
      }
    };
  },
  methods: {
    ShutDown() {
      this.$emit("ShutDown");
      
    },
  
  },
  created() {},
  mounted() {
      
  },
  components: {},
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
.gallary {
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: fixed;
    left: 0;
    right: 0;
    top: 0;
    bottom: 0;
    background: #000;
    z-index 1;
    .wrap {
     
        overflow: hidden;
        height: 0;
        width: 100%;
        padding-bottom: 100%;

        .swiper-img {
            width: 100%;
        }
    }
}
</style>

detailList子组件

<template>
  <div>
      <ul class="categoryList">
        <li class="categoryList-item" v-for="(item, index) in categoryList" :key="index">
          <p class="item.item"> <i class="iconfont">&#xe642;</i>{{item.title}}</p>
          <ul class="item-children" v-if="item.children">
            <li class="children-ele" v-for="(ele, i) in item.children" :key="i">
              <p class="ele-title"> <i class="iconfont">&#xe642;</i>{{ele.title}}</p>
              <ul class="ele-children" v-if="ele.children">
                <li class="children-con" v-for="(con, ind) in ele.children" :key="ind">
                  <p class="con-title"> <i class="iconfont">&#xe642;</i>{{con.title}}</p>
                </li>
              </ul>
            </li>
          </ul>
        </li>
      </ul>
 </div>
</template>

<script>
export default {
  props: ["categoryList"],
  data() {
    return {};
  },
  methods: {},
  created() {},
  mounted() {},
  components: {},
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
ul {
  padding: 0 0.2rem;
}

p {
  border-bottom: 0.02rem solid #ccc;
  line-height: 1rem;
  font-size: 0.32rem;

  i {
    margin-right: 0.2rem;
    color: #05b9d2;
  }
}
</style>

城市页

主页:

<template>
  <div>
      <search class="header" @changeflag="changeflag" :cities="cities"></search>
<div class="wrap" v-if="flag">
    <!--      
      <div class="header">
          <div class="top">
              <i class="iconfont"> &#xe605;</i>
              <span>城市选择</span>
              <i></i>
          </div>
            <div class="bottom">
                  <input type="text" placeholder="输入城市名或拼音">
            </div>
      </div> -->
      <p class="title">当前城市</p>
        <div class="city">
           <span @click="gohome(city)"> {{city}}</span>
        </div>
      <p class="title">热门城市</p>
      <ul class="hotCities">
          <li @click="gohome(item.name)" v-for="(item, index) in hotCities" :key="index">
              {{item.name}}
          </li>
      </ul>
<div :ref="key" v-for="(value, key,) in cities" :key="key">
<cityAll :list="value" :title="key"></cityAll>
</div>
      
      <ul class="right">
        <li @click="change(key)" v-for="(value, key,) in cities" :key="key">
          {{key}}
        </li>
       </ul>
     
</div>
 </div>
</template>

<script>
import Bscroll from "better-scroll";
import cityAll from "./cityAll.vue";
import search from "./search.vue";
export default {
  data() {
    return {
      hotCities: [],
      cities: [],
      innerText: "",
      city: this.$route.query.city,
      startY: 0,
      flag: true,
      touchStatus: false
    };
  },
  methods: {
    // handleTouchStart() {
    //   this.touchStatus = true;
    // },
    // handleTouchMove(e) {
    //   if (this.touchStatus) {
    // console.log(e);
    // const startY = this.$refs[e.target.innerText][0].offsetTop;
    // console.log(startY);
    // this.innerText = e.target.innerText;
    // // document.documentElement.scrollTop=startY-100
    // },
    // handleTouchEnd(e) {
    //   this.touchStatus = false;
    //   console.log(e);
    // },
    gohome(name) {
      this.$router.push({
        path: "/",
        query: {
          name
        }
      });
    },
    changeflag(flag) {
      this.flag = flag;
    },
    change(key) {
      console.log(key);
      document.documentElement.scrollTop = this.$refs[key][0].offsetTop - 100;
    }
  },
  updated() {
    this.startY = this.$refs["A"][0].offsetTop;
    console.log(this.startY);
  },
  created() {
    this.$axios.get("/static/city.json").then(res => {
      console.log(res);
      this.hotCities = res.data.data.hotCities;
      this.cities = res.data.data.cities;
    });
  },
  mounted() {},
  components: {
    cityAll,
    search
  },
  computed: {},
  watch: {}
};
</script>

<style lang='stylus' scoped>
@import '~styles/minxins.styl';

.header {
  width: 100%;
  bg();
  height: 1.6rem;
  position: sticky;
  top: 0;

  .top {
    height: 55%;
    align-items: center;
    font-size: 0.32rem;
    width: 100%;
    padding: 0 0.2rem;
    display: flex;
    box-sizing: border-box;

    i {
      font-size: 0.7rem;
      width: 0.8rem;
      color: #fff;
      height: 100%;
      line-height: 1.1rem;
    }

    span {
      flex: 1;
      text-align: center;
      color: #fff;
    }
  }

  .bottom {
    height: 45%;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
  }

  input {
    width: 95%;
    border-radius: 0.2rem;
    height: 80%;
    text-align: center;
  }
}

.title {
  line-height: 0.6rem;
  font-size: 0.3rem;
  padding-left: 0.2rem;
  box-sizing: border-box;
  background-color: #f0f0f0;
}

.city {
  height: 1rem;
  background-color: #fff;
  display: flex;
  align-items: center;

  span {
    margin-left: 0.2rem;
    border-radius: 0.1rem;
    padding: 0.08rem 0.5rem;
    border: 1px solid #ccc;
  }
}

.hotCities {
  width: 100%;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-around;
  padding-right: 0.7rem;
  box-sizing: border-box;
  padding-bottom: 0.2rem;

  li {
    width: 28%;
    text-align: center;
    border: 0.02rem solid #ccc;
    line-height: 0.6rem;
    margin-top: 0.2rem;
    border: 1px solid #ccc;
    border-radius: 0.1rem;
  }
}

.list {
  position: fixed;
  right: 0.04rem;
  top: 2rem;

  li {
    text-align: center;
    line-height: 0.4rem;
    color: #00c6c3;
  }
}

.right {
  position: fixed;
  right: 0.1rem;
  top: 3rem;

  li {
    line-height: 0.4rem;
    color: #01c5c3;
    text-align: center;
  }
}
</style>

搜索

<template>
  <div>
       
      <div class="header">
          <div class="top">
              <i @click="$router.go(-1)" class="iconfont"> &#xe605;</i>
              <span>城市选择</span>
              <i></i>
          </div>
            <div class="bottom">
                  <input v-model="keyword" @keydown.enter="changeinp" type="text" placeholder="输入城市名或拼音">
            </div>
      </div>
<div class="search" v-if="flag">
     <p v-if="result.length==0">暂无数据</p>
         <ul v-else>
         <li @click="gohome(item)" v-for="(item, index) in result" :key="index">
                {{item}}
         </li>
     </ul>
        </div>
 </div>
</template>

<script>
export default {
  props: ["cities"],
  data() {
    return {
      keyword: "",
      result: [],
      flag: false
    };
  },
  methods: {
      gohome(name){
          this.$router.push({
              path: '/',
              query: {
                  // url的参数, 类似get请求的传参
                  name
              },
          })
      },
    changeinp() {
      if (this.keyword == "") {
        this.flag = false;
        this.$emit("changeflag", true);
        return;
      }
      this.flag = true;
      this.$emit("changeflag", !this.flag);
      this.result = [];
      console.log(this.keyword);
      console.log();
      for (let key in this.cities) {
        this.cities[key].forEach(item => {
          if (
            item.spell.indexOf(this.keyword) > -1 ||
            item.name.indexOf(this.keyword) > -1
          ) {
            this.result.push(item.name);
          }
        });
      }
    }
  },
  created() {},
  mounted() {},
  components: {},
  computed: {
    list() {
      let arr = Array.from(this.cities);
      return arr;
    }
  },
  watch: {}
};
</script>

<style lang='stylus' scoped>
@import '~styles/minxins.styl';

.header {
    width: 100%;
    bg();
    height: 1.6rem;
    position: sticky;
    top: 0;

    .top {
        height: 55%;
        align-items: center;
        font-size: 0.32rem;
        width: 100%;
        padding: 0 0.2rem;
        display: flex;
        box-sizing: border-box;

        i {
            font-size: 0.7rem;
            width: 0.8rem;
            color: #fff;
            height: 100%;
            line-height: 1.1rem;
        }

        span {
            flex: 1;
            text-align: center;
            color: #fff;
        }
    }

    .bottom {
        height: 45%;
        width: 100%;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    input {
        width: 95%;
        border-radius: 0.2rem;
        height: 80%;
        text-align: center;
    }
}

.search {
    ul {
        li {
            line-height: 0.8rem;
            line-height: 0.8rem;
            width: 100%;
            padding-left: 0.2rem;
            border-bottom: 0.02rem solid #ccc;
        }
    }
}
</style>

城市列表

<template>
  <div>
      
<div class="list" @touchstart = "handleTouchStart"
@touchmove = "handleTouchMove"
@touchend = "handleTouchEnd">
    <div>
	<div v-for="(value, key) in cities"  :key="key" class="area">
		<div class="title" :ref="key" >
			{{key}}         
		</div>
		<div class="item-list" v-for="(item, index) in value" :key="index">
			<div class="item">{{item.name}}</div>
		</div>
	</div>
         </div>
</div>
 </div>
</template>

<script>
import Bscroll from "better-scroll";
export default {
  props: ["cities", "letter"],
  data() {
    return {
      touchStatus: false,
      timer: null
    };
  },
  methods: {
    handleTouchStart(e) {
      this.touchStatus = true;
    },
    handleTouchMove(e) {
      if (this.touchStatus) {
        // if (this.timer) {
        //   clearInterval(this.timer);
        // }
        // this.timer = setInterval(() => {
        let documentTOP = document.documentElement.scrollTop + 80;
        console.log(documentTOP);
          this.lists.forEach(item => {
            let startY = this.$refs[item][0].offsetTop;
            console.log(startY);
            if (startY == documentTOP) {
              this.$emit("changeItem", item);
            }
          });
        // }, 500);
      }
    },
    handleTouchEnd() {
      this.touchStatus = false;
    }
  },
  created() {},
  mounted() {
    //   this.scroll = new Bscroll(this.$refs.wrapper)
    // console.log(new Bscroll(this.$refs.wrapper));
  },
  components: {},
  computed: {
    lists() {
      let lists = [];
      for (const key in this.cities) {
        lists.push(key);
      }
      return lists;
    }
  },
  watch: {
    letter() {
      console.log(this.letter);
      if (this.letter) {
        const element = this.$refs[this.letter][0];
        console.log(element);
        document.documentElement.scrollTop =
          this.$refs[this.letter][0].offsetTop - 80;
        // this.scroll.scrollToElement(element)
      }
    }
  }
};
</script>

<style lang='stylus' scoped>
.list {
    width: 100%;

    .area {
        width: 100%;

        .title {
            background-color: #f0f0f0;
            line-height: 0.6rem;
        }

        .item {
            line-height: 0.6rem;
            border-bottom: 1px solid #ccc;
            padding-left: 0.2rem;
        }
    }
}
</style>

 let documentTOP = document.documentElement.scrollTop + 80;
 //获取页面卷曲出去的距离
        console.log(documentTOP);
          this.lists.forEach(item => {
            let startY = this.$refs[item][0].offsetTop;
            console.log(startY);
            判断title ABCD..距离顶部的距离 如果相等把 item传递给父组件
            if (startY == documentTOP) {
              this.$emit("changeItem", item);
            }
          });

右边悬浮字母表

<template>
  <div>
      
 <ul class="list">
   <li 
@touchstart = "handleTouchStart"
@touchmove = "handleTouchMove"
@touchend = "handleTouchEnd"
@click = "handleLetterClick" 
class="item" :class="{active:i==index}" v-for="(item, index) in cities" 
:ref="index" :key="index">
       {{index}}
   </li>
</ul>
 </div>
</template>

<script>
export default {
  props: ["cities", "letter"],
  data() {
    return {
      touchStatus: false,
      i: "A",
      timer: null,
      key: ""
    };
  },
  methods: {
    handleLetterClick(e) {
      this.i = e.target.innerText;

      this.$emit("change", e.target.innerText); //发送
    },
    handleTouchStart(e) {
      this.touchStatus = true;
    },
    handleTouchMove(e) {
      if (this.touchStatus) {
        // this.timer = setInterval(() => {
        const startY = this.$refs["A"][0].offsetTop;
        const touchY = e.touches[0].clientY - 80;
        console.log(touchY);
        // index触控位置的下标   20量为字符的高度
        const index = Math.floor((touchY - startY) / 20);
        
        if (index >= 0 && index < this.letters.length) {
          this.i = this.letters[index];
          this.$emit("change", this.letters[index]);
        }
        // }, 15);
        //A字符距离顶部的距离
        //所触控区距离最顶部距离e.touches[0].clientY   79为量出来量出来header高43+search高为36
      }
    },
    handleTouchEnd() {
      this.touchStatus = false;
    }
  },
  created() {},
  mounted() {},
  components: {},
  computed: {
    letters() {
      const letters = [];
      for (let i in this.cities) {
        letters.push(i);
      }
      return letters;
    }
  },
  watch: {
    letter: {
      //   deep: true,
      immediate: true,
      handler(newVal, oldVal) {
        this.i = newVal;
      }
    }
  }
};
</script>

<style lang='stylus' scoped>
.list {
    display: flex;
    flex-direction: column;
    justify-content: center;
    position: fixed;
    top: 1.58rem;
    right: 0;
    bottom: 0;
    width: 0.6rem;
    z-index: 99;

    // background :red
    .item {
        margin: 0 auto;
        line-height: 0.4rem;
        text-align: center;
        color: #01c5c3;
        width: 20px;
    }

    .active {
        background-color: #01c5c3;
        color: #fff;
    }
}
</style>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值