乐趣区

关于element-ui:elementui源码学习之仿写一个elcard

本篇文章记录一下,仿写一个 el-card 组件,有助于大家更好了解,饿了么 ui 的轮子具体工作细节。本文是 elementui 源码学习仿写系列的又一篇文章,后续闲暇了会不断更新并仿写其余组件。源码在 github 上,大家能够拉下来,npm start 运行跑起来,联合正文有助于更好的了解。github 仓库地址如下:https://github.com/shuirongsh…

集体愚见

对于卡片 card 组件,个别在应用中,次要还是 card 的交互成果,比方暗影成果。饿了么官网提供的 card 组件除了通过传参管制暗影呈现的机会,额定还提供了一个卡片头部插槽。好是好,不过个别用不到,因为卡片内容基本上都是本人写的,如果还应用头部插槽,可能须要多一些/deep/ 去管制款式,倒不如本人改写封装一个

自己看了饿了么 el-card 组件当前,也封装了一个 my-card 组件,没有退出原有的头部插槽 #header,不过多加了一些交互成果,整体有以下成果:

  • 暗影呈现的机会(原有性能)

    • 鼠标悬浮呈现
    • 总是呈现
    • 不呈现
  • 鼠标悬浮卡片稍微上移
  • 鼠标悬浮卡片放大一些
  • 鼠标悬浮卡片反转(即多了一个 slot="back" 的插槽用于传递反面的内容)
  • 以及管制侧面、反面的款式变量 cardStylebackCardStyle

咱们先看一下效果图

效果图

大家有什么好的录制 gif 软件能够分享我一下哦。我的这个软件录制进去的 gif 成果不太好。

组件中所用到的低频知识点

perspective属性:示意咱们看到的与 z = 0 立体的间隔,能够做三维地位变换透视成果

官网:https://developer.mozilla.org…

backface-visibility:hidden属性:指定当元素反面朝向观察者时藏起来

官网:https://developer.mozilla.org…

实现思路就是将两个要展现的 div 利用定位重叠在一起,其中一个首先围绕 Y 轴旋转肯定角度,而后搭配 backface-visibility:hidden 先藏起啦。鼠标悬浮的时候,整个旋转,就呈现不可见到可见的一个成果啦,翻转动画就有喽

this.$slots属性:寄存插槽的对象,能够存命名插槽、或者 default 一般插槽。

比方外界传递 <div slot="back"> 反面的内容 </div> 那么console.log("this.$slots", this.$slots); 就能够看到是否传递进来插槽了。本例中可用于判断是否开启翻转卡片模式,而后通过:class 的数组用法来动静增加类名,即可实现上述效果图

大家打印一下就明确,这个很简略。

应用组件的代码

<template>
  <div class="box">
    <my-card class="cardClass" shadow="hover"> 悬浮出暗影 </my-card>
    <my-card class="cardClass" shadow="always"> 始终出暗影 </my-card>
    <my-card class="cardClass" shadow="none"> 没有暗影 </my-card>
    <my-card class="cardClass" shadow="hover" isHoverUp> 悬浮出暗影上移 </my-card>
    <my-card class="cardClass" shadow="always" isHoverUp> 始终出暗影上移 </my-card>
    <my-card class="cardClass" shadow="none" isHoverUp> 没有暗影上移 </my-card>
    <my-card class="cardClass" shadow="hover" zoomCard> 悬浮出暗影放大 </my-card>
    <my-card class="cardClass" shadow="always" zoomCard> 始终出暗影放大 </my-card>
    <my-card class="cardClass" shadow="none" zoomCard> 没有暗影放大 </my-card>
    <my-card class="cardClass" :cardStyle="{padding: 0}" shadow="hover"
      > 应用 cardStyle 去管制款式,比方这里革除内边距 </my-card
    >
    <my-card
      class="cardClass cardClass2"
      :cardStyle="{background:'pink'}"
      :backCardStyle="{background:'#baf'}"
      > 悬浮卡片翻转(侧面)
      <!-- 当有命名插槽 back 的时候,主动开启翻转模式 -->
      <div slot="back"> 反面的内容 </div>
    </my-card>
  </div>
</template>

<style lang='less' scoped>
.box {
  display: flex;
  flex-wrap: wrap;
  box-sizing: border-box;
  padding: 24px;
  .cardClass {
    width: 240px;
    margin-right: 24px;
    margin-bottom: 24px;
  }
  .cardClass2 {height: 180px;}
}
</style>

封装的组件代码

<template>
  <div
    :class="['card-box',
      this.$slots.back ? 'card-reverse' : '',
      zoomCard ? 'card-box-zoom' : '',
    ]"
  >
    <div class="card-content">
      <!-- 当有 back 命名插槽时,加上 frontReverse 类名并移除 front-side 类名,才有反转成果 -->
      <div
        :style="cardStyle"
        :class="[
          this.$slots.back ? 'frontReverse' : 'front-side',
          shadow,
          isHoverUp ? 'isHoverUp' : '',
        ]"
      >
        <!-- 失常状况下一般插槽显示内容即可 -->
        <slot></slot>
      </div>
      <div :style="backCardStyle" class="backReverse" v-if="this.$slots.back">
        <!-- 有命名插槽就显示命名插槽内容,并做类名移除和新增,开启翻转成果 -->
        <slot name="back" />
      </div>
    </div>
  </div>
</template>

<script>
const shadowArr = ["hover", "always", "none"]; // shadow="none" 不传递也行的
export default {
  name: "myCard",
  props: {cardStyle: {}, // 管制卡片(侧面的款式)backCardStyle: {}, // 管制反面卡片的款式
    shadow: {
      // 暗影呈现机会:鼠标悬浮呈现、始终呈现、或不呈现
      type: String,
      validator(val) {
        // 校验
        if (shadowArr.includes(val)) return true;
        return false;
      },
    },
    isHoverUp: Boolean, // 是否悬浮往上平移一点
    zoomCard: Boolean, // 是否放大卡片(hover 时)},
  mounted() {console.log("this.$slots", this.$slots);
  },
};
</script>

<style lang="less" scoped>
.card-box {
  // background-color: #fff; /* 留神卡片盒子不能加背景色,会挡住旋转款式成果 */
  color: #333;
  perspective: 1000;
  transform-style: preserve-3d;
  transition: all 0.4s;
}
// 加 card-box-zoom 类名,就整体放大 1.08 倍
.card-box-zoom:hover {transform: scale(1.08);
}
// 直达的用于定位的容器盒子
.card-content {
  position: relative;
  width: 100%;
  height: 100%;
  transition: 0.75s;
  transform-style: preserve-3d;
}
/* 应用 front-side 类名管制一般状态时的款式 */
.front-side {
  box-sizing: border-box;
  padding: 18px;
  border-radius: 4px;
  border: 1px solid #e9e9e9;
  transition: 0.3s;
}
// 有 hover 类名时,在 hover 时,就加暗影
.hover:hover {box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
// 有 isHoverUp 类名时,就在 hover 时往上挪动一点
.isHoverUp:hover {transform: translateY(-3px);
}
// 有 always 类名时,就加暗影
.always {box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
/* 应用 frontReverse 和 backReverse 类名专门管制卡片反转状态时的款式 */
.frontReverse, // 利用定位使前前面重叠
.backReverse {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  backface-visibility: hidden;
  transform-style: preserve-3d;
  box-sizing: border-box;
  padding: 18px;
  border-radius: 4px;
  border: 1px solid #e9e9e9;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.frontReverse {z-index: 2; // 后面层级贬低}
.backReverse {transform: rotateY(-180deg); // 前面旋转不可见
}
.card-reverse:hover .card-content {
  // hover 时候,旋转容器,就会呈现,不可见到可见的过程了,翻转动画就有了
  transform: rotateY(180deg);
}
</style>

至于 css 兼容性的话,大家能够本人加上浏览器厂商的后缀呗

总结

  • 复制粘贴,即可呈现成果。
  • 如果对您有一点点帮忙,欢送 github 给个 star 哦
  • 因为是系列文章,您的激励是咱创作的能源^_^
退出移动版