封装常见的组件

简介: 封装常见的组件

1.手写分页组件


效果图:

适合vue3,稍作修改可用于vue2版本

image.png

<template>
  <div class="xtx-pagination">
    <a href="javascript:;" v-if="myCurrentPage===1" class="disabled">上一页</a>
    <a href="javascript:;" v-else @click="go(-1)">上一页</a>
    <!-- 如果起点按钮大于2就显示 -->
    <span  v-if="pageInfo.start>2">...</span>
    <a href="javascript:;" @click="changePage(item)"  :class="{active: myCurrentPage === item}" v-for="(item,idx) in pageInfo.pager" :key="idx"> {{item}} </a>
    <!-- 如果当前终点按钮小于总页数就显示 当终点按钮是20总按钮也是20 就不显示 -->
    <span  v-if="pageInfo.end < pageInfo.pageCount">...</span>
    <!-- 如果当前按钮等于最后一页就禁止点击 disabled -->
     <a href="javascript:;" v-if="myCurrentPage==pageInfo.end" class="disabled">下一页</a>
     <a href="javascript:;" v-else @click="go(1)">下一页</a>
  </div>
</template>
<script>
import { computed, ref, watch } from 'vue'
export default {
  name: 'XtxPagination',
  props: {
    total: { type: Number, default: 100 },
    pageSize: { type: Number, default: 10 },
    currentPage: { type: Number, default: 1 },
    btnCount: { type: Number, default: 5 }
  },
  setup (props, { emit }) {
    const myTotal = ref(100) // 总条数
    const myPageSize = ref(5) // 每页共几条
    const myCurrentPage = ref(3) // 用户实时点击,修改
    const myBtnCount = ref(5) // 分页按钮的个数5个
    // 让当前的页码处于正中间
    // const pager = ref([1, 2, 3, 4, 5])
    // 根据上边信息,实时计算 pager,起始页码,结束页码
    const pageInfo = computed(() => {
      // 总页数 = 总条数/每页几条
      const pageCount = Math.ceil(myTotal.value / myPageSize.value)
      // 起点 = 当前页数-总页数/2  举例 3 - Math.floor(5/2)  = 1
      let start = myCurrentPage.value - Math.floor((myBtnCount.value / 2))
      // 终点 = 起点页数 + 总页数 - 1  距离 1 + 5 -1 || 3 + 5 -1
      let end = start + myBtnCount.value - 1
      // 意外1 当起点小于1
      if (start < 1) {
        start = 1
        // 终点= 当前页数>总页数?总页数 否则 当前页数
        end = myBtnCount.value > pageCount ? pageCount : myBtnCount.value
      }
      // 意外2  当终点大于最大页码
      if (end > pageCount) {
        end = pageCount
        // 起点= 终点+(-所有页数+1)>1?1:= 终点+(-所有页数+1)
        start = (end - myBtnCount.value + 1) < 1 ? 1 : (end - myBtnCount.value + 1)
      }
      const pager = []
      for (let i = start; i <= end; i++) {
        pager.push(i)
      }
      return { start, end, pageCount, pager }
    })
    // 上一页下一页
    const go = (step) => {
      myCurrentPage.value += step
    }
    const changePage = (page) => {
      // 如果等于现在页页码 保持不动
      if (page === myCurrentPage.value) return
      myCurrentPage.value = page
      emit('currentCahnge', page)
    }
    // 监听传入的值改变
    watch(props, () => {
      myTotal.value = props.total
      myPageSize.value = props.pageSize
      myCurrentPage.value = props.currentPage
      myBtnCount.value = props.btnCount
    }, { immediate: true })
    return { myTotal, myPageSize, myCurrentPage, myBtnCount, pageInfo, go, changePage }
  }
}
</script>
<style scoped lang="less">
.xtx-pagination {
  display: flex;
  justify-content: center;
  padding: 30px;
  > a {
    display: inline-block;
    padding: 5px 10px;
    border: 1px solid #e4e4e4;
    border-radius: 4px;
    margin-right: 10px;
    &:hover {
      color: @xtxColor;
    }
    &.active {
      background: @xtxColor;
      color: #fff;
      border-color: @xtxColor;
    }
    &.disabled {
      cursor: not-allowed;
      opacity: 0.4;
      &:hover {
        color: #333
      }
    }
  }
  > span {
    margin-right: 10px;
  }
}
</style>

2.手写轮播图组件


功能:

  1. 图片切换显示
  2. 上一张,下一张按钮点击
  1. 底部指示条高亮
  2. 自动播放,鼠标移入开始,鼠标移出继续

主要逻辑:

一: 自动播放:

  • 暴露自动轮播属性,设置了就自动轮播
  • 暴露自动播放间隔时间
  • 如果有自动播放,鼠标进入离开,暂停,开启
  • 销毁组件时清理定时器
  • 离开暂停: 如果有自动播放,鼠标进入离开,暂停,开启

销毁组件,清理定时器

二: 上下切换指示器

思路: 封装一个函数,处理上一张,下一张按钮的回调。

<template>
  <div class='xtx-carousel'>
    <ul class="carousel-body">
      <li class="carousel-item fade">
        <RouterLink to="/">
          <img src="http://yjy-xiaotuxian-dev.oss-cn-beijing.aliyuncs.com/picture/2021-04-15/1ba86bcc-ae71-42a3-bc3e-37b662f7f07e.jpg" alt="">
        </RouterLink>
      </li>
    </ul>
    <a href="javascript:;" class="carousel-btn prev"><i class="iconfont icon-angle-left"></i></a>
    <a href="javascript:;" class="carousel-btn next"><i class="iconfont icon-angle-right"></i></a>
    <div class="carousel-indicator">
      <span v-for="i in 5" :key="i"></span>
    </div>
  </div>
</template>
<script>
export default {
  name: 'XtxCarousel'
}
</script>
<style scoped lang="less">
.xtx-carousel{
  width: 100%;
  height: 100%;
  min-width: 300px;
  min-height: 150px;
  position: relative;
  .carousel{
    &-body {
      width: 100%;
      height: 100%;
    }
    &-item {
      width: 100%;
      height: 100%;
      position: absolute;
      left: 0;
      top: 0;
      opacity: 0;
      transition: opacity 0.5s linear;
      &.fade {
        opacity: 1;
        z-index: 1;
      }
      img {
        width: 100%;
        height: 100%;
      }
    }
    &-indicator {
      position: absolute;
      left: 0;
      bottom: 20px;
      z-index: 2;
      width: 100%;
      text-align: center;
      span {
        display: inline-block;
        width: 12px;
        height: 12px;
        background: rgba(0,0,0,0.2);
        border-radius: 50%;
        cursor: pointer;
        ~ span {
          margin-left: 12px;
        }
        &.active {
          background:  #fff;
        }
      }
    }
    &-btn {
      width: 44px;
      height: 44px;
      background: rgba(0,0,0,.2);
      color: #fff;
      border-radius: 50%;
      position: absolute;
      top: 228px;
      z-index: 2;
      text-align: center;
      line-height: 44px;
      opacity: 0;
      transition: all 0.5s;
      &.prev{
        left: 20px;
      }
      &.next{
        right: 20px;
      }
    }
  }
  &:hover {
    .carousel-btn {
      opacity: 1;
    }
  }
}
</style>

3.手写提示框组件


效果:

image.png

思路:image.png

组件:

<template>
  <div class="xtx-confirm" :class="{fade}">
    <div class="wrapper"  :class="{fade}">
      <div class="header">
        <h3>{{title}}</h3>
        <a @click="cancelCallback()" href="JavaScript:;" class="iconfont icon-close-new"></a>
      </div>
      <div class="body">
        <i class="iconfont icon-warning"></i>
        <span>{{text}}</span>
      </div>
      <div class="footer">
        <XtxButton @click="cancelCallback()" size="mini" type="gray">取消</XtxButton>
        <XtxButton @click="submitCallback()" size="mini" type="primary">确认</XtxButton>
      </div>
    </div>
  </div>
</template>
<script>
// 当前组件不是在APP下进行渲染,无法使用APP下的环境(全局组件,全局指令,原型属性函数)
import XtxButton from '@/components/XtxButton.vue'
import { onMounted, ref } from 'vue'
export default {
  name: 'XtxConfirm',
  components: { XtxButton },
  props: {
    title: {
      type: String,
      default: '温馨提示'
    },
    text: {
      type: String,
      default: ''
    },
    submitCallback: {
      type: Function
    },
    cancelCallback: {
      type: Function
    }
  },
  setup () {
    const fade = ref(false)
    onMounted(() => {
      // 当元素渲染完毕立即过渡的动画不会触发
      fade.value = true
    })
    return { fade }
  }
}
</script>
<style scoped lang="less">
.xtx-confirm {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  z-index: 8888;
  background: rgba(0,0,0,0);
  &.fade {
    transition: all 0.4s;
    background: rgba(0,0,0,.5);
  }
  .wrapper {
    width: 400px;
    background: #fff;
    border-radius: 4px;
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%,-60%);
    opacity: 0;
    &.fade {
      transition: all 0.4s;
      transform: translate(-50%,-50%);
      opacity: 1;
    }
    .header,.footer {
      height: 50px;
      line-height: 50px;
      padding: 0 20px;
    }
    .body {
      padding: 20px 40px;
      font-size: 16px;
      .icon-warning {
        color: @priceColor;
        margin-right: 3px;
        font-size: 16px;
      }
    }
    .footer {
      text-align: right;
      .xtx-button {
        margin-left: 20px;
      }
    }
    .header {
      position: relative;
      h3 {
        font-weight: normal;
        font-size: 18px;
      }
      a {
        position: absolute;
        right: 15px;
        top: 15px;
        font-size: 20px;
        width: 20px;
        height: 20px;
        line-height: 20px;
        text-align: center;
        color: #999;
        &:hover {
          color: #666;
        }
      }
    }
  }
}
</style>

转换成函数调用

Confirm.js

// 实现使用函数调用xtx-message组件的逻辑
//   引入 创建虚拟节点 和渲染方法
import { createVNode, render } from 'vue'
// 引入信息提示组件
import XtxConfirm from './xtxConfirm'
// 准备dom容器
const div = document.createElement('div')
// 添加类名
div.setAttribute('class', 'xtx-message-container')
// 添加到body上
document.body.appendChild(div)
// 该函数渲染XtxConfirm组件,标题和文本
// 函数的返回值是promise对象
export default ({ type, text }) => {
  return new Promise((resolve, reject) => {
    // 1. 渲染组件
    // 2. 点击确认按钮,触发resolve同时销毁组件
    // 3. 点击取消按钮,触发reject同时销毁组件
    const submitCallback = () => {
      render(null, div)
      resolve()
    }
    const cancelCallback = () => {
      render(null, div)
      //   希望给出promise错误原因
      reject(new Error())
    }
    // 实现:根据xtx-message.vue渲染消息提示
    // 1. 导入组件
    // 2. 根据组件创建虚拟节点   第一个参数为要创建的虚拟节点  第二个参数为props的参数
    const vnode = createVNode(XtxConfirm, { type, text, submitCallback, cancelCallback })
    // 3. 准备一个DOM容器
    // 4. 把虚拟节点渲染DOM容器中
    render(vnode, div)
  })
}

使用:

<button @click="delete">删除</button>
<script>
import Confirm from '@/components/confirm'
export default {
  setup () {
    const delete= () => {
      Confirm({ text: '您确定从购物车删除该商品吗?' }).then(() => {
        console.log('点击确认')
      }).catch(e => {
        console.log('点击取消')
      })
    }
    return { delete}
  }
}
</script>
相关文章
|
12月前
|
存储 Cloud Native 安全
C++ 封装成库
C++ 封装成库
|
Java 数据挖掘 数据库
封装的理解
封装的理解
100 0
|
2月前
|
数据安全/隐私保护 C语言 C++
C++(七)封装
本文档详细介绍了C++封装的概念及其应用。封装通过权限控制对外提供接口并隐藏内部数据,增强代码的安全性和可维护性。文档首先解释了`class`中的权限修饰符(`public`、`private`、`protected`)的作用,并通过示例展示了如何使用封装实现栈结构。接着介绍了构造器和析构器的使用方法,包括初始化列表的引入以及它们在内存管理和对象生命周期中的重要性。最后,通过分文件编程的方式展示了如何将类定义和实现分离,提高代码的模块化和复用性。
|
5月前
什么是封装?为什么是要封装?
什么是封装?为什么是要封装?
114 0
|
6月前
|
安全 C#
C#封装详解
C#封装详解
61 0
|
开发框架 JavaScript API
UniApp组件封装
UniApp是一个跨平台的开发框架,允许开发者使用Vue.js编写一次代码,然后将其发布到多个平台,包括iOS、Android和Web。在UniApp中,组件是构建用户界面的基本单元,它们可以重复使用,并且具有可配置的属性和方法。其中组件是一种可重用的UI元素,用于展示信息、接收用户输入或实现特定功能。UniApp提供了一系列内置的组件,如按钮、输入框、列表、滑动组件等,开发者也可以自定义和扩展组件以满足特定需求。
200 1
|
6月前
|
安全 数据安全/隐私保护
什么是封装?
什么是封装?
33 0
|
设计模式 开发框架 开发者
组件封装使用?
组件封装使用?
|
程序员
封装(了解一下)
封装(了解一下)
91 0