阅读 31099
UI:你们有没有什么花哨点的组件库给我参考一下?

UI:你们有没有什么花哨点的组件库给我参考一下?

⚠️ 本文为掘金社区首发签约文章,未获授权禁止转载

前言

在刚刚过去的国庆节我们公司上线了好几个国庆的活动页🎉,之前开会探讨这些活动页的时候UI小姐姐曾问到:“你们前端有没有那种比较炫酷的组件库啊?不是像咱们平时页面里的那种很普通的组件,有的话可以给我看看,我就按照组件库的风格出图,这样你省事我也省事,咱们进度也能更快一点。活动页就是要做的标新立异一些,但我要是太标新立异了怕你们做起来麻烦导致咱们不能在国庆前上线,所以你去你们程序员的 GitHubCSS TricksCodePen 之类的网站上找找有没有这样的库吧!”

我:这当然有啦!你看看这个咋样:

她:哟!这个效果还不错!我还以为你们前端的组件库都是Element UIAnt Design那种样式的呢。

我:这你可就孤陋寡闻了吧,我们前端花里胡哨的组件库可多了去了,只不过是因为咱们这种以内容为导向的网站大多都用不到什么特别炫酷的效果吧?所以才很少会看到这种效果的组件库。

她:有道理,还有哪些组件啊?都给我看看,咱们活动页就需要这种标新立异的组件来点缀。

花式组件库

组件库的名字叫fancy-components,但我更喜欢把它翻译成中文:花式组件库。下面就来看看它都有哪些组件,对不对得起它这么嚣张的名字。

按钮类

FcWarpBtn

warp 是变形的意思,顾名思义,这个按钮看起来像是变了形翘起来了一样。

FcDblWarpBtn

Dbl就是double的简写,上面那个按钮不是只有一边翘起来了么?那这个是两边都翘了,所以加了个Dbl

Fc3DBtn

顾名思义,3D嘛!非常立体的这么一种感觉。

FcUnderlineBtn

Underline下划线的意思,这款按钮在非hover状态时会有一个下划线。

FcRoundBtn

Round圆润的意思嘛!圆润的一款按钮。

FcParenthesesBtn

Parentheses是括号的意思,这款按钮在非hover状态时会有一个括号。

FcPixelBtn

Pixel是像素的意思,这款按钮在hover时会有一个像素风的动画。

FcArrowBtn

Arrow是箭头的意思,箭头按钮非常适合作为返回按钮等指引按钮。

表单类

FcTypingInput

Typing是打字的意思,这个输入框在focus状态时的placeholder会出现一种类似打字的效果。

滤镜类

FcWaveFilter

Wave是波浪的意思,它会把传进来的图片加以波浪效果,更具体的用法请点击这里

渐进增强类

FcBubbles

Bubbles是气泡的意思,渐进增强式的组件就是你传进来的东西什么都不变,就是多加了个特效罢了。

国旗类

FcChina

(由于某些原因导致本文无法上传与🇨🇳有关的图片,具体的效果请点击这个链接来查看)

China相信不用翻译大家也都知道是啥意思。

具体用法

首先这是一款基于web components的组件库,无论你是vuereactangular还是svelte等一些其他框架,它都能良好的与这些框架共存,因为这就是JS原生的组件化技术。没有哪个框架说自己不支持原生JS的某一部分API的,这种技术有人看好也有人唱衰,看好的人觉得:

除了fancy-components,我还经常用的一个web components组件是css doodle,翻译过来是CSS涂鸦的意思。它不能算是一个组件库,因为它只有一个组件,但是可以通过这个组件画出万花筒一样的样式来,也是超炫的一个web components组件:

2021-08-20 22-05-56.2021-08-20 22_06_44.gif

感兴趣的同学可以去B站搜索前端学不动这位up主,看看上面那个效果是怎么实现出来的。

现如今已经有很多组件库都采用了web components作为底层技术,已经可以看到这种趋势了。只不过web components在国内很少被人谈起,所以那些在国外还不错的一些组件库也就没能传到大家的耳朵里。

就连新发布的Vue3.2也出了一个defineCustomElement方法,就是为了专门用来生成自定义元素(web components的其中一项技术)的。目前已经有趋势表明这门技术未来将会大展身手,以前它没能火起来的主要原因就是兼容性问题。

不过既然有人看好那就肯定有人唱衰,唱衰的人觉得:

  • 几乎所有流行框架都拥有自己的一套组件化系统 何必大费周折的去用web components重构呢?
  • 这么多年了还没火起来 不是没给它时间 是它自己不争气啊!
  • 不兼容IE的技术不是好技术

为何说web components未来可能会取代框架这个观点有点扯淡呢?发布这个观点的作者认为jQuery的没落源于浏览器实现了document.querySelectordocument.querySelectorAll方法,这不就跟jQuery的主要方法$()有些相似么,那谁还用jq。所以web components也是同理:现代框架的主要卖点不就是组件化么?浏览器原生实现了组件化功能,所以现代框架未来也会像jq那样。(个人感觉纯属扯淡

不过毕竟咱们这篇文章不是讲web components的,只不过是咱们用到的组件库fancy-components是用web components来进行封装的,就简单的提一嘴web components。咱们只需要知道怎么用fancy-components就行:

在普通项目中

普通项目指的是那种直接在文件夹里建个HTML文件就开始写代码的那种项目,没有什么工程化、webpack、babel这些花里胡哨的东西。我们新建个HTML然后在<script>标签中写上type="module"就能使用模块化的语法来加载fancy-components啦:

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>公众号:前端学不动</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    html, body {
      height: 100%;
      display: grid;
      place-items: center;
    }
    fc-wave-filter {
      --width: 100px;
    }

    /* :defined 选择器会选择到已定义的元素 */
    /* 但却没有 :undefined 这样的选择器 所以只能用 :not() 选择器来配合使用 */
    /* 这个选择器具体是干嘛用的 可以B站搜索:前端学不动 这位up主 */
    /* 找到他的《自定义元素基础篇》在第 17:25 的位置有讲 */
    :not(:defined) {
      display: none;
    }
  </style>
</head>
<body>
  <!-- 需要在<fc-wave-filter>里指定color这个属性 默认为黑色 -->
  <fc-wave-filter color="#047">
    <!-- 在这里(slot里)放入img图片 -->
    <img src="data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOjFlbTtoZWlnaHQ6MWVtO3ZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJjdXJyZW50Q29sb3IiIG92ZXJmbG93PSJoaWRkZW4iPjxwYXRoIGQ9Ik0yNjQuMTI5IDI2MS4yNjJjNS4wMjUtNS45NCA0LjI4NS0xNS4yNS0zLjAwOS0yMS40MS02LjQ3NS01LjQzNS0xNi4wODUtMy45MzgtMjAuMzU0IDEuMTk4bC0zOC4wNzcgNDUuMzIzIDIzLjY2MiAxOS44NjYgMzcuNzc4LTQ0Ljk3N3ptLTQzLjkzNy01MC4wMTljLTYuMTQ0LTUuMTA0LTE1LjU2NS01LjI3Ny0xOS43ODctLjMxNWwtMzYuMjAzIDQzLjE2NiAyMi40MDIgMTguNzk0IDM1Ljc5My00Mi42NjFjNC41MzctNS4zNTcgNC41MDYtMTMuMzQ0LTIuMjA1LTE4Ljk4NHptNTY2LjQxMyAxMzUuODE0bC0yMi40NDktMjcuOTE2IDQ0LjcyNS02NS4zNzgtLjI4My0uMzE1LTczLjIwOCAzMC4xMjEtMjIuNjg2LTI3Ljc1OCA3Ny40OTMtOTkuNzIyIDE5LjEyNSAyMy42My00OC41MjIgNjMuNTA1IDc0LjE4NS0zMS44NyAyMC41MTIgMjUuMzYzLTQ2LjU2OSA2NS45MyA3Mi4yLTM0LjI4IDE5LjEyNiAyMy41OTktMTEzLjY0OSA1NS4wOTF6TTUwNy4xNjQgODA3LjAzOGMtMTY1LjYwNSAwLTI5OS44NzUtMTM0LjI1NC0yOTkuODc1LTI5OS44NzQgMC0xNjUuNTczIDEzNC4yNy0yOTkuODQzIDI5OS44NzUtMjk5Ljg0MyAxNjUuNjIgMCAyOTkuODc0IDEzNC4yNTQgMjk5Ljg3NCAyOTkuODQzIDAgMTY1LjYyLTEzNC4yNTQgMjk5Ljg3NC0yOTkuODc0IDI5OS44NzR6TTEyNi45MjkgMjY0Ljk4bDYwLjI5LTcxLjgyMmMxMi41MDgtMTQuODg3IDI5Ljk2NC0yNi43ODIgNDYuNTUyLTEyLjg0IDUuMTA1IDQuMjcgNy4yOTQgNS42ODggMTMuNTAxIDE3LjA0NiAxLjQ2NSA0LjAwMiAyLjU4NCAxMS4yOTYtLjE4OSAxOC40NDggMTQuNDE1LTguOTY0IDI5Ljc5LTYuMDM0IDM5LjcxNiAzLjYyMyAxNS4yODEgMTQuODU2IDEzLjA2IDMxLjk5Ni0xLjQ2NSA0OS4zMjZsLTYzLjU4MyA3NS43NzYtOTQuODIyLTc5LjU1N3ptMzExLjYxLTIwMy4yNTZoMzcuMjI3bDMzLjYxOSA4OCAzMy42MTktODhoMzcuMTYzdjEyMy41NzNoLTI0LjczNHYtODYuM2wtMzIuNTQ3IDg2LjNoLTI3LjA1bC0zMi40ODQtODYuM3Y4Ni4zSDQzOC41NFY2MS43MjR6bTY4LjYyNS0yMy45OTRDMjQ3LjkxOCAzNy43MyAzNy43MyAyNDcuOTE4IDM3LjczIDUwNy4xNjRjMCAyNTkuMjc2IDIxMC4xODggNDY5LjQ4IDQ2OS40MzQgNDY5LjQ4IDI1OS4zMDggMCA0NjkuNDgtMjEwLjIwNCA0NjkuNDgtNDY5LjQ2NVM3NjYuNDcyIDM3LjcxNSA1MDcuMTY0IDM3LjcxNXptMCA3NDkuOTk0YzE1NC45ODYgMCAyODAuNjA3LTEyNS41OSAyODAuNjA3LTI4MC41Nkg1MDcuMTY0Vjc4Ny43NHptLTI4MC41NzYtMjgwLjU2aDI4MC41NzZWMjI2LjYxOWMtMTU0Ljk3MSAwLTI4MC41NzYgMTI1LjYwNS0yODAuNTc2IDI4MC41NDV6bTI4MC41NzYgNDg5LjYzYy0yNjkuOTU4IDAtNDg5LjY0Ni0yMTkuNjU3LTQ4OS42NDYtNDg5LjYzIDAtMjY5Ljk1OCAyMTkuNjg4LTQ4OS42MyA0ODkuNjQ2LTQ4OS42MyAyNzAuMDA1IDAgNDg5LjY0NSAyMTkuNjcyIDQ4OS42NDUgNDg5LjYzIDAgMjY5Ljk3My0yMTkuNjQgNDg5LjYzLTQ4OS42NDUgNDg5LjYzem0wLTk5Ni43OTRDMjI3LjUgMCAwIDIyNy41MDEgMCA1MDcuMTY0YzAgMjc5LjY2MiAyMjcuNTAxIDUwNy4xOTUgNTA3LjE2NCA1MDcuMTk1IDI3OS42OTMgMCA1MDcuMTc5LTIyNy41MzMgNTA3LjE3OS01MDcuMTk1QzEwMTQuMzQzIDIyNy41IDc4Ni44NTcgMCA1MDcuMTYzIDB6IiBmaWxsPSIjQjlCRUMzIi8+PC9zdmc+" />
  </fc-wave-filter>

  <script type="module">
    // 从 fancy-components 中引入组件
    // 这里拿 FcWaveFilter 来举例
    import { FcWaveFilter } from 'https://unpkg.com/fancy-components'

    // new 就相当于全局注册了这个组件,相当于 Vue 的 Vue.component('fc-wave-filter', FcWaveFilter)
    new FcWaveFilter()
  </script>
</body>
</html>
复制代码

所用图片:

fancy-components中有个叫FcWaveFilter的组件,翻译过来就是波浪滤镜,也很形象,用这个组件把<img>标签包裹一下就可以变成这样:

在 React 项目中

npm i fancy-components

先在主文件中引入你想要的组件,然后 new 一下:

/* eslint-disable no-new */
import React from 'react'
import ReactDom from 'react-dom'
...
// 从 fancy-components 中引入 FcWaveFilter(波浪滤镜)
import { FcWaveFilter } from 'fancy-components'

// new 就相当于全局注册了这个组件,相当于 Vue 的 Vue.component('fc-wave-filter', FcWaveFilter)
new FcWaveFilter()
复制代码

然后在用的时候(xxx.jsx):

export default () => (
  <fc-wave-filter color="#047">
    <img src="data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOjFlbTtoZWlnaHQ6MWVtO3ZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJjdXJyZW50Q29sb3IiIG92ZXJmbG93PSJoaWRkZW4iPjxwYXRoIGQ9Ik0yNjQuMTI5IDI2MS4yNjJjNS4wMjUtNS45NCA0LjI4NS0xNS4yNS0zLjAwOS0yMS40MS02LjQ3NS01LjQzNS0xNi4wODUtMy45MzgtMjAuMzU0IDEuMTk4bC0zOC4wNzcgNDUuMzIzIDIzLjY2MiAxOS44NjYgMzcuNzc4LTQ0Ljk3N3ptLTQzLjkzNy01MC4wMTljLTYuMTQ0LTUuMTA0LTE1LjU2NS01LjI3Ny0xOS43ODctLjMxNWwtMzYuMjAzIDQzLjE2NiAyMi40MDIgMTguNzk0IDM1Ljc5My00Mi42NjFjNC41MzctNS4zNTcgNC41MDYtMTMuMzQ0LTIuMjA1LTE4Ljk4NHptNTY2LjQxMyAxMzUuODE0bC0yMi40NDktMjcuOTE2IDQ0LjcyNS02NS4zNzgtLjI4My0uMzE1LTczLjIwOCAzMC4xMjEtMjIuNjg2LTI3Ljc1OCA3Ny40OTMtOTkuNzIyIDE5LjEyNSAyMy42My00OC41MjIgNjMuNTA1IDc0LjE4NS0zMS44NyAyMC41MTIgMjUuMzYzLTQ2LjU2OSA2NS45MyA3Mi4yLTM0LjI4IDE5LjEyNiAyMy41OTktMTEzLjY0OSA1NS4wOTF6TTUwNy4xNjQgODA3LjAzOGMtMTY1LjYwNSAwLTI5OS44NzUtMTM0LjI1NC0yOTkuODc1LTI5OS44NzQgMC0xNjUuNTczIDEzNC4yNy0yOTkuODQzIDI5OS44NzUtMjk5Ljg0MyAxNjUuNjIgMCAyOTkuODc0IDEzNC4yNTQgMjk5Ljg3NCAyOTkuODQzIDAgMTY1LjYyLTEzNC4yNTQgMjk5Ljg3NC0yOTkuODc0IDI5OS44NzR6TTEyNi45MjkgMjY0Ljk4bDYwLjI5LTcxLjgyMmMxMi41MDgtMTQuODg3IDI5Ljk2NC0yNi43ODIgNDYuNTUyLTEyLjg0IDUuMTA1IDQuMjcgNy4yOTQgNS42ODggMTMuNTAxIDE3LjA0NiAxLjQ2NSA0LjAwMiAyLjU4NCAxMS4yOTYtLjE4OSAxOC40NDggMTQuNDE1LTguOTY0IDI5Ljc5LTYuMDM0IDM5LjcxNiAzLjYyMyAxNS4yODEgMTQuODU2IDEzLjA2IDMxLjk5Ni0xLjQ2NSA0OS4zMjZsLTYzLjU4MyA3NS43NzYtOTQuODIyLTc5LjU1N3ptMzExLjYxLTIwMy4yNTZoMzcuMjI3bDMzLjYxOSA4OCAzMy42MTktODhoMzcuMTYzdjEyMy41NzNoLTI0LjczNHYtODYuM2wtMzIuNTQ3IDg2LjNoLTI3LjA1bC0zMi40ODQtODYuM3Y4Ni4zSDQzOC41NFY2MS43MjR6bTY4LjYyNS0yMy45OTRDMjQ3LjkxOCAzNy43MyAzNy43MyAyNDcuOTE4IDM3LjczIDUwNy4xNjRjMCAyNTkuMjc2IDIxMC4xODggNDY5LjQ4IDQ2OS40MzQgNDY5LjQ4IDI1OS4zMDggMCA0NjkuNDgtMjEwLjIwNCA0NjkuNDgtNDY5LjQ2NVM3NjYuNDcyIDM3LjcxNSA1MDcuMTY0IDM3LjcxNXptMCA3NDkuOTk0YzE1NC45ODYgMCAyODAuNjA3LTEyNS41OSAyODAuNjA3LTI4MC41Nkg1MDcuMTY0Vjc4Ny43NHptLTI4MC41NzYtMjgwLjU2aDI4MC41NzZWMjI2LjYxOWMtMTU0Ljk3MSAwLTI4MC41NzYgMTI1LjYwNS0yODAuNTc2IDI4MC41NDV6bTI4MC41NzYgNDg5LjYzYy0yNjkuOTU4IDAtNDg5LjY0Ni0yMTkuNjU3LTQ4OS42NDYtNDg5LjYzIDAtMjY5Ljk1OCAyMTkuNjg4LTQ4OS42MyA0ODkuNjQ2LTQ4OS42MyAyNzAuMDA1IDAgNDg5LjY0NSAyMTkuNjcyIDQ4OS42NDUgNDg5LjYzIDAgMjY5Ljk3My0yMTkuNjQgNDg5LjYzLTQ4OS42NDUgNDg5LjYzem0wLTk5Ni43OTRDMjI3LjUgMCAwIDIyNy41MDEgMCA1MDcuMTY0YzAgMjc5LjY2MiAyMjcuNTAxIDUwNy4xOTUgNTA3LjE2NCA1MDcuMTk1IDI3OS42OTMgMCA1MDcuMTc5LTIyNy41MzMgNTA3LjE3OS01MDcuMTk1QzEwMTQuMzQzIDIyNy41IDc4Ni44NTcgMCA1MDcuMTYzIDB6IiBmaWxsPSIjQjlCRUMzIi8+PC9zdmc+" />
  </fc-wave-filter>
)
复制代码

注意千万不要写成驼峰形式的标签:<FcWaveFilter>

因为写组件写习惯了,想用组件的时候自然而然的就会想到这种写法。但实际上<fc-wave-filter>就和那些<div><a><p><ul><li>标签一样,属于HTML的原生标签啦!毕竟是用浏览器原生的组件化系统(web components)实现的,而不是采用了React的组件化系统,所以表现形式还是不一样的,不要搞混咯!而且也不需要像以前那样在用之前要引入一下:

// 不需要写成这样:
import { FcWaveFilter } from 'fancy-components'

export default () => (
  <fc-wave-filter color="#047">
    <img src="data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOjFlbTtoZWlnaHQ6MWVtO3ZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJjdXJyZW50Q29sb3IiIG92ZXJmbG93PSJoaWRkZW4iPjxwYXRoIGQ9Ik0yNjQuMTI5IDI2MS4yNjJjNS4wMjUtNS45NCA0LjI4NS0xNS4yNS0zLjAwOS0yMS40MS02LjQ3NS01LjQzNS0xNi4wODUtMy45MzgtMjAuMzU0IDEuMTk4bC0zOC4wNzcgNDUuMzIzIDIzLjY2MiAxOS44NjYgMzcuNzc4LTQ0Ljk3N3ptLTQzLjkzNy01MC4wMTljLTYuMTQ0LTUuMTA0LTE1LjU2NS01LjI3Ny0xOS43ODctLjMxNWwtMzYuMjAzIDQzLjE2NiAyMi40MDIgMTguNzk0IDM1Ljc5My00Mi42NjFjNC41MzctNS4zNTcgNC41MDYtMTMuMzQ0LTIuMjA1LTE4Ljk4NHptNTY2LjQxMyAxMzUuODE0bC0yMi40NDktMjcuOTE2IDQ0LjcyNS02NS4zNzgtLjI4My0uMzE1LTczLjIwOCAzMC4xMjEtMjIuNjg2LTI3Ljc1OCA3Ny40OTMtOTkuNzIyIDE5LjEyNSAyMy42My00OC41MjIgNjMuNTA1IDc0LjE4NS0zMS44NyAyMC41MTIgMjUuMzYzLTQ2LjU2OSA2NS45MyA3Mi4yLTM0LjI4IDE5LjEyNiAyMy41OTktMTEzLjY0OSA1NS4wOTF6TTUwNy4xNjQgODA3LjAzOGMtMTY1LjYwNSAwLTI5OS44NzUtMTM0LjI1NC0yOTkuODc1LTI5OS44NzQgMC0xNjUuNTczIDEzNC4yNy0yOTkuODQzIDI5OS44NzUtMjk5Ljg0MyAxNjUuNjIgMCAyOTkuODc0IDEzNC4yNTQgMjk5Ljg3NCAyOTkuODQzIDAgMTY1LjYyLTEzNC4yNTQgMjk5Ljg3NC0yOTkuODc0IDI5OS44NzR6TTEyNi45MjkgMjY0Ljk4bDYwLjI5LTcxLjgyMmMxMi41MDgtMTQuODg3IDI5Ljk2NC0yNi43ODIgNDYuNTUyLTEyLjg0IDUuMTA1IDQuMjcgNy4yOTQgNS42ODggMTMuNTAxIDE3LjA0NiAxLjQ2NSA0LjAwMiAyLjU4NCAxMS4yOTYtLjE4OSAxOC40NDggMTQuNDE1LTguOTY0IDI5Ljc5LTYuMDM0IDM5LjcxNiAzLjYyMyAxNS4yODEgMTQuODU2IDEzLjA2IDMxLjk5Ni0xLjQ2NSA0OS4zMjZsLTYzLjU4MyA3NS43NzYtOTQuODIyLTc5LjU1N3ptMzExLjYxLTIwMy4yNTZoMzcuMjI3bDMzLjYxOSA4OCAzMy42MTktODhoMzcuMTYzdjEyMy41NzNoLTI0LjczNHYtODYuM2wtMzIuNTQ3IDg2LjNoLTI3LjA1bC0zMi40ODQtODYuM3Y4Ni4zSDQzOC41NFY2MS43MjR6bTY4LjYyNS0yMy45OTRDMjQ3LjkxOCAzNy43MyAzNy43MyAyNDcuOTE4IDM3LjczIDUwNy4xNjRjMCAyNTkuMjc2IDIxMC4xODggNDY5LjQ4IDQ2OS40MzQgNDY5LjQ4IDI1OS4zMDggMCA0NjkuNDgtMjEwLjIwNCA0NjkuNDgtNDY5LjQ2NVM3NjYuNDcyIDM3LjcxNSA1MDcuMTY0IDM3LjcxNXptMCA3NDkuOTk0YzE1NC45ODYgMCAyODAuNjA3LTEyNS41OSAyODAuNjA3LTI4MC41Nkg1MDcuMTY0Vjc4Ny43NHptLTI4MC41NzYtMjgwLjU2aDI4MC41NzZWMjI2LjYxOWMtMTU0Ljk3MSAwLTI4MC41NzYgMTI1LjYwNS0yODAuNTc2IDI4MC41NDV6bTI4MC41NzYgNDg5LjYzYy0yNjkuOTU4IDAtNDg5LjY0Ni0yMTkuNjU3LTQ4OS42NDYtNDg5LjYzIDAtMjY5Ljk1OCAyMTkuNjg4LTQ4OS42MyA0ODkuNjQ2LTQ4OS42MyAyNzAuMDA1IDAgNDg5LjY0NSAyMTkuNjcyIDQ4OS42NDUgNDg5LjYzIDAgMjY5Ljk3My0yMTkuNjQgNDg5LjYzLTQ4OS42NDUgNDg5LjYzem0wLTk5Ni43OTRDMjI3LjUgMCAwIDIyNy41MDEgMCA1MDcuMTY0YzAgMjc5LjY2MiAyMjcuNTAxIDUwNy4xOTUgNTA3LjE2NCA1MDcuMTk1IDI3OS42OTMgMCA1MDcuMTc5LTIyNy41MzMgNTA3LjE3OS01MDcuMTk1QzEwMTQuMzQzIDIyNy41IDc4Ni44NTcgMCA1MDcuMTYzIDB6IiBmaWxsPSIjQjlCRUMzIi8+PC9zdmc+" />
  </fc-wave-filter>
)
复制代码

只要我们在主文件中引入并且new过就行:

import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()
复制代码

在 Vue2 中

React中很好的一点是组件和原生标签写法不一样,很容易区分:

import Ul form 'xxx'

export default () => (
  <Ul>
    <li/>
  </Ul>
)
复制代码

大写的驼峰形式的标签就是组件,小写的标签就是HTML标签,这样相对容易区分。

Vue就不一样了,Vue组件既可以写成大写字母开头的驼峰形式,又可以写成小写字母开头的短横线形式。那么问题来了:当我们写了一个短横线连接的组件时,它怎么知道我们写的到底是组件还是标签呢?

它的做法是把所有HTML以及SVG标签全列举出来,只要你写的标签不在这个范围内,那么就默认你是组件了,如果你还没有在components里注册过,那么就会在控制台打印一个警告。所以我们要告诉Vue:对我这个既不在HTML标签范围内,又不在SVG标签范围内,同时还不是Vue组件的标签来说就不要给我报警告啦,我确定一定以及肯定这不是个错误!

npm i fancy-components

还是先来到主文件,引入fancy-components

import Vue from 'vue'
import App from './App'
import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()

new Vue({
  render: h => h(App)
}).$mount('#app')
复制代码

然后用Vue.config来配置需要忽略哪些标签:

import Vue from 'vue'
import App from './App'
import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()

// 配置忽略以 fc- 作为开头的元素
Vue.config.ignoredElements = [/^fc-/]

new Vue({
  render: h => h(App)
}).$mount('#app')
复制代码

在用的时候(xxx.vue):

<template>
  <fc-wave-filter color="#047">
    <img src="data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgc3R5bGU9IndpZHRoOjFlbTtoZWlnaHQ6MWVtO3ZlcnRpY2FsLWFsaWduOm1pZGRsZSIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiBmaWxsPSJjdXJyZW50Q29sb3IiIG92ZXJmbG93PSJoaWRkZW4iPjxwYXRoIGQ9Ik0yNjQuMTI5IDI2MS4yNjJjNS4wMjUtNS45NCA0LjI4NS0xNS4yNS0zLjAwOS0yMS40MS02LjQ3NS01LjQzNS0xNi4wODUtMy45MzgtMjAuMzU0IDEuMTk4bC0zOC4wNzcgNDUuMzIzIDIzLjY2MiAxOS44NjYgMzcuNzc4LTQ0Ljk3N3ptLTQzLjkzNy01MC4wMTljLTYuMTQ0LTUuMTA0LTE1LjU2NS01LjI3Ny0xOS43ODctLjMxNWwtMzYuMjAzIDQzLjE2NiAyMi40MDIgMTguNzk0IDM1Ljc5My00Mi42NjFjNC41MzctNS4zNTcgNC41MDYtMTMuMzQ0LTIuMjA1LTE4Ljk4NHptNTY2LjQxMyAxMzUuODE0bC0yMi40NDktMjcuOTE2IDQ0LjcyNS02NS4zNzgtLjI4My0uMzE1LTczLjIwOCAzMC4xMjEtMjIuNjg2LTI3Ljc1OCA3Ny40OTMtOTkuNzIyIDE5LjEyNSAyMy42My00OC41MjIgNjMuNTA1IDc0LjE4NS0zMS44NyAyMC41MTIgMjUuMzYzLTQ2LjU2OSA2NS45MyA3Mi4yLTM0LjI4IDE5LjEyNiAyMy41OTktMTEzLjY0OSA1NS4wOTF6TTUwNy4xNjQgODA3LjAzOGMtMTY1LjYwNSAwLTI5OS44NzUtMTM0LjI1NC0yOTkuODc1LTI5OS44NzQgMC0xNjUuNTczIDEzNC4yNy0yOTkuODQzIDI5OS44NzUtMjk5Ljg0MyAxNjUuNjIgMCAyOTkuODc0IDEzNC4yNTQgMjk5Ljg3NCAyOTkuODQzIDAgMTY1LjYyLTEzNC4yNTQgMjk5Ljg3NC0yOTkuODc0IDI5OS44NzR6TTEyNi45MjkgMjY0Ljk4bDYwLjI5LTcxLjgyMmMxMi41MDgtMTQuODg3IDI5Ljk2NC0yNi43ODIgNDYuNTUyLTEyLjg0IDUuMTA1IDQuMjcgNy4yOTQgNS42ODggMTMuNTAxIDE3LjA0NiAxLjQ2NSA0LjAwMiAyLjU4NCAxMS4yOTYtLjE4OSAxOC40NDggMTQuNDE1LTguOTY0IDI5Ljc5LTYuMDM0IDM5LjcxNiAzLjYyMyAxNS4yODEgMTQuODU2IDEzLjA2IDMxLjk5Ni0xLjQ2NSA0OS4zMjZsLTYzLjU4MyA3NS43NzYtOTQuODIyLTc5LjU1N3ptMzExLjYxLTIwMy4yNTZoMzcuMjI3bDMzLjYxOSA4OCAzMy42MTktODhoMzcuMTYzdjEyMy41NzNoLTI0LjczNHYtODYuM2wtMzIuNTQ3IDg2LjNoLTI3LjA1bC0zMi40ODQtODYuM3Y4Ni4zSDQzOC41NFY2MS43MjR6bTY4LjYyNS0yMy45OTRDMjQ3LjkxOCAzNy43MyAzNy43MyAyNDcuOTE4IDM3LjczIDUwNy4xNjRjMCAyNTkuMjc2IDIxMC4xODggNDY5LjQ4IDQ2OS40MzQgNDY5LjQ4IDI1OS4zMDggMCA0NjkuNDgtMjEwLjIwNCA0NjkuNDgtNDY5LjQ2NVM3NjYuNDcyIDM3LjcxNSA1MDcuMTY0IDM3LjcxNXptMCA3NDkuOTk0YzE1NC45ODYgMCAyODAuNjA3LTEyNS41OSAyODAuNjA3LTI4MC41Nkg1MDcuMTY0Vjc4Ny43NHptLTI4MC41NzYtMjgwLjU2aDI4MC41NzZWMjI2LjYxOWMtMTU0Ljk3MSAwLTI4MC41NzYgMTI1LjYwNS0yODAuNTc2IDI4MC41NDV6bTI4MC41NzYgNDg5LjYzYy0yNjkuOTU4IDAtNDg5LjY0Ni0yMTkuNjU3LTQ4OS42NDYtNDg5LjYzIDAtMjY5Ljk1OCAyMTkuNjg4LTQ4OS42MyA0ODkuNjQ2LTQ4OS42MyAyNzAuMDA1IDAgNDg5LjY0NSAyMTkuNjcyIDQ4OS42NDUgNDg5LjYzIDAgMjY5Ljk3My0yMTkuNjQgNDg5LjYzLTQ4OS42NDUgNDg5LjYzem0wLTk5Ni43OTRDMjI3LjUgMCAwIDIyNy41MDEgMCA1MDcuMTY0YzAgMjc5LjY2MiAyMjcuNTAxIDUwNy4xOTUgNTA3LjE2NCA1MDcuMTk1IDI3OS42OTMgMCA1MDcuMTc5LTIyNy41MzMgNTA3LjE3OS01MDcuMTk1QzEwMTQuMzQzIDIyNy41IDc4Ni44NTcgMCA1MDcuMTYzIDB6IiBmaWxsPSIjQjlCRUMzIi8+PC9zdmc+" />
  </fc-wave-filter>
</template>

<script>
export default {
  components: {
    // 不需要在这里进行注册 就把 <fc-wave-filter> 当成一个浏览器原生标签就行
  }
}
</script>
复制代码

在 vue-cli 的 Vue3 项目中

Vue3 在写法上出现了很大的变化,没有Vue了,取而代之的是app

import { createApp } from 'vue'
import App from './App'
import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()

createApp(App).mount('#app')
复制代码

那么是不是把原来的Vue换成app就行了呢:

// 以前
Vue.config.ignoredElements = [/^fc-/]

// 现在
app.config.ignoredElements = [/^fc-/]
复制代码

很可惜答案是否定的,Vue3处理起来相对要稍微麻烦一点,我们需要在根目录下的vue.config.js中(如果没有就自己新建一个):

module.exports = {
    chainWebpack: config => {
        config.module
            .rule('vue')
            .use('vue-loader')
            .tap(options => {
                options.compilerOptions = {
                    ...(options.compilerOptions || {}),
                    isCustomElement: tag => tag.startsWith('fc-')
                }
                return options
            })
    }
}
复制代码

这样就可以啦!

在 Vite 的 Vue3 项目中

npm i fancy-components

来到主文件引入fancy-componentsnew一下:

import { createApp } from 'vue'
import App from './App'
import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()

createApp(App).mount('#app')
复制代码

然后我们再来到vite.config.js中,把配置改成这样即可:

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue({
    template: {
      compilerOptions: {
        isCustomElement: tag => tag.startsWith('fc-')
      }
    }
  })]
})
复制代码

各组件用法

FcWaveFilter

这款组件非常适合用来生成波浪形式的加载动画,在国庆期间我们就用了这款组件做成了🇨🇳样式的波浪动画。

API

CSS属性含义可选值默认值
--width组件的宽度正常的CSS宽度值fit-content
--height组件的高度正常的CSS高度值fit-content
--color填充颜色正常的CSS颜色值black

标签属性含义可选值默认值
color填充颜色正常的CSS颜色值'black'
dur动画时长大于0的数字(单位为秒)3
amplitude波浪幅度数字(原波浪幅的倍数)1
delay填充后持续的时间大于0的数字(单位为秒)0
mode动画模式'alpha'(透明度)、'luminance'(亮度)、'img'(图片)、'slideshow'(幻灯片)'alpha'
interval几秒一切换(适合幻灯片模式)大于0的数字(单位为秒)0

但可惜的是由于某些原因我没法把🇨🇳国旗相关的图片贴上来,那么我们干脆换一个别的国家的国旗给大家展示一下效果。找个跟咱们比较友好的国家的国旗吧!哪个国家跟咱们关系好?首先想到的肯定是:🇵🇰

但这面🇵🇰左侧有较大一片空白,导致波浪效果不明显,所以我们再换一面旗,换成这个吧:🇪🇺

其实上面的效果跟中国国旗的效果比起来还是差了不少,这款FcWaveFilter组件的具体用法我已经在之前的:《波浪动画很常见,但这个波浪组件绝对不常见》这篇文章里非常详细的介绍过了,所以就不占用本篇文章的篇幅了,感兴趣的朋友可以点进去看看

这里只讲一下基本用法,就是我们找一张纯色(最好为浅灰色)的png镂空图片,比方说我们找了张这个图:

我们只需要用<fc-wave-filter>这个标签把图片包起来,并给一个color属性作为填充颜色即可:

<template>
  <fc-wave-filter color="#047">
    <img src="bwm.png" />
  </fc-wave-filter>
</template>

<script>
import { FcWaveFilter } from 'fancy-components'

/* eslint-disable no-new */
new FcWaveFilter()

export default {}
复制代码

FcChina

听名字也能猜到这是一款什么组件了吧?不过还是由于那个原因,这篇文章没法上传与🇨🇳有关的图片,所以大家只能点进这个链接去看看这炫酷的国旗特效了,放在7.110.1这种日子里作为开场动画效果简直吊炸天。

API

CSS属性含义可选值默认值
--width组件的宽度正常的CSS宽度值300px
--height组件的高度正常的CSS高度值200px
--star-stroke-color五颗五角星在执行描边动画时的描边颜色正常的CSS颜色值red
--star-fill-color五颗五角星在执行填充动画时的填充颜色正常的CSS颜色值red
--flag-stroke-color当国旗执行描边动画时的描边颜色正常的CSS颜色值red
--dalay延时执行动画正常的CSS时间值0s
--dur整段动画的执行时间正常的CSS时间值6.6s
<template>
  <fc-china></fc-china>
</template>

<script>
import { FcChina } from 'fancy-components'

/* eslint-disable no-new */
new FcChina()

export default {}
</script>
复制代码

它的默认宽高是300pxx200px,我们可以通过--width--height这两个CSS自定义属性(又称CSS变量)来改变它的宽高:

<template>
  <fc-china></fc-china>
</template>

<script>
import { FcChina } from 'fancy-components'

/* eslint-disable no-new */
new FcChina()

export default {}
</script>

<style>
fc-china {
  --width: 600px;
  --height: 200px;
}
</style>
复制代码

(本文没法贴🇨🇳图片,这里的效果就是国旗被拉伸导致五颗五角星⭐️变形了)

变得这么难看的原因是因为我们给的宽高没有按照3:2的这么一个宽高来,中国国旗🇨🇳的默认宽高比就是3:2,我们还可以修改动画运行时的颜色:

<template>
  <fc-china></fc-china>
</template>

<script>
import { FcChina } from 'fancy-components'

/* eslint-disable no-new */
new FcChina()

export default {}
</script>

<style>
fc-china {
  --star-stroke-color: black;
  --star-fill-color: aqua;
  --flag-stroke-color: #ff8ef9;
}
</style>
复制代码

(本文没法贴🇨🇳图片,这里的效果就是可以生成其他的颜色的五角星,描边动画的颜色也可以换,只不过动画快要结束时五星红旗依然会恢复经典的红黄配色)

这里只能修改动画运行时的颜色,动画结束后国旗还是会回归到它原本的红黄配色,毕竟国旗神圣,不可随意修改颜色嘛!我们准备监听它身上的animationend事件,当国旗动画一结束我们就写一个背景扩散的效果来回到首页:

<template>
  <fc-china @animationend="onEnd"></fc-china>
</template>

<script>
import { FcChina } from 'fancy-components'

/* eslint-disable no-new */
new FcChina()

export default {
  methods: {
    onEnd () {
      // 在这里写一些逻辑
    }
  }
}
</script>
复制代码

FcWarpBtn

这是我最喜欢的一款按钮组件:

API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值200px
--height组件高度正常的CSS高度值40px
--color组件颜色正常的CSS颜色值#1cd
--shadow-color组件阴影颜色正常的CSS颜色值rgba(0, 0, 0, .5)

标签属性含义取值范围默认值
text-align文本排列方式'left'、'center'、'right''right'
<template>
  <fc-warp-btn></fc-warp-btn>
</template>

<script>
import { FcWarpBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcWarpBtn()

export default {}
</script>
复制代码

我们可以通过--color这个CSS自定义属性(又称CSS变量)来改变它的整体颜色:

<template>
  <fc-warp-btn></fc-warp-btn>
</template>

<script>
import { FcWarpBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcWarpBtn()

export default {}
</script>

<style>
fc-warp-btn {
  --color: gold
}
</style>
复制代码

想要改变里面的文字的话就在标签里面写:

<fc-warp-btn>翘边按钮</fc-warp-btn>
复制代码

我们发现文字默认是居左的,在文字比较少的情况下居左并不好看,所以我们可以用text-align属性来给它变成居中的:

<fc-warp-btn text-align="center">翘边按钮</fc-warp-btn>
复制代码

其实还是不怎么好看,我们用--width来给它变短一点吧:

<template>
  <fc-warp-btn text-align="center">翘边按钮</fc-warp-btn>
</template>

<script>
import { FcWarpBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcWarpBtn()

export default {}
</script>

<style>
fc-warp-btn {
  --width: 160px
}
</style>
复制代码

个人感觉这个按钮不太适合文字较短的按钮,因为这个按钮就是长了才好看,短了就不好看了。另外,--shadow-color指的是这里的阴影颜色:

Fc3DBtn

API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值100px
--height组件高度正常的CSS高度值36px
--color组件颜色正常的CSS颜色值#a69
--cover-color组件凸起的那部分颜色正常的CSS颜色值#0005
--shadow-color组件阴影颜色正常的CSS颜色值#0008
--inset-shadow-color组件内阴影颜色正常的CSS颜色值#fffc
--inset-shadow-color-active组件内阴影在按钮处于点击状态时的颜色正常的CSS颜色值var(--inset-shadow-color)

这个按钮我很喜欢,我们来给它换个颜色换个文字看看:

<template>
  <div class="container">
    <fc-3d-btn>立体按钮</fc-3d-btn>
  </div>
</template>

<script>
import { Fc3DBtn } from 'fancy-components'

/* eslint-disable no-new */
new Fc3DBtn()

export default {}
</script>

<style scoped>
.container {
  padding: 300px;
  background: #4d317a;
}

fc-3d-btn {
  --color: #6e50a6;
  --shadow-color: rgba(255, 255, 255, .4);
  --cover-color: rgba(0, 0, 0, .4);
  --inset-shadow-color: rgb(29, 4, 54);
  --inset-shadow-color-active: rgba(49, 23, 75, .9);
}
</style>
复制代码

FcDblWarpBtn

API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值180px
--height组件高度正常的CSS高度值40px
--color组件颜色正常的CSS颜色值#1cd
--shadow-color阴影颜色正常的CSS颜色值#0005
<template>
  <fc-dbl-warp-btn></fc-dbl-warp-btn>
</template>

<script>
import { FcDblWarpBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcDblWarpBtn()

export default {}
</script>
复制代码

这个双翘边按钮的名字确实是有点太长了,我们其实是可以在注册组件的时候为其改名的,只需要在new的时候传进一个字符串即可,这个字符串便会成为标签的名字。不过名字也不是瞎起的,还是需要遵守web components的命名规范的,比如必须字母开头,必须有短横线进行连接等。这么写效果也是完全一样的:

<template>
  <fc-btn></fc-btn>
</template>

<script>
import { FcDblWarpBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcDblWarpBtn('fc-btn')

export default {}
</script>
复制代码

理论上来说我们采用啥字母开头都行,但如果是在Vue项目中,我们配置的不是忽略fc-开头的元素么,所以起的新名最好也是fc-开头。注意不要与其他组件重名。

FcUnderlineBtn、FcPixelBtn、FcParenthesesBtn、FcRoundBtn

FcUnderlineBtn API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值100px
--height组件高度正常的CSS高度值30px
--color组件颜色正常的CSS颜色值#1cd

FcPixelBtn API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值100px
--height组件高度正常的CSS高度值40px
--color组件颜色正常的CSS颜色值#1cd

FcParenthesesBtn API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值80px
--height组件高度正常的CSS高度值30px
--color组件颜色正常的CSS颜色值#1cd

FcRoundBtn API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值100px
--height组件高度正常的CSS高度值40px
--color组件颜色正常的CSS颜色值#1cd

这几款按钮的API都一模一样,所以只拿一个举例就够了:

<template>
  <fc-underline-btn></fc-underline-btn>
</template>

<script>
import { FcUnderlineBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcUnderlineBtn()

export default {}
</script>
复制代码

除了--width--height这俩控制宽高的CSS自定义属性外,还有一个--color可以控制整体颜色:

<template>
  <fc-underline-btn></fc-underline-btn>
</template>

<script>
import { FcUnderlineBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcUnderlineBtn()

export default {}
</script>

<style>
fc-underline-btn {
  --color: red
}
</style>
复制代码

FcArrowBtn

API

CSS属性含义取值范围默认值
--width组件宽度正常的CSS宽度值100px
--height组件高度正常的CSS高度值30px
--color组件颜色正常的CSS颜色值#1cd

标签属性含义可选值默认值
right箭头朝右写或不写不写

箭头按钮跟上面的那几个按钮一样也是只有三个CSS自定义属性,只不过就是多了一个名为right的标签属性,箭头默认不是朝左的么,加上right就朝右了:

<template>
  <fc-arrow-btn right>下一步</fc-arrow-btn>
</template>

<script>
import { FcArrowBtn } from 'fancy-components'

/* eslint-disable no-new */
new FcArrowBtn()

export default {}
</script>
复制代码

FcTypingInput

API

CSS属性含义可选值默认值
--width组件的宽度正常的CSS宽度值220px
--height组件的高度正常的CSS高度值40px
--color整体颜色正常的CSS颜色值#caf
--border-color边框颜色正常的CSS颜色值#caf
--border-color-hoverhover状态下的边框颜色正常的CSS颜色值var(--color)
--border-color-focusfocus状态下的边框颜色正常的CSS颜色值var(--border-color-hover)
--border-radius圆角正常的CSS圆角值4px
--box-shadow-focus在focus状态下的input框盒阴影正常的CSS阴影值0 0 6px var(--border-color-focus)
--circle-colorinput框在无值并且非focus状态时里面的那个小圆点的颜色正常的CSS颜色值#0003
--circle-color-hoverinput框在无值并处于hover状态下里面的那个小圆点的颜色正常的CSS颜色值var(--circle-color)
--placeholder-colorplaceholder的颜色正常的CSS颜色值#0005
--placeholder-color-focusplaceholder在input框处于focus状态时的颜色正常的CSS颜色值var(--border-color-focus)
--placeholder-animate-colorplaceholder在input框内执行动画时的颜色正常的CSS颜色值red
--placeholder-animate-title-colorplaceholder在input框的头上执行动画时的颜色正常的CSS颜色值#00ff6b
--placeholder-shadowplaceholder的文本阴影正常的CSS文本阴影值none
--stripe-colorinput框在disabled状态时产生的条纹颜色正常的CSS颜色值#0003
--stripe-deginput框在disabled状态时产生的条纹角度数字45
--disabled-filterinput框在disabled状态时的滤镜正常的CSS滤镜值opacity(80%) grayscale(100%)

标签属性含义可选值默认值
whiteinput框的主题颜色为白色(适用于暗色背景)写或不写不写
redinput框的主题颜色为红色(适用于校验不通过时)写或不写不写

我们给它加个disabled属性看看会变成什么样:

<template>
  <fc-typing-input placeholder="UserName" disabled></fc-typing-input>
</template>

<script>
import { FcTypingInput } from 'fancy-components'

/* eslint-disable no-new */
new FcTypingInput()

export default {}
</script>
复制代码

这些CSS自定义属性看似很多很不好记,实则大部分情况压根儿就用不到,因为我们的背景最常见的一个是这种白色为主的亮色模式,另一个就是暗色模式了,比方说我们把背景色换成暗紫色来看看:

看起来效果很不明显对吧?我们难道还要挨个去调各种颜色吗?当然不用,有一个快捷的CSS自定义属性--color,设置它一个就可以把字体颜色、placeholder颜色、圆圈颜色(hover)、边框颜色(hover)等一系列颜色设置了:

<template>
  <fc-typing-input placeholder="UserName"></fc-typing-input>
</template>

<script>
import { FcTypingInput } from 'fancy-components'

/* eslint-disable no-new */
new FcTypingInput()

export default {}
</script>

<style>
fc-typing-input {
  --color: black
}
</style>
复制代码

还有一个适合在暗色背景下用的标签属性white,写上了它就会自动帮我们把各种边框颜色各种字体颜色调成白色:

<fc-typing-input placeholder="UserName" white></fc-typing-input>
复制代码

在默认情况下placeholder本来是没有文本阴影的,但加上了white这个标签属性后它就会为我们自动设置一个白色的文本阴影,看起来就像是文字在发光一样,这在暗色模式下非常好看,如果不喜欢的话也可以直接把--placeholder-shadow-color设置为none,然后再把--placeholder-color换个浅一点的颜色:

<template>
  <fc-typing-input placeholder="UserName" white></fc-typing-input>
</template>

<script>
import { FcTypingInput } from 'fancy-components'

/* eslint-disable no-new */
new FcTypingInput()

export default {}
</script>

<style>
body {
  background: #3f2766
}

fc-typing-input {
  --placeholder-color: #fff8;
  --placeholder-shadow: none;
}
</style>
复制代码

这样看起来确实不怎么好看,所以那个white属性应该是精心配置了各个颜色的值,以达到最佳效果。

除了white还有个redwhite不是让整体颜色变白么?那red就是让整体颜色变红:

一般用于表单校验没通过时。那--placeholder-animate-color--placeholder-animate-title-color这两个属性是干嘛的呢?我们在白色背景下给标签加上一个white属性:

什么也没有?这是因为我们的边框是白色的、字体是白色的、placeholder也是白色的,这跟白色的背景融为一体了,不过我们用鼠标点击一下再看看:

这回看到没?placeholder在动画执行时是会变一下颜色的,--placeholder-animate-color是在框里执行动画时会变的颜色,而--placeholder-animate-title-color是在框上面(也就是title位)执行动画时会变的颜色。(大部分情况下都不会用到)

比较遗憾的一点是这个输入框在Vue中不能使用v-model,因为Vue检测到他不是input元素,不过我们只需要写成这样即可:

<template>
  <fc-typing-input :value="value" @input="onInput"></fc-typing-input>
</template>

<script>
import { FcTypingInput } from 'fancy-components'

/* eslint-disable no-new */
new FcTypingInput()

export default {
  data: () => ({ value: '666' }),
  methods: {
    onInput (event) {
      this.value = event.target.value
    }
  }
}
</script>
复制代码

⚠️该组件不支持change事件 并且type属性只支持textpassword

<template>
  <fc-typing-input
    :value="value"
    @input="onInput"
    type="password"
    placeholder="请输入密码"
  ></fc-typing-input>
</template>

<script>
import { FcTypingInput } from 'fancy-components'

/* eslint-disable no-new */
new FcTypingInput()

export default {
  data: () => ({ value: '666666' }),
  methods: {
    onInput (event) {
      this.value = event.target.value
    }
  }
}
</script>
复制代码

FcBubbles

API

CSS属性含义可选值默认值
--color填充颜色正常的CSS颜色值#1cd
--width组件的宽度正常的CSS宽度值fit-content
--height组件的高度正常的CSS高度值fit-content

标签属性含义可选值默认值
active通过active属性来控制气泡动效的显隐'true'、'false''false'
click通过鼠标点击来控制气泡动效的显隐写或不写不写

这个组件非常好玩,它和FcWaveFilter一样,都是自己本身不产生效果,而是为子元素添加效果,用active属性来控制气泡效果,比如说好多网站都有❤️这么一个效果:

这个小心心❤️很可爱吧?但它没有任何的动画,所以有些略显单调,此时我们就用<fc-bubbles>来把它包裹起来:

<template>
  <fc-bubbles
    :active="isLike"
    @click="isLike = !isLike"
  >
    <svg viewBox="0 0 1024 1024" width="100" height="100">
      <path
        d="M288.105 122.229C174.047 122.21 64.691 231.687 64.691 388.095c0 176.07 156.747 241.891 261.855 312.283 101.962 68.266 174.057 161.602 185.453 201.393 9.743-38.936 91.03-135.019 185.448-203.373 103.196-74.727 261.861-136.19 261.861-312.262 0-152.117-109.34-260.294-222.908-260.294-86.792 0-167.781 15.754-224.419 128.441-65.593-111.977-138.495-132.042-223.876-132.054"
        stroke="black"
        stroke-width="22"
        :fill="isLike ? 'red' : 'none'"
      />
     </svg>
  </fc-bubbles>
</template>

<script setup>
import { ref } from 'vue'

const isLike = ref(false)
</script>

<style scoped>
fc-bubbles { --color: #ff3874 }
svg { display: block }
</style>
复制代码

上面这种情况是需要靠active这个属性来控制动画的出现时机,当active="true"时运行气泡动画,active="false"时停止动画。

⚠️ 只有active="false"时再把active变成true才会有效果。

这是什么意思呢?比如我们想要把这个<fc-bubbles>放在某个按钮上,想要一点按钮就出现效果,那么如果我们写成这样:

<template>
  <fc-bubbles @click="handleClick" :active="isActive">
    <fc-3d-btn></fc-3d-btn>
  </fc-bubbles>
</template>

<script setup>
import { ref } from '@vue/runtime-core'
import { FcBubbles, Fc3DBtn } from 'fancy-components';

/* eslint-disable no-new */
new FcBubbles()
new Fc3DBtn()

const isActive = ref(false)
const handleClick = () => isActive.value = true
</script>

<style scoped>
fc-bubbles {
  --color: #6195f9;
}
</style>
复制代码

发现只有第一次点击时有效果,剩下的点击啥效果也没有,这是因为第一次点击之前active的值为false,第一次点击时把它变成了true,但却没有把它变回false,于是active就一直为true了,相当于第一次点击过后这个值就一直都没有发生任何的变化了,所以才不会有效果。

那我们把handleClick这个函数写成这样不就行了:

const handleClick = () => {
  isActive.value = true
  isActive.value = false
}
复制代码

注意这种写法并不可取,因为active="true"时动画才刚出现,紧接着就把active变成了false,动画就会消失掉,看起来就跟什么效果都没出现一样。可是我们就是想在点击时出现个气泡动画罢了,有必要搞得这么麻烦么?当然没必要啦!因为有个click属性是专门是干这个的:

<template>
  <!-- 在 Vue3 中需要把 click 的首字母大写才会生效 -->
  <fc-bubbles click>
    <fc-3d-btn></fc-3d-btn>
  </fc-bubbles>
</template>

<script>
import { FcBubbles, Fc3DBtn } from 'fancy-components';

/* eslint-disable no-new */
new FcBubbles()
new Fc3DBtn()
</script>

<style scoped>
fc-bubbles {
  --color: #6195f9;
}
</style>
复制代码

<fc-bubbles>这个标签上写上一个click属性就可以让每次点击时都出现气泡效果。由于气泡出现的时机变成了点击时出现,所以就不再需要active这个属性来控制时机了,clickactive这两个属性最好不要同时出现,不然会有bug

Vue3里有这样一个bug:在一个标签中写click属性:

<template>
  <fc-bubbles click></fc-bubbles>
</template>
复制代码

编译后这个click属性却并没有出现在这个标签上,并且页面上也没有任何的报错,而Vue2就没有这个bug,可是我们就是想在Vue3里写这个click属性怎么办呢?答案就是把click的首字母大写:

<template>
  <fc-bubbles Click></fc-bubbles>
</template>
复制代码

这样就不会有问题啦!

之前在公司的多个页面都用过这一效果:

这个老虎机效果用的是《产品经理:能不能让这串数字滚动起来?》这篇文章里的组件,当时的需求是三位数字滚动,当滚动停止时的数字如果为001,就会变成1st002就是2nd0033rd、剩下的数字就是xxxth。而且后面的那个旗的颜色一开始是灰色,只有滚动的数字停下来的时候才会知道第几名,前3名旗的颜色是这个色、前十是那个色、前100又换个别的色、100之后又是个什么色……

总之,当数字停下来后会有一系列的突变(文字+颜色),效果十分突兀,必须要有个什么动画来掩饰一下,于是就用了<fc-bubbles>这个组件,没想到效果出奇的好,当时监听了animationend这个事件,当996的动画一停住就触发这个事件,紧接着把active调成true,效果就这样完成啦!

大家如果碰到那种比较突兀的变化时可以试着用这个组件来掩饰一下,效果还算不错。

这个效果我曾在GitHub上看到过,看起来应该是类似的实现方式,地址贴到这里,感兴趣的可以点进去看看。

fancy-components 仓库地址

github.com/fancy-compo…

这么酷的项目居然没有多少star,可能是因为刚刚起步还没有多少人知道吧?不过我这一波推广应该能让不少人知道。就像Naive UI那样,尤大发个微博发个推特,立马涨了好几千star,只是我应该没尤大那么牛B😂

往期精彩文章

文章分类
前端