我在 impress.js 中学到的小套路
我在 impress.js 中学到的小套路
写在开篇
作为了一个自学 JavaScript 才一个月的新手,前几天“妄图”研究 jQuery-3.1.0 源码,结果自然是被虐得死去活来。机缘巧合之下,遇到了 impress.js ,代码量只有 jQ 的十分之一,看起来挺好下手,研究了两天,勉强弄懂了其中的原理。于是写下此文,记录我在 impress.js 中学到的小套路。
附上impress.js github链接。
impress.js 简介
套路开始
如何使用 JS 为某个元素添加多个样式?
一般情况下,在 JS 中改变元素的样式都是通过元素的 style 属性,比如这样:
- element.style.width = 100 + "px";
添加一个样式还好,如果添加多个呢,比如同时添加 width 和 height ,难道要这样?
- element.style.width = 100 + "px";
- element.style.height = 50 + "px";
非也,同时添加多个样式,可以通过函数来解决,如下:
- /**
- * 为指定的元素添加一组 CSS 样式
- * @param ele 指定的元素
- * @param props 一组 CSS 属性和值,JSON 的形式,属性名和属性值都要加引号
- * @return 返回指定的元素
- */
- var css = function(ele, props) {
- var key, pkey;
- for (key in props) {
- if (props.hasOwnProperty(key)) {
- pkey = pfx(key);
- if (pkey !== null) {
- ele.style[pkey] = props[key];
- }
- }
- }
- return ele;
- }
如何使用 JS 为 CSS 属性添加当前浏览器能够识别的前缀?
比如 transform ,为了让他在各个浏览器上都支持,在 CSS 中就得写成这样:
- #box {
- transform: rotateX(45deg);
- -webkit-transform: rotateX(45deg);
- -moz-transform: rotateX(45deg);
- -ms-transform: rotateX(45deg);
- -o-transform: rotateX(45deg);
- }
可是这样写真的很麻烦啊,怎么办?用函数自动添加!
- /**
- * 在需要的时候,为 CSS 属性添加当前浏览器能够识别的前缀
- * @param prop 一定要记住,参数是一个字符串,所以传入的 CSS 属性一定要加引号
- * @return 返回当前浏览器能够识别的 CSS 属性
- */
- var pfx = (function() {
- var prefixes = "Moz Webkit O ms".split(" ");
- var style = document.createElement("dummy").style;
- var memory = {};
- return function(prop) {
- var uProp = prop.charAt(0).toUpperCase() + prop.slice(1);
- var props = (prop + " " + prefixes.join(uProp + " ") + uProp).split(" ");
- memory[prop] = null;
- for (var i in props) {
- if (style[props[i]] !== undefined) {
- memory[prop] = props[i];
- break;
- }
- }
- return memory[prop];
- }
- })();
把上面的 css() 和 pfx() 两个函数结合起来,就可以方便地在 JS 中为元素添加样式啦。
如何通过 hash 值定位元素?
首先元素必须得有一个 id ,这个简单,遍历一下,没有 id 的加上 id 就可以了,在此不表。
有了 id 之后,就可以改变 hash 值啦,如下:
- h3[i].onclick = function(event) {
- window.location.hash = event.target.id;
- }
改变 hash 值有什么用?当然有用,假如 hash 值是 #h3-3 ,就会自动跳转到 id 为 h3-3 的元素上面,然后转念一想,这不是可以生成目录吗?锚点什么的,out 啦!
基本思想是这样子:首先,保证每一个标题标签都有一个 id ,然后遍历所有的标签,找到标题标签,提取出来,利用自定义列表生成一个目录;目录下的每一项也都有一个 id ,为 # + 对象标题的 id 。当点击目录上的标题时,将这个标题的 id 赋给 hash 值,就 OK 啦。
附上本文生成目录的 JS 代码,仅供参考!
- window.onload = function() {
- addId();
- createContents();
- createLink();
- }
- // 保证所有的标题标签都有 id ,以 h2-* h3-* 的格式
- var addId = function() {
- var h3 = document.querySelectorAll("h3");
- for (var i = 0; i < h3.length; i++) {
- if( !h3[i].id ) {
- h3[i].id = "h3-" + (i + 1);
- }
- }
- var h2 = document.querySelectorAll("h2");
- for (var i = 0; i < h2.length; i++) {
- if( !h2[i].id ) {
- h2[i].id = "h2-" + (i + 1);
- }
- }
- };
- // 创建目录
- var createContents = function() {
- // 创建 dl 标签
- var dl = document.createElement("dl");
- dl.id = "dl";
- document.body.appendChild(dl);
- // 遍历所有的标签,找到 h2 和 h3
- var tags = document.getElementsByTagName("*");
- for (var i = 0; i < tags.length; i++) {
- // 如果是 h2 ,则将标题保存在 dt 标签中,并给这个 dt 标签一个 id ,格式为 #h2-*
- if(tags[i].nodeName.toLowerCase() === "h2") {
- var dt = document.createElement("dt");
- dt.id = "#" + tags[i].id;
- var dt_text = document.createTextNode(tags[i].firstChild.nodeValue);
- dt.appendChild(dt_text)
- dl.appendChild(dt);
- }
- // 如果是 h3 ,则将标题保存在 dd 标签中,并给这个 dd 标签一个 id ,格式为 #h3-*
- if(tags[i].nodeName.toLowerCase() === "h3") {
- if(tags[i].firstChild) {
- var dd = document.createElement("dd");
- dd.id = "#" + tags[i].id;
- var dd_text = document.createTextNode(tags[i].firstChild.nodeValue);
- dd.appendChild(dd_text);
- dl.appendChild(dd);
- }
- }
- }
- }
- // 定义目录与标题的联系
- // 点击目录中的某一项,将这一项的 id 赋给 hash 值,通过 hash 值的改变定位到相应的标题
- function createLink() {
- var dl = document.getElementById("dl");
- var tags = dl.getElementsByTagName("*");
- for (var i = 0; i < tags.length; i++) {
- tags[i].onclick = function() {
- window.location.hash = this.id;
- }
- }
- }
自定义属性 data 与 dataset 对象
在 impress.js 中,充分利用了 data 来定义各个 step 的样式。首先在 HTML 中的元素标签上定义 data 属性,然后在 JS 中通过 dataset 对象读取,然后 通过 css() 函数为元素添加这些样式。虽然最终的结果与直接在 CSS 样式表中定义的一样,不过这能通过 JS 对样式进行更多控制。
举个栗子,下面是 HTML :
然后在 JS 中通过 el.dataset 获取这些属性,长这样:
- var data = el.dataset = {
- x : 0,
- z : 1000,
- rotateY : 45,
- rotateZ : 80,
- scale : 1
- }
然后就可以通过 data 获取具体的属性值,就像这样:
- step = {
- translate: {
- x: toNumber( data.x ),
- y: toNumber( data.y ),
- z: toNumber( data.z )
- },
- rotate: {
- x: toNumber( data.rotateX ),
- y: toNumber( data.rotateY ),
- z: toNumber( data.rotateZ || data.rotate )
- },
- scale: toNumber( data.scale, 1 ),
- el: el
- };
然后调用 css() 函数将这些样式同时添加到元素上。
- css( el, {
- position: "absolute",
- transform: "translate(-50%,-50%)" +
- translate( step.translate ) +
- rotate( step.rotate ) +
- scale( step.scale ),
- transformStyle: "preserve-3d"
- } );
鉴于 step.translate 和 step.rotate 是一个对象,为了解析它们的值,还得需要两个辅助函数,如下:
- /**
- * 设置 3D 转换元素的 translate 值
- * @param t 位移值,以对象字面量的形式,属性值不需要带单位
- * @return 返回 "translate3d() "
- */
- var translate = function(t) {
- return "translate3d(" + t.x + "px," + t.y + "px," + t.z +"px) ";
- }
- /**
- * 设置 3D 转换元素的 rotate 值
- * @param r 旋转值,以对象字面量的形式,属性值不需要带单位
- * @return 返回 "rotateX() rotateY() rotateZ() "
- */
- var rotate = function( r, revert ) {
- var rX = " rotateX(" + r.x + "deg) ",
- rY = " rotateY(" + r.y + "deg) ",
- rZ = " rotateZ(" + r.z + "deg) ";
- return revert ? rZ + rY + rX : rX + rY + rZ;
- };
自定义事件并立即触发
在 impress.js 的初始化函数中,函数的最后,是这样的:
- triggerEvent( root, "impress:init", { api: roots[ "impress-root-" + rootId ] } );
调用的 triggerEvent() 函数长这样:
- /**
- * 自定义事件并立即触发
- * @param el 触发事件的元素
- * @param eventName 事件名
- * @param detail 事件信息
- */
- var triggerEvent = function( el, eventName, detail ) {
- var event = document.createEvent( "CustomEvent" );
- // 事件冒泡,并且可以取消冒泡
- event.initCustomEvent( eventName, true, true, detail );
- el.dispatchEvent( event );
- };
我个人理解,在初始化完成之后,自定义了一个 impress:init 事件,并立即触发,然后在 root 元素接收该事件,并以此为依据,执行另外的任务。
同样在 impress.js 中,每一幕的进入在经过一段时间的延迟之后,都会自定义一个 impress:stepenter 事件并触发,在 root 上接收到这个事件,从而改变 hash 值。
我在 impress.js 中学到的小套路的更多相关文章
- Impress.js上手 - 抛开PPT、制作Web 3D幻灯片放映
前言: 如果你已经厌倦了使用PPT设置路径.设置时间.设置动画方式来制作动画特效.那么Impress.js将是你一个非常好的选择. 用它制作的PPT将更加直观.效果也是嗷嗷美观的. 当然,如果用它来装 ...
- 我对 impress.js 源码的理解
源码看了两天,删掉了一些优化,和对 ipad 的支持,仅研究了其核心功能的实现,作以下记录. HTML 结构如下: <!doctype html> <html lang=" ...
- 一统江湖的大前端(1)——PPT制作库impress.js
<一统江湖的大前端>系列是自己的学习笔记,旨在介绍javascript在非网页开发领域的应用案例和发现各类好玩的js库,不定期更新.如果你对前端的理解还是写写页面绑绑事件,那你真的是有点O ...
- impress.js 一个创建在线幻灯的js库
真的好奇怪,我居然会写前端技术的博客.没有办法的,最近实习,看的大多是前端.所以今天就用这个来练练手了. Impress.js 是一个非常棒的用来创建在线演示的Javascript库.它基于CSS3转 ...
- impress.js初体验——前端装X利器
impress.js 是国外一位开发者受 Prezi 启发,采用 CSS3 与 JavaScript 语言完成的一个可供开发者使用的表现层框架(演示工具).其功能包括画布的无限旋转与缩放,任意角度放置 ...
- 如何使用impress.js做一个网页版本的PPT
blockquote{font-size: 18px;line-height:1.5;margin:0;}line-height: 1.5; 要做一个网站制作规范培训,之前村长做过一次培训,但是后来一 ...
- impress.js学习总结
impress.js是一个很有趣的用来替代PPT的展示用的js工具,它的灵感来自prezi 如果你要学习使用它,这里有很好的演示模板 使用它的第一步,下载 impress.js,引入到你的代码里,并执 ...
- 体验Impress.js
用腻了ppt,prezi的风格看起来更酷一点儿,无意中得知有Impress.js这么一个H5版的prezi,nice,值得一试. 关于Impress.js,网上教程很多,但说实话就跟教小朋友一样,一步 ...
- impress.js初体验
概述 如果你已经厌烦了使用PowerPoint制作PPT,那么impress.js是一个非常好的选择,用它做的PPT更加直观,效果也非常的不错.装X是需要一定代价的,不过如果你是个前端爱好者那么一切就 ...
随机推荐
- MySQL学习指引
mysql指引 1,mysql基本安装 2,mysql多实例安装与维护 3,备份恢复 备份数据库 分备数据库 分备表 恢复数据库
- 关闭linux centos各种声音
shell报警 #vi /etc/inputrc ================================ set bell-style none 或 echo "set bell- ...
- char 转wchar_t 及wchar_t转char
利用WideCharToMultiByte函数来转换,该函数映射一个unicode字符串到一个多字节字符串.通常适合于window平台上使用. #include <tchar.h> #in ...
- 使用POI getCell 获取空的单元格之后在使用的时候报 NullPointerException
解决办法,在得到cell之后先判断cell是否为空,然后再进行逻辑处理. 得到的cell建议使用去除策略(如左对齐,居中等)的cell,不然有可能受到策略影响而导致结果异常. org.apache.p ...
- C#关于MSMQ通过HTTP远程发送专有队列消息的问题
两台计算机的操作系统都是Windows Server 2008两台计算机都安装了MSMQ+Http支持两台计算机的防火墙全部关闭本地Ip:192.168.1.104远程Ip:192.168.1.142 ...
- WebSocket 服务器4
Java Websocket实例 Websocket 2015-04-11 14:11:54 发布 您的评价: 4.4 收藏 6收藏 介绍 现很多网站为了实现即时通讯,所用 ...
- 20145234黄斐《信息安全系统设计基础》GDB调试汇编堆栈过程分析
堆栈跟踪 首先编辑一个程序 用gcc编译,再使用gdb调试,发现gdb尚未下载 下载后重新运行gdb 设置断点:b+行号或者"main" 运行:r frame:打印出的信息:栈的层 ...
- jQuery Easy UI 开发笔记
1.jQuery Easy UI主要的运行原理是通过核心的代码调用插件来实现UI效果的 2.jQuery Easy UI插件与插件之间的关系是: 一.独立式插件: 独立式插件是指:不与其他的插件具有相 ...
- c# winform 火狐浏览器 查看cookie
c# winform 火狐浏览器 查看cookie Firefox的Cookie数据位于:%APPDATA%\Mozilla\Firefox\Profiles\ 目录中的xxx.default目录,名 ...
- java 获取主机IP
public class Chat extends JFrame { public static JTextField jt; public Chat(){ setLayout(new FlowLay ...