SVG 交互图文教学 基础实战篇

发布于 2024-12-24 01:38:55 字数 15162 浏览 5 评论 0

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1379-b0gzx12i34e.gif

背景

最近很多公众号开始流行在公众号正文中嵌入了 svg 交互动画,而不是在末尾/图文中添加二维码引导用户跳去 h5 网页上。那么到底是如何实现的?其实又有什么难点和坑需要攻克和避开?我们一起来学习下 svg 图文的制作思路。先来个经典三问:是什么?为什么?怎么办?

SVG 是什么?

SVG 是什么?SVG 是一种图像文件格式,它的英文全称为 Scalable Vector Graphics,意思为可缩放的矢量图形。用户可以直接用代码来描绘图像,可以用任何文字处理工具打开 SVG 图像,通过改变部分代码来使图像具有交互功能。这种动画交互方式可以脱离 javascript 脚本, 因此才能通过编译 dom 结构的方式嵌入到公众号里面去。

为什么用 svg 不用 h5?

这时候肯定很多人有疑惑:明明同样是移动端的动画交互,h5 动画可以实现更为复杂酷炫的动画和交互,为什么要使用 svg 图文动画替代 h5?

  1. 灵活自由 :svg 图可以潜入到公众号的图文里,可以在推文里的任意位置插入,可以在原有的图文基础上增加文章的阅读交互体验。
  2. 推文跳失率高 :从推文到 h5 需要跳转,用户需要二次点击才能直达 h5,甚至很多用户无法第一时间留意到 h5 跳转的位置,会造成用户流失。
  3. 上线成本高 :一个 h5 的网页需要把 h5 代码挂载到一个服务器,还需要一定时间的开发周期及兼容测试等。有些中小企公司缺少服务器的情况下,还需要搞台服务器或者平台来挂载 h5 服务(还没算域名带宽等等巴拉巴拉的),比较耗费人工成本和资源成本。

怎么把 svg 运用到图文推送上?

如果你对 svg 技术有所了解,你就可以自定义的去实现你想要的一些动画交互方式。在公众号的图文编辑页 按下熟悉的 option+command+j / F12 打开开发者工具,在编辑素材页面,Edit as HTML,操作你想要替换的 dom,最后保存,一篇含有炫酷动效的公众号文章就诞生啦。

svg 图文有什么缺点?

说了这么多的优点,当然 svg 图文交互在实现起来还是有部分缺点和深坑。主要涉及以下几个主要缺点:

  1. 开发难度相比 h5 要高很多 :同样的一个动画实现,h5 只需要几行 javascript 代码即可随意操作,而 svg 图文需要很多“曲线救国”的方法,在 svg 图文交互的制作上,需要结合不同思路取巧。
  2. 受限平台的规则 :部分功能样式需要针对不同平台的特性进行适配微调。

对于上述的问题,后面会有作者踩坑的血泪史详细介绍。

正文教学

前置知识

以下会用到几个常用 svg 标签如 、、、等 建议如果对 svg 不了解的可以先移步补补知识 svg 参考手册 超级强大的 SVG SMIL animation 动画详解

简单案例

构建 svg

我们先构建一个 svg 的基本结构

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: inline-block; width: 100%; background: #061534" viewBox="0 0 345 600">

</svg>

主要说下 viewBox 属性:

viewBox="x, y, width, height"

viewBox 的四个参数分别代表:x(最小 X 轴数值);y(最小 y 轴数值);width(宽度);height(高度)

x、y 其实设置的是 svg 内部元素的整体位移,相当于 svg 视窗的裁剪起始点,除非要对 svg 内元素进行整体位移,否则一般都是 0 0。

width、height 表示的是 svg 内的分辨率,它的单位并不是 px、也不是 css 单位。所以它并不是 svg 的实际宽高。width、height 越大,那么分辨率就越高,里面元素就显得越小。为了计算方便,一般来说 width、height 的尺寸等同于实际设计稿的尺寸。

给 svg 添加内容

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: inline-block; width: 100%; background: #061534" viewBox="0 0 345 600">
  <g>
    <text
      x="100"
      y="240"
      fill="#fff"
      style="width: 100%; font-size: 30px; text-align: center"
    >
      点我就消失
    </text>
  </g>
</svg>

这里使用了一个 <text> 标签简单得填充了一个点击内容的区域,目前效果图如下

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1381-dfv1ndzk0l2.png

元素消失

我们要实现的是通过“一次点击”,然后使得文字元素消失。这里我们可以通过 svg 的 <animate> 标签实现 click 触发动画

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: inline-block; width: 100%; background: #061534" viewBox="0 0 345 600">
  <g opacity="1" >
    <text
      x="100"
      y="240"
      fill="#fff"
      style="width: 100%; font-size: 30px; text-align: center"
    >
      点我就消失
    </text>
    <animate
      attributeName="opacity"
      begin="click"
      dur="0.6s"
      to="0"
      fill="freeze"
      restart="never"
    ></animate>
  </g>
</svg>

关键属性讲解:

属性说明
attributeName目标属性名称,可以是 height、width、opacity 等等 css 属性
begin这里一般可以是 click,也可以是 touchmove 等,“click”代表点击后触发,如需延迟可以设置为“click+Xs”,X 为秒,如 click="click+5s"表示点击后 5s 触发动画
dur表示动画过渡市场
to表示动画过渡的目标值
restart此属性用来规定元素开始动画之后,是否可以被重新开始执行;具有三个属性值: always :动画可以在任何时候被重置。这是默认值。 whenNotActive :只有在动画没有被激活的时候才能被重置,例如在动画结束之后。 never :在整个 SVG 执行的过程中,元素动画不能被重置。

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1383-1tdflwf2awd.gif

元素位移

除了 <animate> 之外,元素位移和缩放可以通过另外一个标签 <animateTransform> 进行操作

<svg version="1.1" xmlns="http://www.w3.org/2000/svg" style="display: inline-block; width: 100%; background: #061534" viewBox="0 0 345 600">
  <g opacity="1" >
    <text
      x="100"
      y="240"
      fill="#fff"
      style="width: 100%; font-size: 30px; text-align: center"
    >
      点我进行位移
    </text>
    <animateTransform
      attributeName="transform"
      type="translate"
      dur="0.6s"
      to="0 100"
      begin="click"
      dur="1s"
      fill="freeze"
      restart="never"
    ></animateTransform>
  </g>
</svg>

除了刚刚 <animate> 讲到的关键属性外, <animateTransfrom> 多了一个 type 值用于控制转换类型

属性说明
type类型的转换其值是随时间变化。可以是 'translate', 'scale', 'rotate', 'skewX', 'skewY'

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1383-1tdflwf2awd.gif

实战 demo

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1386-rd3oij2syww.gif

简单的过了一些 svg 的交互行为方法后,我们来一个现在常见的 svg 图文交互案例

1. 准备基本框架

我们对这个 demo 进行一个简单的交互分析

1、一开始仅展示首屏封面 2、点击后收起并展示文章详情

<section style="overflow: hidden">
  <section name="article" style="height: 0">
    <!-- 隐藏的文章页 -->
  </section>
  <section name"cover">
    <!-- 封面页 -->
  </section>
</section>

首先我们对这个案例进行一些结构的拆解,把 首屏详情页 进行分离,这里用了 2 个 <section> 进行区分。

文章页的 height: 0 配合上 父级的 overflow: hidden ,起到一个隐藏文章的作用, 这时候图文的高度就全由封面页的高去控制了

2. 开始制作

我们先随便网上搞一个静态的小火箭 svg 复制下来,并放在一个 345*500 的一个容器内。

<section style="overflow: hidden">
  <section style="height: 0">
    <!-- 隐藏的文章页 -->
  </section>
  <section name="封面">
    <svg
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      style="
        display: inline-block;
        vertical-align: top;
        width: 100%;
        background: #6a90e1;
      "
      viewBox="0 0 345 500"
      preserveAspectRatio="xMidYMin meet"
    >
      <g>
        <foreignObject x="0" y="0" width="345" height="500">
          ...小火箭的 svg 代码
        </foreignObject>
      </g>
    </svg>
  </section>
</section>

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1391-fbv0v0ru5r2.png

结合刚刚学到的 <animateTransform> 我们给小火箭添加一个简单的漂浮动画

...
  <section name="封面">
    <svg
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      style="
        display: inline-block;
        vertical-align: top;
        width: 100%;
        background: #6a90e1;
      "
      viewBox="0 0 345 500"
      preserveAspectRatio="xMidYMin meet"
    >
      <g>
        <g>
          <foreignObject x="0" y="0" width="345" height="500">
            ...小火箭的 svg 代码
          </foreignObject>
        </g>
        <!-- 添加上下漂浮的循环动画 -->
        <animateTransform
          attributeName="transform"
          type="translate"
          begin="0s"
          dur="1s"
          values="0 30;0;0 30"
          repeatCount="indefinite"
        ></animateTransform>
      </g>
    </svg>
  </section>
...

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1394-murgs2whlxd.gif

为小火箭添加一个起飞的动作,这时候我们就需要使用到 <animateTransform> 标签下的 begin=”click“ 的点击操作了。我们设定点击小火箭后,立刻在 0.6s 内往下平移 100 的距离

...
  <section name="封面">
    <svg
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      style="
        display: inline-block;
        vertical-align: top;
        width: 100%;
        background: #6a90e1;
      "
      viewBox="0 0 345 500"
      preserveAspectRatio="xMidYMin meet"
    >
      <g>
        <g>
          <foreignObject x="0" y="0" width="345" height="500">
            ...小火箭的 svg 代码
          </foreignObject>
          <!-- 点击小火箭后,将会在 0.6s 内往下平移 100 的距离 -->
          <animateTransform
            attributeName="transform"
            type="translate"
            dur="0.6s"
            to="0 100"
            begin="click"
            dur="2s"
            fill="freeze"
            restart="never"
          ></animateTransform>
        </g>
        <!-- 添加上下漂浮的循环动画 -->
        <animateTransform
          attributeName="transform"
          type="translate"
          begin="0s"
          dur="1s"
          values="0 30;0;0 30"
          repeatCount="indefinite"
        ></animateTransform>
      </g>
    </svg>
  </section>
...

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1396-3ztxvu2202a.gif

小火箭起飞,过渡到文章页

...
  <section name="封面">
    <svg
      version="1.1"
      xmlns="http://www.w3.org/2000/svg"
      style="
        display: inline-block;
        vertical-align: top;
        width: 100%;
        background: #6a90e1;
      "
      viewBox="0 0 345 500"
      preserveAspectRatio="xMidYMin meet"
    >
      <g>
        <g>
          <foreignObject x="0" y="0" width="345" height="500">
            ...小火箭的 svg 代码
          </foreignObject>
          <!-- 点击小火箭后,将会在 0.6s 内往下平移 100 的距离 -->
          <animateTransform ... />
        </g>
        <!-- 添加上下漂浮的循环动画 -->
        <animateTransform .../>
        <!-- 点击 2s 后,页面先从 500 收起到 0,再从 0 展开到 3000 -->
        <animate
          attributeName="height"
          calcMode="spline"
          keySplines="0.42 0 0.58 1.0;0.42 0 0.58 1.0"
          values="500; 0; 3000"
          dur="5s"
          begin="click+2s"
          keyTimes="0;0.2;1"
          fill="freeze"
          restart="never"
        ></animate>
        <!-- 当封面收起后,把封面宽度设为 0,防止遮挡文章页 -->
        <animate
          attributeName="width"
          begin="click+3s"
          dur="0.000001s"
          to="0"
          fill="freeze"
          restart="never"
        ></animate>
      </g>
    </svg>
  </section>
...

这里着重讲一下新加上去的 2 个 <animate>

1. 页面收起展开的功能: 这里 <animate>attributeName 设成了 height ,并再点击后,从本来的封面高度 500 在动画执行链路(0 ~ 1)的 0.2 时刻过渡到 0 ,从而实现封面收起的效果,由于上面【1.准备基本框架】提到的“ 图文的高度就全由封面页的高去控制 ”这个原因,整个图文都会收起。在剩下的动画链路 0.2~1 的过程,在把封面的高度从 0 展开到 3000,这时候整个区域就会撑大到 3000

<!-- 点击 2s 后,页面先从 500 收起到 0,再从 0 展开到 3000 -->
<animate
  attributeName="height"
  calcMode="spline"
  keySplines="0.42 0 0.58 1.0;0.42 0 0.58 1.0"
  values="500; 0; 3000"
  dur="5s"
  begin="click+2s"
  keyTimes="0;0.2;1"
  fill="freeze"
  restart="never"
></animate>

2. 封面隐蔽功能: 这里 <animate>attributeName 设成了 width ,并再点击后,在 svg 收起的瞬间,我们在 极短 的时间内把封面的宽度设置成 0 把封面“ 隐藏 ”起来,而由于节点的高度还在,所以页面还是会继续把高度撑开。这时候, 原本被封面页遮挡的文章详情页就可以露出来了 这里会有人提问,为什么不用 opacity 来隐藏?因为如果仅仅把透明度变成 0,原来的封面仍然在那个位置,会对遮挡到文章内容页的 点击事件

<!-- 当封面收起后,把封面宽度设为 0,防止遮挡文章页 -->
<animate
  attributeName="width"
  begin="click+3s"
  dur="0.000001s"
  to="0"
  fill="freeze"
  restart="never"
></animate>

到这里,终于大功告成了!!!直接上效果图!!!

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1386-rd3oij2syww.gif

等等??不会吧? 不会真的有人以为要结束了吧?最重要的一步,把做好的 svg 图文放公众号!!不然这么辛苦搞个 svg 还不如不用 js 写??

3. 嵌入到公众号

如果代码中使用到了图片,那么图片必须上传至微信后台,获取线上地址,如果使用别的域或者上传到别的公众号的图片是无法使用的哦。 步骤: 1、进入微信公众平台,点击左边的素材管理->图片->上传: 2、上传成功后,打开图片,获取图片的线上地址:

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1398-5qeacb1m12p.png

下一步就是新建图文消息,先输入好标题、作者,上传好封面图。。

打开 chrome 调试工具,直接定位到编辑器的 body

http://storage.360buyimg.com/azfff/markdown/v1/10.jpg

把代码粘贴到 <body> 节点里,这时候!!!点击 预览!!!!搞掂!!

http://www.wenjiangs.com/wp-content/uploads/2024/docimg16/1404-et5e0hscz4m.gif

4. 注意事项

微信编辑器有很多内置的规则,会对编辑器的内容进行一些过滤,我们嵌入的代码需要对此进行一些兼容和处理防止被莫名其妙的“优化”了 比较重要和容易踩坑的规则有: 1、不能使用 <script><style> 标签。 2、标签里的 background 的 url() 里,地址不能加引号,单引号双引号都不行,否则会被微信编辑器过滤掉 3、使用 <img> 标签需要把 filter 属性强行去掉: filter:none !important; ,否则暗黑模式会自动给你添加暗黑滤镜 4、标签里不能有 id。

后面有新的发现,会在第二期继续补充!

参考文献

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

够钟

暂无简介

文章
评论
513 人气
更多

推荐作者

白云不回头

文章 0 评论 0

糖粟与秋泊

文章 0 评论 0

洋豆豆

文章 0 评论 0

泛滥成性

文章 0 评论 0

mb_2YvjCLvt

文章 0 评论 0

夜光

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文