点击查看更新记录

更新记录

2021-12-21:插件版1.0.5

  1. 将cdn配置项外露,支持自定义CDN链接
  2. 将CDN改为npm.elemecdn.com

2021-06-19:新增提示

  1. 插件化完成。从此告别繁琐的配置。
  2. 只需两步,安装插件,添加配置项。

2021-01-31:新增提示

  1. 更新butterfly_v3.6.0适配方案

2020-12-26:内测版v0.04

  1. 新增外挂标签写法

2020-12-26:内测版v0.03

  1. 在基础方案基础上实现插件化配置。
  2. 新增四个配置项
  3. 优化配置逻辑,弃用_data/wowjs.yml
  4. 支持直接在主题配置文件内配置动画类和动画效果
  5. 优化了各静态资源的引入逻辑

2020-12-24:内测版v0.02

  1. 优化基础引入方案的异步加载和pjax适配

2020-12-23:内测版v0.01

  1. 编写参考文档
  2. 编写TODO
  3. 编写基础引入方案
点击查看参考教程
参考方向教程原贴
动画样式依赖animate.css
wowjs文档

插件化版本(推荐)

安装插件即可使用,已包含外挂标签内容
  1. 安装插件,在博客根目录[Blogroot]下打开终端,运行以下指令:

    1
    npm install hexo-butterfly-wowjs --save
  2. 添加配置信息,以下为写法示例
    在站点配置文件_config.yml或者主题配置文件_config.butterfly.yml中添加

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    wowjs:
    enable: true #控制动画开关。true是打开,false是关闭
    priority: 10 #过滤器优先级
    mobile: false #移动端是否启用,默认移动端禁用
    animateitem:
    - class: recent-post-item #必填项,需要添加动画的元素的class
    style: animate__zoomIn #必填项,需要添加的动画
    duration: 2s #选填项,动画持续时间,单位可以是ms也可以是s。例如3s,700ms。
    delay: 1s #选填项,动画开始的延迟时间,单位可以是ms也可以是s。例如3s,700ms。
    offset: 100 #选填项,开始动画的距离(相对浏览器底部)
    iteration: 2 #选填项,动画重复的次数
    - class: card-widget
    style: animate__zoomIn
    animate_css: https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/animate.min.css
    wow_js: https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow.min.js
    wow_init_js: https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow_init.js
  3. 参数释义
参数备选值/类型释义
enabletrue/false【必选】控制开关
prioritynumber【可选】过滤器优先级,数值越小,执行越早,默认为10,选填
mobiletrue/false控制移动端是否启用,默认移动端禁用
animateitem.classclass【可选】添加动画类名,只支持给class添加
animateitem.styletext【可选】动画样式,具体类型参考animate.css
animateitem.durationtime,单位为s或ms【可选】动画持续时间,单位可以是ms也可以是s。例如3s,700ms。
animateitem.delaytime,单位为s或ms【可选】动画开始的延迟时间,单位可以是ms也可以是s。例如3s,700ms。
animateitem.offsetnumber,单位为px【可选】开始动画的距离(相对浏览器底部)。
animateitem.iterationnumber,单位为s或ms【可选】动画重复的次数
animate_cssURL【可选】animate.css的CDN链接,默认为https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/animate.min.css
wow_jsURL【可选】wow.min.js的CDN链接,默认为https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow.min.js
wow_init_jsURL【可选】wow_init.js的CDN链接,默认为https://npm.elemecdn.com/hexo-butterfly-wowjs/lib/wow_init.js

1
2
3
{% wow [animete],[duration],[delay],[offset],[iteration] %}
内容
{% endwow %}
  1. animate: 动画样式,效果详见animate.css参考文档
  2. duration: 选填项,动画持续时间,单位可以是ms也可以是s。例如3s700ms
  3. delay: 选填项,动画开始的延迟时间,单位可以是ms也可以是s。例如3s700ms
  4. offset: 选填项,开始动画的距离(相对浏览器底部)
  5. iteration: 选填项,动画重复的次数

注意,后面四个虽然是选填项,但是当有跨位选填时,次序不能乱。详见示例。
支持嵌套其他外挂标签。

  1. flip动画效果。

    flip动画效果。

  2. zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10次。

    zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10

  3. slideInRight动画效果,持续5s,延时5s

    slideInRight动画效果,持续5s,延时5s

  4. heartBeat动画效果,延时5s,重复10次。

    heartBeat动画效果,延时5s,重复10次。

  1. flip动画效果。
    1
    2
    3
    4
    5
    {% wow animate__flip %}
    {% note green 'fas fa-fan' modern%}
    `flip`动画效果。
    {% endnote %}
    {% endwow %}
  2. zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10次。
    1
    2
    3
    4
    5
    {% wow animate__zoomIn,5s,5s,100,10 %}
    {% note blue 'fas fa-bullhorn' modern%}
    `zoomIn`动画效果,持续`5s`,延时`5s`,离底部`100`距离时启动,重复`10`次
    {% endnote %}
    {% endwow %}
  3. slideInRight动画效果,持续5s,延时5s
    1
    2
    3
    4
    5
    {% wow animate__slideInRight,5s,5s %}
    {% note orange 'fas fa-car' modern%}
    `slideInRight`动画效果,持续`5s`,延时`5s`。
    {% endnote %}
    {% endwow %}
  4. heartBeat动画效果,延时5s,重复10次。此处注意不用的参数位置要留空,用逗号间隔。
    1
    2
    3
    4
    5
    {% wow animate__heartBeat,,5s,,10 %}
    {% note red 'fas fa-battery-half' modern%}
    `heartBeat`动画效果,延时`5s`,重复`10`次。
    {% endnote %}
    {% endwow %}

基础引用

若您不想修改源码,只需使用基础引用方案即可
  1. 新建[Blogroot]\themes\butterfly\source\js\wow_init.js,配置特性动画的默认项。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    wow = new WOW({
    boxClass: 'wow',
    // 当用户滚动时显示隐藏框的类名称
    animateClass: 'animate__animated',
    // 触发 CSS 动画的类名称(动画库默认为"animate.css"库)
    offset: 0,
    // 定义浏览器视口底部与隐藏框顶部之间的距离。
    // 当用户滚动并到达此距离时,将显示隐藏的框。
    mobile: false,
    // 在移动设备上打开/关闭wow.js。
    live: true
    // 在页面上检查新的 wow.js元素。
    })
    wow.init();
  2. 引入js和css样式,修改[Blogroot]\_config.butterfly.ymlinject配置项,添加样式资源。

    1
    2
    3
    4
    5
    6
    inject:
    head:
    - <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css" media="defer" onload="this.media='all'">
    bottom:
    - <script defer src="https://cdn.jsdelivr.net/gh/graingert/wow@1.3.0/dist/wow.min.js"></script>
    - <script defer data-pjax src="/js/wow_init.js"></script>
  3. 选择需要添加动画的dom元素,添加动画class类。此处提供三种写法。

    • 页面内写法,拟给<div class='example'><div>套上动画。一般在page页面或post页面中使用(也就是写博客的.md文件)。
      1
      2
      3
      4
      5
      6
      <!-- raw的外挂标签是告诉渲染引擎这段代码不用渲染。 -->
      {% raw %}
      <div class="example wow animate__bounceInUp">
      Content to Reveal Here
      </div>
      {% endraw %}
    • pug写法,拟给首页文章卡片套上动画,直接源码修改:
      修改[Blogroot]\themes\butterfly\layout\includes\mixins\post-ui.pug
      1
      2
      3
      4
      5
      6
          mixin postUI(posts)
      each article , index in page.posts.data
      - .recent-post-item
      + .recent-post-item.wow.animate__zoomIn
      - let link = article.link || article.path
      - let title = article.title || _p('no_title')
    • js批量添加写法(引入顺序需要在wow_init.js之前,而且需要pjax重载,每页重新添加一遍class)。通过在页面按F12,使用控制台右上角的元素选择器找到对应元素并获取class类名。
      修改[Blogroot]\themes\butterfly\source\js\wow_init.js,在原有内容之前添加内容:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      // 给首页文章卡片套上动画
      var arr = document.getElementsByClassName("recent-post-item");
      for(var i = 0;i<arr.length;i++){
          arr[i].classList.add("wow"); //必要项,添加wow.js标记
      arr[i].classList.add("animate__zoomIn"); //必要项,添加样式动画
        }
      // 给侧栏卡片套上动画
      var arr = document.getElementsByClassName("card-widget");
      for(var i = 0;i<arr.length;i++){
          arr[i].classList.add("wow");
      arr[i].classList.add("animate__slideInRight");
        }
      //初始化函数
      wow = new WOW({
      boxClass: 'wow',
      // 当用户滚动时显示隐藏框的类名称
      animateClass: 'animate__animated',
      // 触发 CSS 动画的类名称(动画库默认为"animate.css"库)
      offset: 0,
      // 定义浏览器视口底部与隐藏框顶部之间的距离。
      // 当用户滚动并到达此距离时,将显示隐藏的框。
      mobile: true,
      // 在移动设备上打开/关闭wow.js。
      live: true
      // 在页面上检查新的 wow.js元素。
      })
      wow.init();
  4. 运行hexo cl && hexo g之后即可看到效果。更多动画样式可以查看animate.css参考文档

魔改源码方案

点击查看魔改源码方案

魔改源码方案是基于Butterfly_v3.4.1编写的,低版本可能有些许不适用,可以考虑使用基础引入方案或者升级主题。或者自己理解后重构配置。

  1. 新建[Blogroot]\themes\butterfly\source\js\wow_init.js,配置默认值。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    wow = new WOW({
    boxClass: 'wow',
    // 当用户滚动时显示隐藏框的类名称
    animateClass: 'animate__animated',
    // 触发 CSS 动画的类名称(动画库默认为"animate.css"库)
    offset: 0,
    // 定义浏览器视口底部与隐藏框顶部之间的距离。
    // 当用户滚动并到达此距离时,将显示隐藏的框。
    mobile: false,
    // 在移动设备上打开/关闭wow.js。
    // 经测试此项配置无效。
    live: true
    // 在页面上检查新的 wow.js元素。
    })
    wow.init();
  2. 新建[Blogroot]\themes\butterfly\layout\includes\third-party\wowjs.pug,
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    .pjax-reload
    if theme.wowjs.animateitem
    each item in theme.wowjs.animateitem
    script(async).
    var arr = document.getElementsByClassName('!{item.class}');
    for(var i = 0;i<arr.length;i++){
        arr[i].classList.add('wow');
    arr[i].classList.add('!{item.style}');
    arr[i].setAttribute('data-wow-duration''!{item.duration}');
    arr[i].setAttribute('data-wow-delay''!{item.delay}');
    arr[i].setAttribute('data-wow-offset''!{item.offset}');
    arr[i].setAttribute('data-wow-iteration''!{item.iteration}');
      }
    script(defer src=url_for(theme.CDN.wowjs))
    script(defer src=url_for(theme.CDN.wowjs_init))
  3. 修改[Blogroot]\themes\butterfly\layout\includes\head.pug的内容,注意butterfly_v3.6.0取消了缓存配置,转为完全默认,需要将{cache:theme.fragment_cache}改为{cache: true}
    1
    2
    3
    4
    5
    6
    7
    8
        //- font
    if theme.blog_title_font && theme.blog_title_font.font_link
    link(rel='stylesheet' href=url_for(theme.blog_title_font.font_link) media="print" onload="this.media='all'")
    + //- animate_css
    + if theme.wowjs.enable
    + link(rel='stylesheet' href=url_for(theme.CDN.animate_css) media="print" onload="this.media='all'")
    //- global config
    !=partial('includes/head/config', {}, {cache:theme.fragment_cache})
  4. 修改[Blogroot]\themes\butterfly\layout\includes\additional-js.pug的内容,注意butterfly_v3.6.0取消了缓存配置,转为完全默认,需要将{cache:theme.fragment_cache}改为{cache: true}
    1
    2
    3
    4
    5
    6
    7
        if theme.pjax.enable
    !=partial('includes/third-party/pjax', {}, {cache:theme.fragment_cache})

    !=partial('includes/third-party/baidu_push', {}, {cache:theme.fragment_cache})

    + if theme.wowjs.enable
    + !=partial('includes/third-party/wowjs', {}, {cache:theme.fragment_cache})
  5. 修改[Blogroot]\themes\butterfly\layout\includes\third-party\pjax.pug的内容。

    原则上不推荐再用低于v3.4.0的版本,新版方案已经实现去jquery化,而此处的pjax适配仍然是需要jquery的。


    1
    2
    3
    4
    -   $('script[data-pjax]').each(function () {
    + $('script[data-pjax], .pjax-reload script').each(function () {
    $(this).parent().append($(this).remove())
    })

    1
    2
    3
    4
    5
    6
    7
    8
    -   document.querySelectorAll('script[data-pjax]').forEach(item => {
    + document.querySelectorAll('script[data-pjax], .pjax-reload script').forEach(item => {
    const newScript = document.createElement('script')
    const content = item.text || item.textContent || item.innerHTML || ""
    Array.from(item.attributes).forEach(attr => newScript.setAttribute(attr.name, attr.value))
    newScript.appendChild(document.createTextNode(content))
    item.parentNode.replaceChild(newScript, item)
    })
  6. 修改[Blogroot]\_config.butterfly.yml,添加CDN配置项
    1
    2
    3
    4
    5
    6
    7
    8
    9
        CDN:
    # main
    main_css: /css/index.css
    jquery: https://npm.elemecdn.com/jquery@latest/dist/jquery.min.js
    main: /js/main.js
    utils: /js/utils.js
    + wowjs: https://cdn.jsdelivr.net/gh/graingert/wow@1.3.0/dist/wow.min.js
    + wowjs_init: /js/wow_init.js # 之后可以自己换成CDN链接
    + animate_css: https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.1.1/animate.min.css
  7. 修改[Blogroot]\_config.butterfly.yml,添加wowjs开关配置项,其中class和style是必填项,其余四个是选填项。此处提供首页文章卡片和侧栏卡片添加动画的示例。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    wowjs:
    enable: true #控制动画开关。true是打开,false是关闭
    animateitem:
    - class: recent-post-item #必填项,需要添加动画的元素的class
    style: animate__zoomIn #必填项,需要添加的动画
    duration: 2s #选填项,动画持续时间,单位可以是ms也可以是s。例如3s,700ms。
    delay: 1s #选填项,动画开始的延迟时间,单位可以是ms也可以是s。例如3s,700ms。
    offset: 100 #选填项,开始动画的距离(相对浏览器底部)
    iteration: 2 #选填项,动画重复的次数
    - class: card-widget
    style: animate__zoomIn
  8. 运行hexo cl && hexo g之后即可看到效果。更多动画样式可以查看animate.css参考文档

外挂标签写法配置方案

点击查看外挂标签写法配置教程
  1. 外挂标签写法生效的前提是完成了上面的基础引入方案或者插件引入方案(二选一即可)。
  2. 新建[Blogroot]\themes\butterfly\scripts\tag\wowanimate.js:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    'use strict'

    function wow (args, content) {
    args = args.join(' ').split(',')
    let p0 = args[0]?args[0].trim():''
    let p1 = args[1]?args[1].trim():''
    let p2 = args[2]?args[2].trim():''
    let p3 = args[3]?args[3].trim():''
    let p4 = args[4]?args[4].trim():''
    return `<div class='wow ${p0}' data-wow-duration='${p1}' data-wow-delay='${p2}' data-wow-offset='${p3}' data-wow-iteration='${p4}' >${hexo.render.renderSync({ text: content, engine: 'markdown' })}</div>`
    }

    hexo.extend.tag.register('wow',wow,{ ends: true });
  3. 使用方式
    1
    2
    3
    {% wow [animete],[duration],[delay],[offset],[iteration] %}
    内容
    {% endwow %}
    1. animate: 动画样式,效果详见animate.css参考文档
    2. duration: 选填项,动画持续时间,单位可以是ms也可以是s。例如3s700ms
    3. delay: 选填项,动画开始的延迟时间,单位可以是ms也可以是s。例如3s700ms
    4. offset: 选填项,开始动画的距离(相对浏览器底部)
    5. iteration: 选填项,动画重复的次数

    注意,后面四个虽然是选填项,但是当有跨位选填时,次序不能乱。详见示例。
    支持嵌套其他外挂标签。

    1. flip动画效果。

      flip动画效果。

    2. zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10次。

      zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10

    3. slideInRight动画效果,持续5s,延时5s

      slideInRight动画效果,持续5s,延时5s

    4. heartBeat动画效果,延时5s,重复10次。

      heartBeat动画效果,延时5s,重复10次。

    1. flip动画效果。
      1
      2
      3
      4
      5
      {% wow animate__flip %}
      {% note green 'fas fa-fan' modern%}
      `flip`动画效果。
      {% endnote %}
      {% endwow %}
    2. zoomIn动画效果,持续5s,延时5s,离底部100距离时启动,重复10次。
      1
      2
      3
      4
      5
      {% wow animate__zoomIn,5s,5s,100,10 %}
      {% note blue 'fas fa-bullhorn' modern%}
      `zoomIn`动画效果,持续`5s`,延时`5s`,离底部`100`距离时启动,重复`10`次
      {% endnote %}
      {% endwow %}
    3. slideInRight动画效果,持续5s,延时5s
      1
      2
      3
      4
      5
      {% wow animate__slideInRight,5s,5s %}
      {% note orange 'fas fa-car' modern%}
      `slideInRight`动画效果,持续`5s`,延时`5s`。
      {% endnote %}
      {% endwow %}
    4. heartBeat动画效果,延时5s,重复10次。此处注意不用的参数位置要留空,用逗号间隔。
      1
      2
      3
      4
      5
      {% wow animate__heartBeat,,5s,,10 %}
      {% note red 'fas fa-battery-half' modern%}
      `heartBeat`动画效果,延时`5s`,重复`10`次。
      {% endnote %}
      {% endwow %}

TO DO

提供wowjs引入基本方案

将配置内容整合进配置文件

添加异步加载和pjax适配

编写外挂标签

将wowjs开关整合进front-matter的控制项(废弃,与pjax冲突过大)

BUG反馈归纳

  1. 如果使用了gulp-babel,在压缩js时可能报错:

    1
    wow_init.js:1 Uncaught ReferenceError: wow is not defined

    修改[Blogroot]\gulpfile.js,添加一行屏蔽项,不要压缩wow_init.js

    1
    2
    3
    4
    5
    6
        //minify js babel
    gulp.task('compress', () =>
    - gulp.src(['./public/**/*.js', '!./public/**/*.min.js'])
    + gulp.src(['./public/**/*.js', '!./public/**/*.min.js','!./public/js/wow_init.js'])
    .pipe(babel({
    presets: ['@babel/preset-env']
  2. 在wowjs初始化设置中设置了mobile为false,但是手机依然生效。
    推测是因为wowjs原本是基于animate.css_v3.0编写的,但是本帖沿用的是4.0。好吧,经测试,3.0也不生效
    解决方案是自主添加媒体选择。在css异步加载的适配中将onload="this.media='all'" 改为onload="this.media='screen'",这样,样式就只会对电脑设备(或等宽度的设备)生效了。