一些组件封装

不定期更新

目录

1、弹出框/对话框

2、星星评分

3、返回顶部

4、toast


1、弹出框/对话框

  1. 创建一个子组件,在父组件上引用

  2. 在子组件写布局样式,并在标题和内容区域插入<slot name="####”></slot>插槽

  3. 在父组件定义show变量,默认为false,并定义标题,内容区域内容

  4. 点击按钮,show为true让组件显示

  5. 点击不同按钮,让其对应标题,内容区域内容显示

  6. 点击X /取消 /确定 通过子传父,当其触发,让show的值为false,隐藏

 //父组件
 <template>
  <div>
    <dlog v-show="show" @clo="clo">
      <template #title>
        <span>{{ titles }}</span>
      </template>
      <template #content>
        <span>{{ slots }}<button>按钮</button></span>
      </template>
    </dlog>
    <van-button type="primary" @click="open1">btn1</van-button>
    <van-button type="primary" @click="open2">btn2</van-button> 
  </div>
</template>

<script setup>
import dlog from "../components/dlog.vue";
import start from "../components/start.vue";
import { ref } from "vue";
const show = ref(false);
const slots = ref();
const titles = ref(); 
const open1 = () => {
  show.value = true;
  titles.value = "点击了btn1";
  slots.value = "btn1内容";
};
const open2 = () => {
  titles.value = "点击了btn2";
  show.value = true;
  slots.value = "btn2内容";
};
const clo = () => {
  console.log(1);
  show.value = false;
}; 
</script>
<style>
.van-button {
  margin-left: 20px;
}
.star {
  margin: 20px;
  font-size: 20px;
  display: flex;
  color: #f00;
}
</style>
//子组件
<template>
  <div class="dlog">
    <div class="box">
      <div class="t">
        <p><slot name="title"></slot></p>
        <span @click="close">X</span>
      </div>
      <div class="m">
        <slot name="content"></slot>
      </div>
      <div class="f">
        <van-button @click="close" plain type="primary">取消</van-button>
        <van-button @click="close" type="primary">确定</van-button>
      </div>
    </div>
  </div>
</template>

<script setup>
const s = defineEmits(["clo"]);
const close = () => {
  s("clo");
};
</script>

<style lang="scss" scoped>
.dlog {
  position: fixed;
  top: 0;
  z-index: 999;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.297);

  display: flex;
  align-items: center;
  justify-content: center;
  .box {
    width: 40%;
    background-color: #fff;
    border-radius: 20px;
    padding: 20px;
    box-sizing: border-box;
    .t {
      width: 100%;
      display: flex;
      height: 18%;
      font-size: 20px;
      justify-content: space-between;
      align-items: center;
      span {
        cursor: pointer;
      }
    }
    .m {
      padding: 20px 0;
    }
    .f {
      float: right;
      .van-button {
        margin-left: 20px;
      }
    }
  }
}
</style>

2、星星评分

  1. 创建一个子组件,在父组件上引用

  2. 子组件逻辑:写了两个星星图标,第一个循环5,第二个循环一个变量(sum),并让其默认为0

  3. 利用定位让其重叠

  4. 点击循环第一个,并传递他的下标,在事件内赋值,让sum为下标+1(index+1),此时当你点击那个就会出现已经点击过的样式

  5. 但是此时有一个问题,点击之后不能取消选中

  6. 点击循环的第二个,并传递他的下标,在事件内赋值,让sum为下标+1(index+1)

  7. 此时能点击,能取消,最后写一个子传父的事件,并把其sum传递到父组件(sum及已选中几颗星),在父组件可进行渲染/判断逻辑处理

//子组件

    <template>
      <div class="box">
        <van-icon
          v-for="(item, index) in 5"
          @click="click(index)"
          :key="item"
          name="star"
        />
        <div class="ok">
          <van-icon
            class="h"
            @click="h(index)"
            name="star"
            v-for="(item, index) in sum"
            :key="index"
          />
        </div>
      </div>
    </template>
    <script setup>
    import { ref } from "vue";
    const sum = ref(0);
    const s = defineEmits(["startnum"]);
    const click = (i) => {
      console.log(i);
      sum.value = i + 1;
      console.log("总", sum.value);
      s("startnum", sum.value);
    };
    const h = (i) => {
      console.log(i);
      sum.value = i + 1;
      console.log("总", sum.value);
      s("startnum", sum.value);
    };
    </script>
    <style>
    .van-icon {
      font-size: 20px;
      margin-right: 10px;
      color: #999;
    }
    .box {
      position: relative;
    }
    .ok {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 999;
    }
    .h {
      color: #ffa940;
    }
    </style>

3、返回顶部

  1. 创建一个子组件,在父组件上引用

  2. 在父组件写一个超出试图的元素内容,滚动时带有滚动条

  3. 在子组件自定义一个滚动事件,使用document.documentElement.scrollTop获取到元素滚动到都,方便图标的显示隐藏

    const handle = () => {
      if (document.documentElement.scrollTop > 200) {
        show.value = true;
      } else if (document.documentElement.scrollTop < 200) {
        show.value = false;
      }
      // console.log(document.documentElement.scrollTop);
    };
  4. 在子组件使用onMounted(()=>{})里面监听滚动事件

onMounted(() => {
  window.addEventListener("scroll", handle)
});

     5.子传父传递一个事件,在父组件接受,当父组件接收并处罚后,让其滚动高度为0,也可以设置平滑滚动过渡

 let timer = setInterval(() => {
    let top = document.documentElement.scrollTop
    let animation = top / 5
    document.documentElement.scrollTop = top - animation
    if (top === 0) {
      clearInterval(timer)
    }
  }, 50);
//父组件
<template>
  <div id="box">
    <h2>返回顶部</h2>
    <ul>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
      <li>li</li>
    </ul>
    <gotopcom @bt="bt"></gotopcom>
  </div>
</template>

<script setup>
import gotopcom from "../components/gotopcom.vue"; 
const bt = () => {
  // document.documentElement.scrollTop = 0

  let timer = setInterval(() => {
    let top = document.documentElement.scrollTop
    let animation = top / 5
    document.documentElement.scrollTop = top - animation
    if (top === 0) {
      clearInterval(timer)
    }
  }, 50);
};
</script>

<style lang="scss" scoped>
li {
  width: 100%;
  text-align: center;
  height: 50px;
  background-color: palevioletred;
  font-size: 20px;
  color: #fff;
  margin-bottom: 20px;
}
</style>
//子组件
<template>
  <div v-show="show">
    <img
      src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fbpic.136pic.com%2Fkimg%2F481%2F2015%2F3%2F2%2Fe2241f6b6452c99bfe4428302005de86.jpg&refer=http%3A%2F%2Fbpic.136pic.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1665021440&t=0b459cd983097a2d5360d28f7053eea8"
      alt="" @click="oncli" />
  </div>
</template>
<script setup>
import { ref, defineEmits, onMounted } from "vue";
const show = ref(false);
const s = defineEmits(["bt"]);
const oncli = () => {
  s("bt");
};

const handle = () => {
  if (document.documentElement.scrollTop > 200) {
    show.value = true;
  } else if (document.documentElement.scrollTop < 200) {
    show.value = false;
  }
  // console.log(document.documentElement.scrollTop);
};
onMounted(() => {
  window.addEventListener("scroll", handle)
});
</script>
<style lang="scss" scoped>
img {
  width: 50px;
  height: 50px;
  position: fixed;
  right: 20px;
  bottom: 50px;
}
</style>

4、toast

  1. 创建一个子组件,在父组件上引用

  2. 在父组件定义一个show状态,默认为false,使用v-show绑定

  3. 写一个按钮,当点击时,让show为true,显示弹框

  4. 消失:子传父,传递一个事件,在点击 X 时 在父组件接收传过来的事件,并让show为false

  5. 停留三秒消失:在子组件的onMounted生命周期里,定义一个 setInterval,设置事件3s,当到达三秒,调用取消按钮事件

//停留3s
onMounted(() => {
    setInterval(() => {
        hide()
    }, 3000);
})
//父组件
<template>
    <div>
        <button @click="btn">testtost</button>
        <toast v-show="show" @hid="hid">测试 toast</toast>
    </div>
</template>

<script setup>
import toast from '../components/toast.vue'
import { ref } from 'vue'
const show = ref(false)
const btn = () => {
    show.value = true
}
const hid = (e) => {
    show.value = e
}
</script>
//子组件
<template>
    <div>
        <van-icon name="warning" />
        <p>
            <slot></slot>
        </p>
        <span @click="hide">X</span>
    </div>
</template>
<script setup>
import { onMounted } from 'vue';
const s = defineEmits(['hid'])
const hide = () => {
    s('hid', false)
}
onMounted(() => {
    setInterval(() => {
        hide()
    }, 3000);
})
</script>
<style lang="scss" scoped>
div {
    background-color: #edf2fc;
    color: #909399;
    display: flex;
    align-items: center;
    width: 30%;
    margin: 100px auto;
    justify-content: space-around;
    height: 60px;
    border-radius: 10px;

    p {
        width: 50%;
    }

    span {
        cursor: pointer;
    }
}
</style>

5、select下拉

  1. 创建一个子组件,在父组件上引用

  2. 在父组件创建一个数组,或者接口上获取一个,传递到子组件

  3. 子组件接收后,v-for循环渲染选项

  4. 定义一个属性show,默认为false并为选项绑定v-show

  5. 点击盒子,让show为true

  6. 点击选项,传递名字参数,把参数赋值给盒子,使用v-text,之后在将show为false

  7. 在点击选项时,子组件像父组件传递事件和参数

  8. 父组件接收后,可获取选中的选项内容

//父组件
<template>
    <div>
        <selects :item="arr" @gpo="gpo"></selects>
        <div>{{item?`已选中${item}`:''}}</div>
    </div>
</template>
<script setup>
import selects from '../components/select.vue'
import { ref } from 'vue';
const arr = ref(['黄金糕', '双皮奶', '蚵仔煎', '龙须面', '北京烤鸭'])
const item = ref()
const gpo = (e) => {
    item.value = e
    console.log(e);
}
</script>
//子组件
<template>
    <div class="box">
        <!-- <input type="text" @click="open" disabled v-model="inp"> -->
        <div class="inp" v-text="inp" @click="open"></div>
        <van-icon name="arrow-down" />
        <div class="div" v-show="show">
            <p v-for="(item,index) in pro.item" :key="index" @click="slec(item)">{{item}}</p>
        </div>
    </div>
</template>

<script setup>
import { ref } from 'vue';
const pro = defineProps({
    item: {
        type: Object,
        default: [1, 2]
    }
})
const s = defineEmits(['gpo'])
const inp = ref()
const show = ref(false)
const slec = (item) => {
    inp.value = item
    show.value = false
    s('gpo', item)
}
const open = () => {
    console.log('====================================');
    console.log(5);
    console.log('====================================');
    show.value = true
}


</script>
<style lang="scss" scoped>
.box {
    padding: 20px;
    box-sizing: border-box;
    position: relative;
}



.inp {
    width: 200px;
    height: 40px;
    border: #409eff;
    border-radius: 5px;
    border: 2px #409eff solid;
    line-height: 40px;

}

.van-icon {
    position: absolute;
    left: 190px;
    top: 35px;
}

.div {
    width: 200px;
    background-color: rgb(226, 226, 226);

    p {
        background-color: #f5f7fa;
        margin-bottom: 10px;
        line-height: 40px;
        color: #409eff;
        height: 40px;
        padding-left: 20px;
        box-sizing: border-box
    }
}
</style>

6、封装tabs

  1. 在父组件引入子组件

  2. 父组件的数据内容传递给子组件

  3. 子组件渲染tabs列表

  4. 子组件列表内容根据点击tabs的下标来进行显示隐藏内容块 

//父组件
<template>
    <!-- vue实例外创建 -->
    <div>
        <tab :lis="lis" :conts="conts" @handel="handel"></tab>
        <div>{{indexid?`选择了第${indexid}项`:'默认第一项'}}</div>
    </div>
</template>
<!-- 调用   <mycom></mycom> -->
<script setup>
import tab from '../components/tab.vue'
import { ref } from 'vue'
const indexid = ref()
const lis = ref(['第一项', '第二项', '第三项', '第四项'])
const conts = ref(['内容1', '内容2', '内容3', '内容4'])
const handel = (index) => {
    indexid.value = index + 1
}
</script>
//子组件
<template>
    <div>
        <ul>
            <li v-for="(item,index) in pro.lis" :class="index===indexi?'bgc':''" @click="changli(index)" :key="index">
                {{item}}</li>
        </ul>
        <div class="cont">
            <div>{{!contcent?`${pro.conts[0]}`:`${contcent}`}}</div>
        </div>
    </div>
</template>

<script setup>
import { ref } from 'vue'
const pro = defineProps({
    lis: {
        type: Object,
        default: [1, 2]
    },
    conts: {
        type: Object,
        default: [3, 4]
    }
})
const contcent = ref()
const indexi = ref(0)
const d = defineEmits(['handel'])
const changli = (index) => {
    indexi.value = index
    contcent.value = pro.conts[index]
    d('handel', index)
}
</script>
<style lang="scss" scoped>
ul {
    height: 30px;
    margin-top: 20px;

    li {
        float: left;
        list-style-type: none;
        width: 100px;
        height: 30px;
        margin-left: 30px;
        line-height: 30px;
        text-align: center;
        border: 1px #f00 solid;

        // &:nth-child(1) {
        //     background-color: palevioletred;
        //     color: #fff;
        // }
    }
}

.cont {
    border: 1px #f00 solid;
    width: 800px;
    height: 500px;
    margin-top: 10px;
}

.bgc {
    background-color: palevioletred;
    color: #fff;
}
</style>

7、轮播图

  1. 在父组件引入子组件,我们这个总的来说,就是依靠下标来进行循环切换,以及点击切换

  2. 父组件的数据内容传递给子组件

  3. 子组件渲染 li按钮,根据传过来的长度,

  4. 当点击li的某一项时,传递其下标

  5. 定一个变量,吧这个传过来的arr[index]赋值给上面的图片

  6. 此时能够点击来进行切换图片

  7. 自动播放

  8. 在onMounted使用setinterval设置5000ms时间

onMounted(() => {
    setInterval(() => {
        indexi.value++     //每过5s让下标++
        let ar = ref(pro.imgs[indexi.value])
        img.value = ar._value    //赋值给上边图片
        if (indexi.value >= pro.imgs.length) {       
        循环,当这个下标大于等于这个总长度时(即:等跳转到最后一项,此时我们应该可以循环播放
            indexi.value = 0                   ,然后将indexi置为0,
            img.value = pro.imgs[0]            mg.value置为第一个初始图)
        }
        s('changea', indexi.value)      调用子传父,告知我们这个是跳转到第几个图片了
    }, 5000);
})

//父组件
<template>
    <div>
        <bannerimg :imgs="imgs" @changea="changea"></bannerimg>
        <div>选择{{ind+1}}个</div>
    </div>
</template>
<script setup>
import bannerimg from '../components/bannerimg.vue'
import { ref } from 'vue'
const imgs = ref(['../../public/1.jpg', '../../public/2.png', '../../public/3.jpg', '../../public/4.jpg'])
const ind = ref(1)
const changea = (index) => {  
    ind.value = index 
}
</script>
<style lang="scss" scoped>
</style>
//子组件
<template>
    <div class="box">
        <img :src=img>
        <ul>
            <li @click="changli(index)" :class="indexi==index?'bgc':''" v-for="(item,index) in pro.imgs.length"
                :key="index">{{index}}</li>
        </ul>
    </div>
</template>

<script setup>
import { ref, onMounted } from 'vue'
const pro = defineProps({
    imgs: {
        type: Object,
        default: [1, 2]
    }
})
const s = defineEmits(['changea'])
const img = ref(pro.imgs[0])
const indexi = ref(0)
const changli = (index) => {
    indexi.value = index
    let ar = ref(pro.imgs[index])
    img.value = ar._value
    console.log(img.value);
    s('changea', index)
}
onMounted(() => {
    setInterval(() => {
        indexi.value++
        let ar = ref(pro.imgs[indexi.value])
        img.value = ar._value
        if (indexi.value >= pro.imgs.length) {
            indexi.value = 0
            img.value = pro.imgs[0]
        }
        s('changea', indexi.value)
    }, 5000);
})
</script>
<style lang="scss" scoped>
.box {
    border: 10px pink solid;
    margin: 0 auto;
    width: 500px;
    position: relative;
}

img {
    height: 280px;
    width: 500px;
}

ul {
    width: 100%;
    position: absolute;
    display: flex;
    justify-content: center;
    bottom: 20px;

    li {
        cursor: pointer;
        letter-spacing: none;
        background-color: palevioletred;
        width: 20px;
        float: left;
        margin-left: 20px;
        height: 20px;
        text-align: center;
        line-height: 20px;
        border-radius: 20px;
    }
}

.bgc {
    background-color: pink;
}
</style>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值