首页
闲言碎语
雁过留名
友链申请
Search
1
国外短信接码服务平台
9,716 阅读
2
Beyond Compare 4 序列号“这个授权密钥已被吊销”的解决办法
9,137 阅读
3
收藏几个Github镜像源
7,668 阅读
4
Handsome主题夜间模式插件 fo Typecho
7,514 阅读
5
美剧鸟v5.6.3(官方原版)
7,210 阅读
随笔吐槽
福利活动
技术教程
软件下载
源码分享
私密相册
登录
/
注册
Search
标签搜索
安卓软件
影音播放
影音视频
电视软件
电视盒子
Typecho
游戏加速
听书软件
影视播放
Handsome
音乐试听
影音视听
音乐播放
文件管理
输入法皮肤
解锁音乐
实用工具
学习阅读
GitHub
多开软件
低调G
累计撰写
291
篇文章
累计收到
701
条评论
首页
栏目
随笔吐槽
福利活动
技术教程
软件下载
源码分享
私密相册
页面
闲言碎语
雁过留名
友链申请
搜索到
42
篇与
技术教程
的结果
2020-07-09
Handsome主题使用文档
相册创建相册新建分类:分类的缩略名称为image(这个是固定的,标识该分类是相册)。分类描述会输出到相册列表页面创建属于该分类的一篇文章,即创建了一个新的相册。文章的标题即相册的标题。在文章的自定义字段中添加字段名album,值为你的相册描述上传相片在属于相册分类新建一篇文章,在编辑器中添加图片即可。添加图片:允许以下的几种方式:使用自带的附件功能,上传并插入编辑器中使用markdown的图片语法,支持外站链接使用html语法,支持外站链接举例: <img src="图片地址" alt="图片描述">  <img src="http://localhost/build/usr/uploads/2018/05/1374653827.png" alt="奔跑的日子">主题代码会自动解析代码,并显示为相片格式,编辑器内多余的文字将不会显示*相关问题:编辑器无法解析HTML代码*内容加密handsome已经支持很多种内容加密方式,用最灵活的方式保障写作者的写作隐私问题。这篇文章是一个综合介绍全站加密加密后网站任何内容只有输入密码才能阅读,选择此种方式不知道密码的用户无法通过任何方式获取内容,包括无法通过feed订阅方式适合非常私密站点,比如日记本博客【加密方式】:外观设置——高级设置——全站访问密码分类加密v5.2.0及以上版本支持,必须配合最新版本主题插件对于分类加密下面的文章,是不能有多个分类的!否则加密失效!!加密分类输入密码才能阅读内容【加密方式】:第一步:在分类设置里面按照下面格式填写分类描述(下面四种方式只能且只需要填一种!)://第一种方式:只是配置加密和对应的密码“1234” {"lock":true,"password":"1234"}</p><p> //第二种方式:还可以继续配置分类描述 {"lock":true,"password":"1234","desc":"一个加密的分类,输入密码后可见内容"}</p></li></ul></li></ul><pre v-pre="" data-lang=""><code class="lang-"> //第三种方式:还可以继续配置分类的图标 {"lock":true,"password":"1234","desc":"一个加密的分类,输入密码后可见内容","img":"https://i.loli.net/2019/05/01/5cc95872929ef.jpeg"} //第四种方式:也可以直接简单的填写文字表示分类描述,此时该分类不会加密 一个普通的分类描述而已。第二步:在links插件设置里面填写需要加密的分类的mid,这一步不完成的时候别人仍然可以通过feed查看到加密内容分类隐藏v5.2.0及以上版本支持,必须配合最新版本主题插件在主题插件中填写需要隐藏的分类mid即可分类隐藏仅仅是在首页不显示该分类的文章,游客仍然可以根据文章地址查看内容,左侧边栏的分类列表仍然会显示隐藏分类【适用场景】:比较适合自己的一些小片段笔记,不希望直接显示在首页文章加密整篇文章加密是typecho提供的功能,不多说【加密方式】:在文章编辑页面右侧的高级功能,里面有密码选项【相关问题】:输入正确密码显示密码错误为什么?文章部分内容回复可见游客回复并且评论通过审核后可以可见一般可以用在资源分享的帖子,增加内容的参与度【加密方式】:文章部分内容隐藏文章部分内容登录用户可见对于单用户的博客,也就是博客主人可见,这里可以写一写比较隐私的内容。【加密方式】:文章部分内容登录可见万物皆可RSS 配置 想法来源于熊猫小A的博客。 能做哪些事情?可以把任何有RSS源网站内容可以聚合在时光机页面内。比如微博、微信公众号、(前两个需要RSShub的开源服务支持)另一个博客的内容等等。对代码不了解的伙伴们直接看下一个说明(简单配置微博),后面的都不要看了!!简单配置微博{"id":"weibo","name":"微博","url":"https://rsshub.app/weibo/user/5631723091"}直接把上面的代码复制到配置框中,https://rsshub.app/weibo/user/5631723091 最后的一串数字5631723091是你的微博UID,打开你的微博的主页的地址中有的配置项填写id :rss标识符,任何字母(id请勿重复)。比如微博,可以是weiboname :rss内容标题,一般是中文。如果是微博,就直接填微博url :rss源地址比如微博,就是https://rsshub.app/weibo/user/5631723091(这个源有时候不稳定,可以用另一个)或者https://rsshub.app/weibo/user2/5631723091比如别的博客内容:一般的博客系统都支持生成RSS订阅地址的,比如我的博客就是https://www.ihewro.com/feed/只要是RSS源地址,都是支持的img (非必填项):代表该栏目的图片,以头像形式显示。建议是正方形的。填写图片的url地址即可type(非必填项):显示的内容形式discription 仅显示文章摘要(有的RSS源摘要中包含整个文章内容)(不填的话,默认是这个)title 仅显示文章标题mix 显示标题+摘要 (暂不支持)RSS 源禁止跨域怎么办?最简单的解决办法是:在原有的RSS源地址前面加上https://cors-anywhere.herokuapp.com/举例:https://api.fanfou.com/statuses/user_timeline/~k40sgjV_6kg.rss 该源是禁止跨域的,所有无法请求到(浏览器可以正常访问,但是无法通过代码获取数据),修改后的源地址为:https://cors-anywhere.herokuapp.com/https://api.fanfou.com/statuses/user_timeline/~k40sgjV_6kg.rss填url属性就填后者即可。(可能速度会有些影响) 独立页面主题内置了五套自定义模板 时光机、文章归档、友情链接和留言板和豆瓣书单。使用方法在后台了撰写——创建页面的右下角的自定义模板选择相应的自定义模板即可。下面简单介绍自定义模板的使用方法。时光机关注微信公众号ihewro(我要起飞啦熬)按照微信公众号发送时光机 即可通过微信公众号同步发送到handsome主题的博客中填写地址的时候,必须填写为 cross.html(是地址,不是标题!!!标题随便写,但是地址要固定的,否则首页无法读取内容)外观设置——初级设置——首页左侧边栏头像的链接地址 默认是时光机页面的地址,你可以修改内容框里面不用填任何东西,这个页面在前台(就是直接打开这个独立页面,然后在登录的状态下)就可以发布“说说”,用来记录你的日常和心情的~看不到输入框:请确保你已经登录了,并且该独立页面允许评论(只有管理员登录后才会显示输入框,游客是看不见的,请放心)如何删除说说:在后台的评论管理中删掉该页面的对应评论即可。说说不能发表图片: 见常见问题文章归档地址随意填写。内容框不用填任何内容。这个页面会自动把你所有文章以时间树的形式显示出来。友情链接地址随意填写。这个页面自动输出links插件里面设置的友情链接。(具体用法见插件设置)友情链接页面的本博信息在独立页面的输入框中填写即可,会和链接一起输出。留言板地址随意填写。这个页面会自动输出评论数最多的前15名。如果需要填写自定义内容在输出框中填写即可,会一起输出。豆瓣清单地址随意填写。这个页面会自动输出你的豆瓣书单(已读的书)、电影清单(已看的电影)。在自定义字段中填写:名称为doubanID,值为你的豆瓣ID。访问该网址以检查的ID是否正确:https://www.douban.com/people/你的豆瓣ID/,填写的是豆瓣ID,不是整个url地址因为需要写入缓存文件,请确保你的主题下的aseets/cache目录可写请确保的你的豆瓣有已看的电影和已读的书的数据,不然会显示错误。图书数据不能显示,一直显示“数据已添加成功,请刷新一次”,刷新了还是显示不了的话,一般是全站静态缓存了,请修改你的cdn缓存策略,不要全站静态缓存,缓存静态资源(.jpg .css .js)之类文件即可 ![3.jpg][2]github项目地址随意填写这个页面会输出你所想要输出的github项目名称你有两种方式显示你的github项目:输出所有的你的github项目受限制与github提供的api限制,你只能显示30个你的github项目清单在自定义字段中填写:名称为github,值为你的github用户名自定义输出项目(待开发,暂不能使用)在编辑器中按照下面的格式填写:[github="用户名/仓库名"] //举例: [github="ihewro/typecho-theme-leaf"] 评论系统主题内置Typecho原生评论系统,同样支持任何第三方评论服务(如:多说,disqus,畅言等)。使用原生评论系统你可以通过后台外观设置中这些开关来加强原生评论系统:「评论系统——原生评论框的背景图片」设置评论框的背景图片。「评论系统——默认评论者头像」设置默认的gravatar头像。「主题增强功能——启用ajax评论」获取无刷新评论体验。Q:如何更好的防止垃圾评论?A:推荐SmartSpam 使用畅言在后台外观设置——评论设置 选择 畅言,填写畅言appid和填写畅言conf参数。使用其他第三方评论系统在后台外观设置——评论设置 选择 其他第三方评论系统。找到主题目录下的usr/third_party_comments.php,增加第三方评论系统的代码。(不推荐,第三方评论不仅不稳定,而且不一定与主题的pjax兼容,如果不兼容,请在后台外观设置中关闭pjax!)关闭评论适用于部分特殊情况需要关闭。 增强功能博文头图分为两种:首页头图:首页每篇文章顶部的图片文章头图:每篇文章详情页面顶部的图片具体见上图指示。在文章的编辑页面可以对单篇文章的头图进行控制在后台的外观设置中可以对这两部分进行整体个性化设置: 1. 个性化首页头图样式: 大版式头图小版式头图图片版式头图在后台外观设置——外观设置开关中选择。缩小版头图显示即所有文章默认显示小版式头图。每篇文章的编辑页面都可以选择首页头图样式,这里的设置会无视掉上面设置中的效果(仅对该篇文章有效),这样就实现大版式和小版式头图交叉的效果。 2. 个性化头图来源: 在后台主题增强功能——博客头图来源设置中选择。提供四种方式:只显示随机图片显示顺序:thumb自定义字段——文章第一个附件——文章第一张图片显示顺序:thumb自定义字段——文章第一个附件——文章第一张图片——随机图片(推荐)显示顺序:thumb自定义字段——随机图片以第三种为例,当thumb字段为空的时候,会寻找文章的第一个附件,附件不是图片,会继续寻找文章中第一张图片,文章中如果没有图片的话再去加载随机图片。其他选项亦是同理。文章的随机头图的图片存放位置为: 主题目录下的usr/img/sj 右侧边栏的随机图片的存放位置为:usr/img/sj2 3. 个性化头图显示: 不显示文章页面头图不显示首页头图在后台外观设置——外观设置开关选择文章页面不显示头图或首页不显示头图,将会默认不显示文章页面或者首页文章顶部的头图。每篇文章的编辑页面底部的自定义字段中,字段名为thumb,当值为no的时候,会不显示当前文章的头图(首页头图和文章头图)(仅对当前文章有效),这里的设置同样会无视上面的设置。灯箱插件文章中如果某个图片不想显示灯箱效果,可以给图片标签中加入nogallery属性:<img nogallery src="">如果某张图片高度很大,想折叠展示,可以给图片标签加入max属性:<img max src="">DNS预解析这个功能即将被删除DNS prefetching通过指定具体的URL来告知客户端未来会用到相关的资源,告诉客户端可以尽早的解析DNS。更多详细信息,请戳这个文章目录树文章中的目录树已经内置代码,仅当文章有h2 h3 h4标题 才会生成目录树,并且手机端不显示目录树。注意:如果文章中没有h2标题,只有h3 h4标题是不会生成目录树的。侧边栏的标签云需要在新建文章的页面右侧填写标签,才会在首页侧边栏输出的。(回车添加当前标签)自定义摘要字数大版式头图默认摘要字数200字,小版式头图默认摘要字数80字。你可以在后台外观设置->自定义大版式头图摘要/自定义小版式头图摘要来改变这两个默认值。你还可以使用摘要分隔符进行自主截断内容输出,但是自主生成的摘要不会超过默认摘要字数。举例:你的默认摘要字数设置为200字,使用摘要分隔符截断的摘要为230字,则摘要只会显示200字。<!--more-->添加自定义图标主题已经内置的图标列表,详见图标列表如果不能满足你的图标需求,可以使用以下方法扩充主题图标:方法一:傻瓜式扩充fontawesome图标直接引入全套的fontawesome图标:在主题外观设置——开发者设置——自定义输出head 头部的HTML代码,填入:<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">上面的fontawesome 的css文件来自bootcdn.css 公共cdn提供,你可以替换成自己的文件。方法二:自定义添加iconfont图标列表主题内置fontello图标来自网站http://fontello.com/你可以在该网站中导入主题目录下的assets/fonts/fontello的config.json,然后重新生成字体文件。覆盖到assets/fonts/fontello下,并且需要修改assets/css/handsome.css中形如.fontello-*:before,替换为下载的新的标签。(难度较大,不推荐……)文章中插入按钮handsome支持以下类型的按钮:矩形文字按钮椭圆形文字按钮矩形图标文字按钮[button]矩形按钮文字[/button] [button color="succees"]矩形按钮文字[/button] [button type="round" color="success"]椭圆形按钮文字[/button] [button color="success" icon="glyphicon glyphicon-eur"]图标按钮文字[/button]type:选填,不填默认为矩形按钮。可选值:round:椭圆形按钮 color: 选填,不填默认为success(绿色),可选值:light:白色info:蓝色dark:深色success:绿色black:黑色warning:黄色primary:紫色danger:红色icon:选填,不填默认为文字按钮,可用按钮见图标列表url:选填,填写点击的链接。举例:如果你的链接是http://www.baidu.com,请手动将/前面加一个反斜杆\,即http:\/\/www.baidu.com举例:[button color="danger" icon="fontello fontello-gratipay" url="http:\/\/wpa.qq.com\/msgrd?v=3&uin=535425690&site=qq&menu=yes"]点击QQ咨询购买(√推荐)[/button] [button color="success" icon="glyphicon glyphicon-send" url="mailto:
[email protected]
"]ihewro#163.com[/button]文章内插入音乐点击编辑器的插入音乐图标可以在文章内可以插入音乐歌曲地址,支持云解析和本地MP3地址两种方式:时光机的音乐插入按钮也是同样的操作 云解析歌曲:暂时支持解析单曲,不支持歌单,支持以下媒体: 网易云音乐:http://music.163.com/#/song?id=40147556QQ音乐:https://y.qq.com/n/yqq/song/000jDQWP4JiB3y.html虾米音乐:http://www.xiami.com/song/bf08DNT3035f酷狗音乐:http://www.kugou.com/song/#hash=09E8DE70A24C97B92A29F6A19F3528A2百度音乐:http://music.baidu.com/song/268275324 本地mp3地址播放: 示例:直接在输入框中输入.mp3结尾的地址,并填写歌曲名和歌手的名称。[hplayer title="歌曲名" author="歌手" url="http:\/\/xxx.com\/xxx.mp3" size="large" /]文章页面插入播放器size默认为large时光机插入播放器size默认为small你也可以手动改动这个标签的内容以选择不同的播放器样式:)文章内插入视频点击编辑器的插入音乐图标可以插入视频,只支持本地的视频地址的播放时光机的视频插入按钮也是同样的操作直接在输入框中输入视频的地址即可,一般以.mp4结尾的资源地址。示例:[vplayer url="http://xxx.com/xxx.mp4" pic="http://xxx.com/xxx.png"]url:视频地址pic:视频背景图片相关问题:默认的播放器比较简单,复杂需求可以尝试DPlayer-Typecho,主题已经内置适配代码。文章内调用其他文章点击编辑器的调用文章的按钮可以调用其他文章并显示。[post cid="1" /] [post cid="1" cover="http:\/\/localhost\/build\/usr\/themes\/handsome\/usr\/img\/sj\/6.jpg"/] cid:必填,是文章的唯一编号,在后台的编辑文章的地址可以看到,比如http://localhost/build/admin/write-post.php?cid=23,值为23cover:可选项,调用文章显示的封面,如果不填则默认显示随机缩略图。文章内调用外链网站v5.0及其以上版本支持调用外链[post url="https:\/\/www.ihewro.com" title="友人C" intro="一个个人博客" cover="http://www.ihewro.com/img/xxx.jpg" /]title:必填,外链的名称/标题url:必填,外链的地址(请填写绝对地址,就是浏览器地址栏什么样的就填什么样的)intro:(可选)外链网站的简介/介绍cover:(选填)外链网站的介绍图片地址文章内插入相册v5.1 版本及其以上支持使用方法:[album](插入图片,支持图片的HTML格式或者是markdown语法都可以,支持外链或者附件上传均可)[/album]举例://方式1(markdown语法) [album] ![图片描述1][1] ![图片描述2][2] [/album] [1]: http://xxx.com/xxx1.jpg [2]: http://xxx.com/xxx2.jpg //方式2(markdown语法) [album]   [/album] //方式3(HTML语法) [album] <img src="http://xxx.com/xxx1.jpg" alt="图片描述1" /> <img src="http://xxx.com/xxx2.jpg" alt="图片描述2" /> [/album]相关问题:typecho1.1版本编辑器无法解析HTML代码文章中使用mathJax公式需要在后台外观设置——主题增强功能中启用公式(MathJax)选项。语法格式://块级公式: $$ 公式内容 $$ $$ x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} $$ // 行内公式: $ 行内公式内容 $ \\( 行内公式内容 \\) $\Gamma(n) = (n-1)!\quad\forall n\in\mathbb N$ \\( x = \dfrac{-b \pm \sqrt{b^2 - 4ac}}{2a} \\)文章内部分隐藏回复可见在文章使用使用标签包裹住你想要隐藏的内容,游客必须先回复后才能查看隐藏内容。文章内部分内容登录可见为什么增加这样的功能呢?因为有时候一篇文章并不想完全的加密,部分内容由于隐私问题需要加密。该部分内容仅登录用户(如果是个人博客就是仅博主)可见。在文章中使用文章中插入短代码高亮文本[scode type="share"]这是灰色的短代码框,常用来引用资料什么的[/scode] [scode type="yellow"]这是黄色的短代码框,常用来做提示,引起读者注意。[/scode] [scode type="red"]这是红色的短代码框,用于严重警告什么的。[/scode] [scode type="lblue"]这是浅蓝色的短代码框,用于显示一些信息。[/scode] [scode type="green"]这是绿色的短代码框,显示一些推荐信息。[/scode]文章中插入收缩框示例代码:[collapse title="标题" status="false"]一些文字内容[/collapse] [collapse title="标题"]一些文字内容[/collapse]其中status为false 表示默认不显示文字内容,为true表示默认显示内容。不写status 属性,默认是展开内容的。文章内插入标签卡示例代码:[tabs] [tab name="标签页 1" active="true"]内容 1[/tab] [tab name="标签页 2"]内容 2[/tab] [/tabs]每个tab 都必须包括name属性,只能有一个tab 添加active属性,表示默认显示该tab的内容。此外tab支持更多css的属性,比如颜色,字体粗细等:[tab name="标签页 2" color:"#000" font-weight="bold"]高级内容文本示例[/tab]文章内插入标签示例代码:[tag]默认白色文字[/tag] [tag type="primary"]紫色文字[/tag] [tag type="info"]蓝色文字[/tag] [tag type="warning"]黄色文字[/tag] [tag type="danger"]红色文字[/tag] [tag type="success"]绿色文字[/tag] [tag type="dark"]黑色文字[/tag]文章内插入图集示例代码:默认样式是pc端一行最多显示3个,根据屏幕尺寸调整每行显示的图片个数[alubm] [普通的图片插入,支持markdown语法和html语法,混合也可以] [/album]增加type="photos" 则album下的图片排成一行,并根据图片的长高比自动排列[alubm type="photos"] [普通的图片插入,支持markdown语法和html语法,混合也可以] [/album]博客时间友好格式化 使用效果 几小时前 几天前 几月前 几年前当时间不是整小时/天/月/年 时会显示默认的时间格式 开启方法 后台选择设置——评论——评论日期格式 内填写natural。在这里同样可以修改博客的时间格式为你需要的时间格式,值为标准的php格式。如标准时间格式:Y-n-j H:i:s 首页轮播图设置样例代码:{"title":"第一篇文章","link":"","cover":"","desc":""}, {"title":"第一篇文章","link":"","cover":"","desc":""}{"title":"handsome —— 一如少年般模样","link":"http://www.ihewro.com", "cover":"xxx.jpg","desc":"在复杂中,保持简洁。 一款精心打磨后的typecho主题。"}, {"title":"Focus——不只是RSS订阅器","link":"","cover":"xxx.jpg","desc":"拒绝信息化的算法推送"}属性介绍:title: 文章标题link: 文章的地址cover: 文章图片地址,比例建议8:3,不要太小,否则显示的不清楚desc: 简单描述(不要太长)最后一个}后面不要加上英文逗号 评论表情只需要修改主题目录下面的usr/OwO.json文件修改表情主题内置三个栏目颜文字和阿鲁和推特直接在原有的代码上面做一些修改即可,比如图片替换,文字替换等。(具体代码含义见下面 )增加新的表情栏目"新的表情栏目名称": { "name": "表情包文件夹名称",//只有图片表情类型才需要加这一项 "type": "emoticon/emoji/image", "container": [ { "icon": "OωO", "text": "Author: DIYgod" }, { "icon": "OωO", "text": "Author: DIYgod" }, ] }评论表情图片存储在主题目录下的usr/img/emotion表情名称name:该项只有当表情类型为图片表情时候才需要添加name的值对应了emotion文件夹下的表情包文件夹名称。如值为aru,文件夹名称对应为aru。建议填写英文表情类别type有三种:emoticon: 颜文字emoji: emoji表情(比如这些图标,typecho的数据库类型默认不支持emoji编码)image: 图片表情,只支持.png 后缀的图片container下存储的是表情的具体内容:icon:表示的表情具体内容:颜文字就填具体的颜文字emoji表情就填具体的emoji图标图片表情填写对应图片的文件名,如angry.png,填angrytext:指的是鼠标悬停在表情上面显示的提示文字,一般为中文提示 图标列表主题内置了大量的网页图标 (非图片格式),方便在 自定义栏目中使用。可用图标handsome v4.3.1 由原来的fa fa- 修改为fontello fontello-,是为了避免与fontawesome库冲突,你可以自行引入该图标库,以便使用更多图标,但是会带来一定的加载体积。引入更多图标1. 主题内置的iconfont图标:2. 主题内置的fontello图标: 3. bootcss自带的Glyphicons字体图标: 详细见Glyphicons 字体图标4. 主题内置的feather图标支持 feather的所有图标。第一项和第二项的图标很少,如果找不到相应图标,建议在第三项的图标库中寻找相关问题:自定义栏目的图标使用使用方法举个例子: <!--首页名称左侧的图标设置项,直接填写class的内容即可,如:--> <!--iconfont图标--> iconfont icon-xxx <!--Glyphicons图标--> glyphicon glyphicon-eur <!--fontello图标--> fontello fontello-xxx <!--feather图标--> xxx <!--下面三种是一般的HTML用法,一般是使用不到的--> <!--iconfont图标--> <i class="iconfont icon-xxx"></i> <!--Glyphicons图标--> <i class="glyphicon glyphicon-eur"></i> <!--fontello图标--> <i class="fontello fontello-xxx"></i> <!--feather图标--> <i data-feather="xxx"></i> 使用用途:直接修改主题内的图标,主题的所有图标都是使用的是网页图标,你可以更换图标的类名来更换图标。 (不推荐,因为更新后会覆盖修改内容)在 自定义左侧边栏栏目 和 自定义顶部导航按钮 和 首页名称左侧的图标设置项 中使用。具体见:自定义栏目 速度优化本地图片云存储(镜像)加速4.3.0 进行了升级,请务必重新更新配置在配置框按照格式填写(镜像空间的自定义域名)| (域名商)如:http://assets.ihewro.com | UPYUN实现思路就是:将博客服务器本地图片资源地址都转换为镜像空间的地址,访问云服务商的镜像空间,通常能获得更快的速度。下面分别写下又拍云和七牛云的配置过程: 又拍云举例: 创建服务——CDN按照下图配置创建完成后,需要在域名解析中,将刚才的加速域名解析到给定分配的cname地址 在服务配置的——回源管理——开启源站资源迁移 七牛云举例: 选择对象存储——镜像存储——填写镜像空间地址注意:你的七牛空间必须在镜像存储的设置项中填写你的博客地址(例如:https://www.ihewro.com/),这样才能达到加速的效果。云存储选项其实主题外观设置那里写的比较清楚了。webp格式目前主要是Chrome支持,所以一般正确的用法是,不要在后台启用webp图片格式。而是去云服务器商的图片处理设置里开启webp的自适应(比如又拍云的就是在性能优化——WebP自适应选项,开启了就可以了),会自动根据浏览器支持情况来是否转换为webp格式。将本地静态资源上传到你的cdn上如果设置了本地图片云存储(镜像)加速,这个选项无需再配置了。因为上面的选项就相当于全站镜像到云服务器商,博客的静态资源会直接访问镜像空间的资源。请在你的云存储服务商设置允许资源的跨域访问,否则会导致字体文件无法访问而显示页面图标。如果不知道如何设置,可以发工单问客服(这是最简单的方法,因为不同服务器提供商具体设置我也不是很清楚),一般能够得到解决方法。需要在后台外观设置——将本地静态资源上传到你的cdn上中配置:使用该项设置前,你必须有自己搭建的cdn服务器(不是指当前服务器)主题目录下的/assets/目录下有 css、js、fonts、img四个静态资源文件夹。你需要把asset目录上传到你的cdn服务器上,比如CDN服务器的 handsome目录里,地址即为 https://cdn.ihewro.com/handsome/assets/在当前框中就填入该地址,主题就会引用你搭建的cdn上面的资源,而不再引用当前服务器上的资源热心用户提供的静态资源服务器地址 星路博客 为了提高各位使用Handsome主题的用户的加载速度,星路博客的博主将Handsome主题的静态文件全部处理后存放在阿里云CDN上,未设置防盗链。供各位博主使用。为了节约钱财(博主穷),请不要大量访问。Handsome主题的后台设置-速度优化-将本地静态资源上传到你的cdn上中填写://格式: https://asset.starroad.top/handsome/{版本号}/ //举例: https://asset.starroad.top/handsome/5.0.0 https://asset.starroad.top/handsome/5.1.0 https://asset.starroad.top/handsome/5.1.1提供5.0.0-5.1.1的静态文件。如有其他问题,请参见本博客博文。 Peter Peng //格式: https://ufile.goldpetergood.top/HandSome/版本号/assets //举例: https://ufile.goldpetergood.top/HandSome/5.2.0 https://ufile.goldpetergood.top/HandSome/5.3.0 多语言设置主题内置了多语言包,默认选择根据浏览器自动选择语言,后台外观设置可以手动修改语言。多语言分为两部分:主题默认集成多语言文件(在主题的根目录的lang文件夹下)用户自定义语言文件(在主题的根目录usr/lang文件夹下)用户自定义语言文件优先级最高,请勿修改默认翻译文件(lang/目录下面的语言文件),只要修改usr/lang下的语言文件即可。通过修改相应的语言文件,可以更改主题里面**任何词组**和**时间格式**。在本文最后会举几个例子方便大家自行修改。 语言显示规则Auto :自动根据用户浏览器的语言设置显示相应的语言文件。简体中文 :显示顺序依次是:usr/lang/zh_CN.php —> lang/zh_CN.php,其他的语言文件(如zh_TW.php)则不会生效。其他语言设置同理。修改主题默认翻译以语言设置中选择了使用简体中文为例比如:文章页面的「浏览次数」默认显示为「200次浏览」,希望改成「200次小伙伴来过」在usr/lang/zh_CN.php修改如下:/** * @return array 返回包含翻译文本的数组 */ public function translated() { return array( '次浏览' => '次小伙伴来过' //添加翻译的词汇,每两组之间,用英文逗号隔开 ); }注意,语言文件的翻译,是针对**已存在的词组**进行重新翻译,**而不是对任意汉字或不存在的词组翻译**。打开`lang/zh_TW.php` 可以看到所有可以翻译的词组。(目前所有翻译词组没有分类,有些凌乱,v4.0.0会进行整理) 再比如:文章顶部的「最后修改时间的时间格式」,默认为:「Y 年 m 月 d 日 h : i A」,想要修改为24进制时间在相应的语言文件的翻译函数里面增加:'Y 年 m 月 d 日 h : i A' => 'Y 年 m 月 d 日 G : i "修改其他语言同上所述,是完全一样的。增加自定义语言文件主题默认集成了中文简体、中文繁体、英语三种语言设置。首先需要了解多语言文件的命名规则:多语言文件名称 = Locale Code + .php。如 zh_CN.php和en.php一些常见语言的Local Code:zh_CN: 中文简体 zh_HK: 中文繁体,港澳 zh_TW: 中文繁体,台湾 en : 英语 en_US: 英语,美式 en_CA: 英语,加拿大 en_AU: 英语,澳洲 ja : 日语 ko : 韩语如果你想再增加一份新的语言文件,比如 日语首先在usr/lang目录下创建语言文件:ja.php文件初始化内容如下:<?php if (!defined('__TYPECHO_ROOT_DIR__')) exit; /** * ja.php * Author : Your name * Date : * Version : * Description: */ class Usr_Lang_ja extends Lang { /** * @return string 返回语言名称 */ public function name() { return "日语"; } /** * @return array 返回包含翻译文本的数组 */ public function translated() { return array( '首页' => '家', '分类' => '分類' ); } public function dateFormat() { return "月のM Y D日"; } }在文件中的translated函数里面,按照格式填写翻译内容即可。最后在后台语言设置中选择日语即可。自己创建的语言文件中,需要对所有的**已存在的词组进行翻译**,否则将默认返回简体中文默认的词组。这项工作量要远远大于修改主题默认翻译。 自定义栏目主题外观设置中提供了非常简单的自定义设置,无需修改主题源码即可配置以下自定义栏目。配置中可以实现两个功能,一种是 添加自定义栏目/按钮,另一种是隐藏主题默认栏目/按钮。1. 左侧导航栏目 2. 顶部导航按钮 3. 时光机的社会化图标 4. 时光机的联系方式内容下面配置中所有的可用网页图标列表,参考[图标列表](/icons) 左侧边栏导航添加自定义栏目:name:代表显示栏目/按钮的名称class:使用图标库中的第1-3种的图标的classfeather:使用图标库第4种图标使用该属性link:代表栏目/按钮的链接target(可选): 代表定在何处打开链接文档,如_blank:浏览器总在一个新打开、未命名的窗口中载入目标文档。_self:代表在当前窗口打开。不填则为:_blank。更多介绍{"name":"音乐","class":"glyphicon glyphicon-music","link":"xxx.com"}, {"name":"音乐2","feather":"music","link":"xxx.com"}, {"name":"笔记","class":"glyphicon glyphicon-book","link":"xxx.com"}, {"name":"相册","class":"fontello fontello-picture","link":"xxx.com","target":"_self"}每两项之间,用英文逗号(,)隔开,最后一项请勿加上逗号。检查配置语法是否正确的方法:将配置内容复制到json校验 网站中,可以检查你的填写配置语法是否正确。不显示图标,原因可能是语法错误或者图标根本就不在图标列表中,只能使用图标列表中的图标。如果想要链接ajax(无刷新)的点击效果,确保你的链接是绝对地址(浏览器地址栏什么样的就是怎么填)而且是本站地址,并且target属性为_self。隐藏默认栏目:左侧边栏目默认加载首页按钮。隐藏方法:{"name":"home","status":"hide"}顶部导航栏目添加自定义栏目:与左侧边栏导航配置的书写规则完全相同:{"name":"音乐","class":"fa fa-music","link":"xxx.com"}, {"name":"相册","class":"fontello fontello-picture","link":"xxx.com","target":"_self"}每两项之间,用英文逗号(,)隔开,最后一项请勿加上逗号。检查配置语法是否正确的方法:将配置内容复制到json校验 网站中,可以检查你的填写配置语法是否正确。不显示图标,原因可能是语法错误或者图标根本就不在图标列表中,只能使用图标列表中的图标。如果想要链接ajax(无刷新)的点击效果,确保你的链接是绝对地址(浏览器地址栏什么样的就是怎么填)而且是本站地址,并且target属性为_self。隐藏默认栏目:顶部导航按钮默认加载闲言碎语按钮。隐藏方法:{"name":"talk","status":"hide"}时光机社会化图标默认已经填入了配置,书写规则和上面基本类似:name:代表显示按钮的名称class:表示按钮的网页图标的样式link:代表按钮的链接status:当status值为single时,特指页面中的绿色文字按钮,此时无需填写class项。{"name":"twitter","class":"fa fa-twitter","link":"#"}, {"name":"facebook","class":"fa fa-facebook","link":"#"}, {"name":"googlepluse","class":"fa fa-google-plus","link":"#"}, {"name":"github","status":"single","link":"#"}简单配置,只需要修改"value"和"link"的值(修改# 那个位置的值,不要修改错位置!!)。高级配置,模仿上面的写法,增加或者删除相应的项目即可。每两项之间,用英文逗号(,)隔开,最后一项请勿加上逗号!!时光机联系方式默认已经填写email、QQ、微博以及网易云音乐的配置:name:代表显示栏目的名称img:表示该联系方式的图标(图片格式)link:代表联系方式的地址{"name":"email","img":"https://ww4.sinaimg.cn/large/a15b4afegy1fg2pmtjbaej201s01s0aw","value":"
[email protected]
","link":"#"}, {"name":"QQ","img":"https://ww4.sinaimg.cn/large/a15b4afegy1fg2pnirhr2j201s01va9u","value":"535425690","link":"#"}, {"name":"微博","img":"https://ww4.sinaimg.cn/large/a15b4afegy1fg2pofbz5fj201s01swe9","value":"@i超级男孩","link":"http://weibo.com/hewro"}, {"name":"网易云音乐","img":"https://ww4.sinaimg.cn/large/a15b4afegy1fg2pouholzj201s01s0ja","value":"@许多年以后我依然是我","link":"http://music.163.com/#/user/home?id=83271175"}简单配置,只需要修改"value"和"link"的值(修改# 那个位置的值,不要修改错位置!!)。高级配置,模仿上面的写法,增加或者删除相应的项目即可。每两项之间,用英文逗号(,)隔开,最后一项请勿加上逗号!! 个性化修改以下模块由勤劳的使用者提供的关于handsome主题的自定义修改内容,你可以应用到自己的主题中来。欢迎投稿,感谢! handsome用户分享社区用户可以在「handsome自助授权平台」中添加教程,可以添加任何你觉得不错的教程本博客基于Handsome主题的一些小修改教程这篇文章主要是typecho下的彩色标签云实现方式一个追番列表独立页模板把可爱的 Pio 捉到博客上吧!Typecho 在主题与 EditorMD 前台解析冲突的情况下使用其样式ColorHighlight插件实现Mac风格代码高亮Typecho下实现一键评论打卡功能安利一款Hansome主题专用的UserAgent插件神代綺凜式魔改出现的相关问题解决附魔改教程handsome主题美化/修改教程 typecho相关以下内容与主题无关,是为了方便typecho新手更快熟悉这个博客系统而创建的。以下内容不断补充,如果你有更好的推荐和建议,欢迎一起充实。好用的编辑器插件 插件名称 介绍 Editor.md for Typecho Markdown 编辑器,主要是支持markdown语法的 UEditor-for-Typecho 这款是html编辑器,适合新手用,简单方便,功能强大 MyEditor:MyEditor 是一款采用TinyMCE核心,支持切换编辑器、插入图片的Typecho编辑器插件。 邮件通知插件插件 插件名称 介绍 Mailer typecho 创始人对typecho1.1 适配的插件,必须是1.1+版本才可以,因为文字中给的是Mailer.tar.gz 后缀,我解压了上传到百度云的是zip包,直接下载百度云那个即可。 CommentToMail(羽飞原版) 老牌的typecho评论通知插件,可是很多小伙伴们说后台怎么配置都无法发信,韩红听了都想打人,我用的可以。 CommentToMail(更新版1) 王忘杰更新版本: 更新了PHP Mailer版本关闭了使用SMTP发信的证书认证(QQ邮箱证书加密级别太低) CommentToMail(更新版2) 致远博客更新版本:使用网址监控方法避免异步触发失败 个人喜欢的其他插件 插件名称 介绍 SmartSpam 非常强大的一款Typecho智能评论过滤插件,就此别过垃圾评论的入侵者吧。 AutoTags 标签自动生成插件,避免了手动填写Tag,对我这种懒得填tag的人很有帮助。 Parsedown Plugin 弥补了typecho1.0正式版本md语法不支持表格的缺陷。 Sticky 一个小巧的文章置顶插件。 APlayer 是在原作者ZGQ394基础上由FaithPatrick修改而来。一款很好看的音乐播放器插件。 主题外观配色指南主题支持单栏、双栏、三栏。主题布局非常丰富,通过后台的外观设置,轻松搭配不一样的博客风格。布局单栏——极简模式外观设置——置顶导航 开启(最侧边栏置顶)外观设界面——页面元素显示设置——右侧边栏元素控制——不显示整体(不显示右侧边栏)双栏模式上面的两个操作执行一个即可三栏模式默认,显示更多的信息配色选择在外观设置——主题色调选择,可以看到主题默认内置了14种配色。如默认的dark-white-dark分别代表:「左侧边栏和上导航栏的交集部分(logo位置)」、「上导航栏」、「侧导航栏」。自定义主题色调自定义搭配已有的颜色(后续考虑提供更多的配色):black纯黑色white白色info蓝色success绿色danger深红色dark深色light灰白色primary紫色其中dker 表示当前颜色增强搭配样例:全白配色即填写:white-white-white 其他配色举例:white-white-white white dker-white-white dark-light-light分别代表:「左侧边栏和上导航栏的交集部分(logo位置)」、「上导航栏」、「侧导航栏」的颜色。
2020年07月09日
2,171 阅读
0 评论
0 点赞
2020-07-02
WordPress纯代码实现去除分类链接中的category
在网站SEO优化中url优化是相对来说比较重要的环节,WordPress分类的链接地址在WordPress程序中会自带category目录,如果能够去掉分类链接中的category无疑也是网站seo优化的一种手法。下面分享一段去掉分类链接中的category的WordPress代码:复制下面代码粘贴到functions.php文件里即可!//去掉分类链接中的category add_action( 'load-themes.php', 'no_category_base_refresh_rules'); add_action('created_category', 'no_category_base_refresh_rules'); add_action('edited_category', 'no_category_base_refresh_rules'); add_action('delete_category', 'no_category_base_refresh_rules'); function no_category_base_refresh_rules() { global $wp_rewrite; $wp_rewrite -> flush_rules(); } // register_deactivation_hook(__FILE__, 'no_category_base_deactivate'); // function no_category_base_deactivate() { // remove_filter('category_rewrite_rules', 'no_category_base_rewrite_rules'); //// We don't want to insert our custom rules again // no_category_base_refresh_rules(); // } // Remove category base add_action('init', 'no_category_base_permastruct'); function no_category_base_permastruct() { global $wp_rewrite, $wp_version; if (version_compare($wp_version, '3.4', '<')) { // For pre-3.4 support $wp_rewrite -> extra_permastructs['category'][0] = '%category%'; } else { $wp_rewrite -> extra_permastructs['category']['struct'] = '%category%'; } } // Add our custom category rewrite rules add_filter('category_rewrite_rules', 'no_category_base_rewrite_rules'); function no_category_base_rewrite_rules($category_rewrite) { //var_dump($category_rewrite);// For Debugging $category_rewrite = array(); $categories = get_categories(array('hide_empty' => false)); foreach ($categories as $category) { $category_nicename = $category -> slug; if ($category -> parent == $category -> cat_ID)// recursive recursion $category -> parent = 0; elseif ($category -> parent != 0) $category_nicename = get_category_parents($category -> parent, false, '/', true) . $category_nicename; $category_rewrite['(' . $category_nicename . ')/(?:feed/)?(feed|rdf|rss|rss2|atom)/? 有点小长,看不懂不要紧,功能实现就行了,要的就是结果。 ] = 'index.php?category_name=$matches[1]&feed=$matches[2]'; $category_rewrite['(' . $category_nicename . ')/page/?([0-9]{1,})/? 有点小长,看不懂不要紧,功能实现就行了,要的就是结果。 ] = 'index.php?category_name=$matches[1]&paged=$matches[2]'; $category_rewrite['(' . $category_nicename . ')/? 有点小长,看不懂不要紧,功能实现就行了,要的就是结果。 ] = 'index.php?category_name=$matches[1]'; } // Redirect support from Old Category Base global $wp_rewrite; $old_category_base = get_option('category_base') ? get_option('category_base') : 'category'; $old_category_base = trim($old_category_base, '/'); $category_rewrite[$old_category_base . '/(.*) 有点小长,看不懂不要紧,功能实现就行了,要的就是结果。 ] = 'index.php?category_redirect=$matches[1]'; //var_dump($category_rewrite);// For Debugging return $category_rewrite; } // Add 'category_redirect' query variable add_filter('query_vars', 'no_category_base_query_vars'); function no_category_base_query_vars($public_query_vars) { $public_query_vars[] = 'category_redirect'; return $public_query_vars; } // Redirect if 'category_redirect' is set add_filter('request', 'no_category_base_request'); function no_category_base_request($query_vars) { //print_r($query_vars);// For Debugging if (isset($query_vars['category_redirect'])) { $catlink = trailingslashit(get_option('home')) . user_trailingslashit($query_vars['category_redirect'], 'category'); status_header(301); header("Location: $catlink"); exit(); } return $query_vars; }
2020年07月02日
1,212 阅读
0 评论
0 点赞
2020-06-16
博客日志配图网站推荐
写博客的时候大家避免不了要用到日志配图,下面我为大家分享一些配图用得到的网站。Pexels优势:搜索功能强大,匹配度高,可以选择尺寸下载,图片质量高,原图分辨率高。劣势:图片种类没有Pixabay多。Pixabay优势:图片种类多,扁平风,摄影都有,可以选择尺寸下载。劣势:搜索功能鸡肋,图片质量一般,需要有一定筛选能力。Unsplash优势:图片质量高劣势:图片种类少,基本都是摄影图片,搜索出来的东西很多不沾边,无法选择尺寸下载需要自己压缩裁剪。可爱图片国内唯美小清新文艺图片壁纸的网站。
2020年06月16日
1,834 阅读
1 评论
0 点赞
2020-06-16
Typecho常用统计代码
一些常用统计<?php Typecho_Widget::widget('Widget_Stat')->to($stat); ?> 文章总数:<?php $stat->publishedPostsNum() ?> 篇 分类总数:<?php $stat->categoriesNum() ?> 个 评论总数:<?php $stat->publishedCommentsNum() ?> 条 页面总数:<?php $stat->publishedPagesNum() ?> 个 当前作者的文章总数:<?php $stat->myPublishedPostsNum() ?> 篇程序自带的统计函数详细参数 说明 代码 获取已发布的文章数目 publishedPostsNum 获取待审核的文章数目 waitingPostsNum 获取草稿文章数目 draftPostsNum 获取当前用户已发布的文章数目 myPublishedPostsNum 获取当前用户待审核文章数目 myWaitingPostsNum 获取当前用户草稿文章数目 myDraftPostsNum 获取当前用户已发布的文章数目 currentPublishedPostsNum 获取当前用户待审核文章数目 currentWaitingPostsNum 获取当前用户草稿文章数目 currentDraftPostsNum 获取已发布页面数目 publishedPagesNum 获取草稿页面数目 draftPagesNum 获取当前显示的评论数目 publishedCommentsNum 获取当前待审核的评论数目 waitingCommentsNum 获取当前垃圾评论数目 spamCommentsNum 获取当前用户显示的评论数目 myPublishedCommentsNum 获取当前用户显示的评论数目 myWaitingCommentsNum 获取当前用户显示的评论数目 mySpamCommentsNum 获取当前文章的评论数目 currentCommentsNum 获取当前文章显示的评论数目 currentPublishedCommentsNum 获取当前文章显示的评论数目 currentWaitingCommentsNum 获取当前文章显示的评论数目 currentSpamCommentsNum 获取分类数目 categoriesNum 该统计函数来自源码typecho/var/Widget/Stat.php <span><?php _me("页面") ?></span> <?php Typecho_Widget::widget('Widget_Stat')->to($stat); ?> <span class="badge bg-default pull-right"> <?php $stat->publishedPagesNum() ?><!--页面总数--> </span
2020年06月16日
1,476 阅读
0 评论
0 点赞
2020-06-13
将Chrome离线小恐龙嵌入博客
前言最近我逛各位大佬的博客时,看到了将chrome的离线游戏嵌入博客,就觉得比较有意思,想抄过来,发现原博客的实现方法和源代码实在粗糙,于是我在github上找到了源码,将其进一步更方便嵌入博客,现在讲讲步骤。试玩正文仅需一个JS文件即可runner.js代码如下!function (A, i) { "object" == typeof exports && "object" == typeof module ? module.exports = i() : "function" == typeof define && define.amd ? define([], i) : "object" == typeof exports ? exports.initRunner = i() : A.initRunner = i() }(this, function () { return function (A) { function i(s) { if (t[s]) return t[s].exports; var e = t[s] = {exports: {}, id: s, loaded: !1}; return A[s].call(e.exports, e, e.exports, i), e.loaded = !0, e.exports } var t = {}; return i.m = A, i.c = t, i.p = "", i(0) }([function (A, i, t) { document.body.insertAdjacentHTML("beforeend", t(3)), t(5); const s = t(6); A.exports = function (A, i) { var t = "string" == typeof A ? document.querySelector(A) : A; return t.classList.add("interstitial-wrapper"), new s(t, i) } }, function (A, i, t) { i = A.exports = t(2)(), i.push([A.id, ".interstitial-wrapper{box-sizing:border-box;margin:0 auto;max-width:600px}.runner-container{width:44px}.runner-canvas,.runner-container{height:150px;max-width:600px;overflow:hidden}.runner-canvas{opacity:1;position:relative;z-index:2}.inverted{transition:-webkit-filter 1.5s cubic-bezier(.65,.05,.36,1),background-color 1.5s cubic-bezier(.65,.05,.36,1);will-change:-webkit-filter,background-color;-webkit-filter:invert(100%);background-color:#000}.controller{background:hsla(0,0%,97%,.1);height:100vh;left:0;position:absolute;top:0;width:100vw;z-index:1}#offline-resources{display:none}", ""]) }, function (A, i) { A.exports = function () { var A = []; return A.toString = function () { for (var A = [], i = 0; i < this.length; i++) { var t = this[i]; t[2] ? A.push("@media " + t[2] + "{" + t[1] + "}") : A.push(t[1]) } return A.join("") }, A.i = function (i, t) { "string" == typeof i && (i = [[null, i, ""]]); for (var s = {}, e = 0; e < this.length; e++) { var n = this[e][0]; "number" == typeof n && (s[n] = !0) } for (e = 0; e < i.length; e++) { var o = i[e]; "number" == typeof o[0] && s[o[0]] || (t && !o[2] ? o[2] = t : t && (o[2] = "(" + o[2] + ") and (" + t + ")"), A.push(o)) } }, A } }, function (A, i) { A.exports = '<div id=offline-resources> <img id=offline-resources-1x src="data:image/png;base64,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"> <img id=offline-resources-2x src="data:image/png;base64,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"> <template id=audio-resources> <audio id=offline-sound-press src=data:audio/mpeg;base64,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></audio> <audio id=offline-sound-hit src=data:audio/mpeg;base64,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 i18n-processed=""></audio> <audio id=offline-sound-reached src="data:audio/mpeg;base64,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"></audio> </template> </div>'; }, function (A, i, t) { function s(A, i) { for (var t = 0; t < A.length; t++) { var s = A[t], e = I[s.id]; if (e) { e.refs++; for (var n = 0; n < e.parts.length; n++) e.parts[n](s.parts[n]); for (; n < s.parts.length; n++) e.parts.push(r(s.parts[n], i)) } else { for (var o = [], n = 0; n < s.parts.length; n++) o.push(r(s.parts[n], i)); I[s.id] = {id: s.id, refs: 1, parts: o} } } } function e(A) { for (var i = [], t = {}, s = 0; s < A.length; s++) { var e = A[s], n = e[0], o = e[1], h = e[2], a = e[3], r = {css: o, media: h, sourceMap: a}; t[n] ? t[n].parts.push(r) : i.push(t[n] = {id: n, parts: [r]}) } return i } function n(A, i) { var t = l(), s = m[m.length - 1]; if ("top" === A.insertAt) s ? s.nextSibling ? t.insertBefore(i, s.nextSibling) : t.appendChild(i) : t.insertBefore(i, t.firstChild), m.push(i); else { if ("bottom" !== A.insertAt) throw new Error("Invalid value for parameter 'insertAt'. Must be 'top' or 'bottom'."); t.appendChild(i) } } function o(A) { A.parentNode.removeChild(A); var i = m.indexOf(A); i >= 0 && m.splice(i, 1) } function h(A) { var i = document.createElement("style"); return i.type = "text/css", n(A, i), i } function a(A) { var i = document.createElement("link"); return i.rel = "stylesheet", n(A, i), i } function r(A, i) { var t, s, e; if (i.singleton) { var n = p++; t = C || (C = h(i)), s = c.bind(null, t, n, !1), e = c.bind(null, t, n, !0) } else A.sourceMap && "function" == typeof URL && "function" == typeof URL.createObjectURL && "function" == typeof URL.revokeObjectURL && "function" == typeof Blob && "function" == typeof btoa ? (t = a(i), s = d.bind(null, t), e = function () { o(t), t.href && URL.revokeObjectURL(t.href) }) : (t = h(i), s = g.bind(null, t), e = function () { o(t) }); return s(A), function (i) { if (i) { if (i.css === A.css && i.media === A.media && i.sourceMap === A.sourceMap) return; s(A = i) } else e() } } function c(A, i, t, s) { var e = t ? "" : s.css; if (A.styleSheet) A.styleSheet.cssText = f(i, e); else { var n = document.createTextNode(e), o = A.childNodes; o[i] && A.removeChild(o[i]), o.length ? A.insertBefore(n, o[i]) : A.appendChild(n) } } function g(A, i) { var t = i.css, s = i.media; if (s && A.setAttribute("media", s), A.styleSheet) A.styleSheet.cssText = t; else { for (; A.firstChild;) A.removeChild(A.firstChild); A.appendChild(document.createTextNode(t)) } } function d(A, i) { var t = i.css, s = i.sourceMap; s && (t += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(s)))) + " */"); var e = new Blob([t], {type: "text/css"}), n = A.href; A.href = URL.createObjectURL(e), n && URL.revokeObjectURL(n) } var I = {}, E = function (A) { var i; return function () { return "undefined" == typeof i && (i = A.apply(this, arguments)), i } }, u = E(function () { return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()) }), l = E(function () { return document.head || document.getElementsByTagName("head")[0] }), C = null, p = 0, m = []; A.exports = function (A, i) { i = i || {}, "undefined" == typeof i.singleton && (i.singleton = u()), "undefined" == typeof i.insertAt && (i.insertAt = "bottom"); var t = e(A); return s(t, i), function (A) { for (var n = [], o = 0; o < t.length; o++) { var h = t[o], a = I[h.id]; a.refs--, n.push(a) } if (A) { var r = e(A); s(r, i) } for (var o = 0; o < n.length; o++) { var a = n[o]; if (0 === a.refs) { for (var c = 0; c < a.parts.length; c++) a.parts[c](); delete I[a.id] } } } }; var f = function () { var A = []; return function (i, t) { return A[i] = t, A.filter(Boolean).join("\n") } }() }, function (A, i, t) { var s = t(1); "string" == typeof s && (s = [[A.id, s, ""]]); t(4)(s, {}); s.locals && (A.exports = s.locals) }, function (A, i) { function t(A, i) { this.outerContainerEl = "string" == typeof A ? document.querySelector(A) : A, this.containerEl = null, this.config = i || t.config, this.dimensions = t.defaultDimensions, this.canvas = null, this.canvasCtx = null, this.tRex = null, this.distanceMeter = null, this.distanceRan = 0, this.highestScore = 0, this.time = 0, this.runningTime = 0, this.msPerFrame = 1e3 / V, this.currentSpeed = this.config.SPEED, this.obstacles = [], this.started = !1, this.activated = !1, this.crashed = !1, this.paused = !1, this.inverted = !1, this.invertTimer = 0, this.resizeTimerId_ = null, this.playCount = 0, this.audioBuffer = null, this.soundFx = {}, this.audioContext = null, this.images = {}, this.imagesLoaded = 0, this.loadImages() } function s(A, i) { return Math.floor(Math.random() * (i - A + 1)) + A } function e(A) { D && window.navigator.vibrate && window.navigator.vibrate(A) } function n(A, i, s, e) { var n = document.createElement("canvas"); return n.className = e ? t.classes.CANVAS + " " + e : t.classes.CANVAS, n.width = i, n.height = s, A.appendChild(n), n } function o(A) { for (var i = A.length / 4 * 3, t = atob(A), s = new ArrayBuffer(i), e = new Uint8Array(s), n = 0; i > n; n++) e[n] = t.charCodeAt(n); return e.buffer } function h() { return T ? (new Date).getTime() : performance.now() } function a(A, i, t, s) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.canvasDimensions = s, this.textImgPos = i, this.restartImgPos = t, this.draw() } function r(A, i, s) { var e = (t.defaultDimensions.WIDTH + A.xPos, new I(i.xPos + 1, i.yPos + 1, i.config.WIDTH - 2, i.config.HEIGHT - 2)), n = new I(A.xPos + 1, A.yPos + 1, A.typeConfig.width * A.size - 2, A.typeConfig.height - 2); if (s && g(s, e, n), d(e, n)) for (var o = A.collisionBoxes, h = i.ducking ? u.collisionBoxes.DUCKING : u.collisionBoxes.RUNNING, a = 0; a < h.length; a++) for (var r = 0; r < o.length; r++) { var E = c(h[a], e), l = c(o[r], n), C = d(E, l); if (s && g(s, E, l), C) return [E, l] } return !1 } function c(A, i) { return new I(A.x + i.x, A.y + i.y, A.width, A.height) } function g(A, i, t) { A.save(), A.strokeStyle = "#f00", A.strokeRect(i.x, i.y, i.width, i.height), A.strokeStyle = "#0f0", A.strokeRect(t.x, t.y, t.width, t.height), A.restore() } function d(A, i) { var t = !1, s = (A.x, A.y, i.x); i.y; return A.x < s + i.width && A.x + A.width > s && A.y < i.y + i.height && A.height + A.y > i.y && (t = !0), t } function I(A, i, t, s) { this.x = A, this.y = i, this.width = t, this.height = s } function E(A, i, t, e, n, o, h) { this.canvasCtx = A, this.spritePos = t, this.typeConfig = i, this.gapCoefficient = n, this.size = s(1, E.MAX_OBSTACLE_LENGTH), this.dimensions = e, this.remove = !1, this.xPos = e.WIDTH + (h || 0), this.yPos = 0, this.width = 0, this.collisionBoxes = [], this.gap = 0, this.speedOffset = 0, this.currentFrame = 0, this.timer = 0, this.init(o) } function u(A, i) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.spritePos = i, this.xPos = 0, this.yPos = 0, this.groundYPos = 0, this.currentFrame = 0, this.currentAnimFrames = [], this.blinkDelay = 0, this.animStartTime = 0, this.timer = 0, this.msPerFrame = 1e3 / V, this.config = u.config, this.status = u.status.WAITING, this.jumping = !1, this.ducking = !1, this.jumpVelocity = 0, this.reachedMinHeight = !1, this.speedDrop = !1, this.jumpCount = 0, this.jumpspotX = 0, this.init() } function l(A, i, s) { this.canvas = A, this.canvasCtx = A.getContext("2d"), this.image = t.imageSprite, this.spritePos = i, this.x = 0, this.y = 5, this.currentDistance = 0, this.maxScore = 0, this.highScore = 0, this.container = null, this.digits = [], this.acheivement = !1, this.defaultString = "", this.flashTimer = 0, this.flashIterations = 0, this.invertTrigger = !1, this.config = l.config, this.maxScoreUnits = this.config.MAX_DISTANCE_UNITS, this.init(s) } function C(A, i, t) { this.canvas = A, this.canvasCtx = this.canvas.getContext("2d"), this.spritePos = i, this.containerWidth = t, this.xPos = t, this.yPos = 0, this.remove = !1, this.cloudGap = s(C.config.MIN_CLOUD_GAP, C.config.MAX_CLOUD_GAP), this.init() } function p(A, i, t) { this.spritePos = i, this.canvas = A, this.canvasCtx = A.getContext("2d"), this.xPos = t - 50, this.yPos = 30, this.currentPhase = 0, this.opacity = 0, this.containerWidth = t, this.stars = [], this.drawStars = !1, this.placeStars() } function m(A, i) { this.spritePos = i, this.canvas = A, this.canvasCtx = A.getContext("2d"), this.sourceDimensions = {}, this.dimensions = m.dimensions, this.sourceXPos = [this.spritePos.x, this.spritePos.x + this.dimensions.WIDTH], this.xPos = [], this.yPos = 0, this.bumpThreshold = .5, this.setSourceDimensions(), this.draw() } function f(A, i, t, s) { this.canvas = A, this.canvasCtx = this.canvas.getContext("2d"), this.config = f.config, this.dimensions = t, this.gapCoefficient = s, this.obstacles = [], this.obstacleHistory = [], this.horizonOffsets = [0, 0], this.cloudFrequency = this.config.CLOUD_FREQUENCY, this.spritePos = i, this.nightMode = null, this.clouds = [], this.cloudSpeed = this.config.BG_CLOUD_SPEED, this.horizonLine = null, this.init() } A.exports = t; var S = 600, V = 60, Q = window.devicePixelRatio > 1, T = window.navigator.userAgent.indexOf("CriOS") > -1 || "UIWebViewForStaticFileContent" == window.navigator.userAgent, D = window.navigator.userAgent.indexOf("Mobi") > -1 || T; "ontouchstart" in window; t.config = { ACCELERATION: .001, BG_CLOUD_SPEED: .2, BOTTOM_PAD: 10, CLEAR_TIME: 3e3, CLOUD_FREQUENCY: .5, GAMEOVER_CLEAR_TIME: 750, GAP_COEFFICIENT: .6, GRAVITY: .6, INITIAL_JUMP_VELOCITY: 12, INVERT_FADE_DURATION: 12e3, INVERT_DISTANCE: 700, MAX_CLOUDS: 6, MAX_OBSTACLE_LENGTH: 3, MAX_OBSTACLE_DUPLICATION: 2, MAX_SPEED: 13, MIN_JUMP_HEIGHT: 35, MOBILE_SPEED_COEFFICIENT: 1.2, RESOURCE_TEMPLATE_ID: "audio-resources", SPEED: 6, SPEED_DROP_COEFFICIENT: 3 }, t.defaultDimensions = {WIDTH: S, HEIGHT: 150}, t.classes = { CANVAS: "runner-canvas", CONTAINER: "runner-container", CRASHED: "crashed", ICON: "icon-offline", INVERTED: "inverted", SNACKBAR: "snackbar", SNACKBAR_SHOW: "snackbar-show", TOUCH_CONTROLLER: "controller" }, t.spriteDefinition = { LDPI: { CACTUS_LARGE: {x: 332, y: 2}, CACTUS_SMALL: {x: 228, y: 2}, CLOUD: {x: 86, y: 2}, HORIZON: {x: 2, y: 54}, MOON: {x: 484, y: 2}, PTERODACTYL: {x: 134, y: 2}, RESTART: {x: 2, y: 2}, TEXT_SPRITE: {x: 655, y: 2}, TREX: {x: 848, y: 2}, STAR: {x: 645, y: 2} }, HDPI: { CACTUS_LARGE: {x: 652, y: 2}, CACTUS_SMALL: {x: 446, y: 2}, CLOUD: {x: 166, y: 2}, HORIZON: {x: 2, y: 104}, MOON: {x: 954, y: 2}, PTERODACTYL: {x: 260, y: 2}, RESTART: {x: 2, y: 2}, TEXT_SPRITE: {x: 1294, y: 2}, TREX: {x: 1678, y: 2}, STAR: {x: 1276, y: 2} } }, t.sounds = { BUTTON_PRESS: "offline-sound-press", HIT: "offline-sound-hit", SCORE: "offline-sound-reached" }, t.keycodes = { JUMP: {38: 1, 32: 1}, DUCK: {40: 1}, RESTART: {13: 1} }, t.events = { ANIM_END: "webkitAnimationEnd", CLICK: "click", KEYDOWN: "keydown", KEYUP: "keyup", MOUSEDOWN: "mousedown", MOUSEUP: "mouseup", RESIZE: "resize", TOUCHEND: "touchend", TOUCHSTART: "touchstart", VISIBILITY: "visibilitychange", BLUR: "blur", FOCUS: "focus", LOAD: "load" }, t.prototype = { updateConfigSetting: function (A, i) { if (A in this.config && void 0 != i) switch (this.config[A] = i, A) { case"GRAVITY": case"MIN_JUMP_HEIGHT": case"SPEED_DROP_COEFFICIENT": this.tRex.config[A] = i; break; case"INITIAL_JUMP_VELOCITY": this.tRex.setJumpVelocity(i); break; case"SPEED": this.setSpeed(i) } }, loadImages: function () { Q ? (t.imageSprite = document.getElementById("offline-resources-2x"), this.spriteDef = t.spriteDefinition.HDPI) : (t.imageSprite = document.getElementById("offline-resources-1x"), this.spriteDef = t.spriteDefinition.LDPI), this.init() }, loadSounds: function () { if (!T && window.AudioContext) { this.audioContext = new AudioContext; var A = document.getElementById(this.config.RESOURCE_TEMPLATE_ID).content; for (var i in t.sounds) { var s = A.getElementById(t.sounds[i]).src; s = s.substr(s.indexOf(",") + 1); var e = o(s); this.audioContext.decodeAudioData(e, function (A, i) { this.soundFx[A] = i }.bind(this, i)) } } }, setSpeed: function (A) { var i = A || this.currentSpeed; if (this.dimensions.WIDTH < S) { var t = i * this.dimensions.WIDTH / S * this.config.MOBILE_SPEED_COEFFICIENT; this.currentSpeed = t > i ? i : t } else A && (this.currentSpeed = A) }, init: function () { this.adjustDimensions(), this.setSpeed(), this.containerEl = document.createElement("div"), this.containerEl.className = t.classes.CONTAINER, this.canvas = n(this.containerEl, this.dimensions.WIDTH, this.dimensions.HEIGHT, t.classes.PLAYER), this.canvasCtx = this.canvas.getContext("2d"), this.canvasCtx.fillStyle = "#f7f7f7", this.canvasCtx.fill(), t.updateCanvasScaling(this.canvas), this.horizon = new f(this.canvas, this.spriteDef, this.dimensions, this.config.GAP_COEFFICIENT), this.distanceMeter = new l(this.canvas, this.spriteDef.TEXT_SPRITE, this.dimensions.WIDTH), this.tRex = new u(this.canvas, this.spriteDef.TREX), this.outerContainerEl.appendChild(this.containerEl), D && this.createTouchController(), this.startListening(), this.update(), window.addEventListener(t.events.RESIZE, this.debounceResize.bind(this)) }, createTouchController: function () { this.touchController = document.createElement("div"), this.touchController.className = t.classes.TOUCH_CONTROLLER }, debounceResize: function () { this.resizeTimerId_ || (this.resizeTimerId_ = setInterval(this.adjustDimensions.bind(this), 250)) }, adjustDimensions: function () { clearInterval(this.resizeTimerId_), this.resizeTimerId_ = null; var A = window.getComputedStyle(this.outerContainerEl), i = Number(A.paddingLeft.substr(0, A.paddingLeft.length - 2)); this.dimensions.WIDTH = this.outerContainerEl.offsetWidth - 2 * i, this.canvas && (this.canvas.width = this.dimensions.WIDTH, this.canvas.height = this.dimensions.HEIGHT, t.updateCanvasScaling(this.canvas), this.distanceMeter.calcXPos(this.dimensions.WIDTH), this.clearCanvas(), this.horizon.update(0, 0, !0), this.tRex.update(0), this.activated || this.crashed || this.paused ? (this.containerEl.style.width = this.dimensions.WIDTH + "px", this.containerEl.style.height = this.dimensions.HEIGHT + "px", this.distanceMeter.update(0, Math.ceil(this.distanceRan)), this.stop()) : this.tRex.draw(0, 0), this.crashed && this.gameOverPanel && (this.gameOverPanel.updateDimensions(this.dimensions.WIDTH), this.gameOverPanel.draw())) }, playIntro: function () { if (this.started || this.crashed) this.crashed && this.restart(); else { this.playingIntro = !0, this.tRex.playingIntro = !0; var A = "@-webkit-keyframes intro { from { width:" + u.config.WIDTH + "px }to { width: " + this.dimensions.WIDTH + "px }}"; document.styleSheets[0].insertRule(A, 0), this.containerEl.addEventListener(t.events.ANIM_END, this.startGame.bind(this)), this.containerEl.style.webkitAnimation = "intro .4s ease-out 1 both", this.containerEl.style.width = this.dimensions.WIDTH + "px", this.touchController && this.outerContainerEl.appendChild(this.touchController), this.activated = !0, this.started = !0 } }, startGame: function () { this.runningTime = 0, this.playingIntro = !1, this.tRex.playingIntro = !1, this.containerEl.style.webkitAnimation = "", this.playCount++, document.addEventListener(t.events.VISIBILITY, this.onVisibilityChange.bind(this)), window.addEventListener(t.events.BLUR, this.onVisibilityChange.bind(this)), window.addEventListener(t.events.FOCUS, this.onVisibilityChange.bind(this)) }, clearCanvas: function () { this.canvasCtx.clearRect(0, 0, this.dimensions.WIDTH, this.dimensions.HEIGHT) }, update: function () { this.drawPending = !1; var A = h(), i = A - (this.time || A); if (this.time = A, this.activated) { this.clearCanvas(), this.tRex.jumping && this.tRex.updateJump(i), this.runningTime += i; var t = this.runningTime > this.config.CLEAR_TIME; 1 != this.tRex.jumpCount || this.playingIntro || this.playIntro(), this.playingIntro ? this.horizon.update(0, this.currentSpeed, t) : (i = this.started ? i : 0, this.horizon.update(i, this.currentSpeed, t, this.inverted)); var s = t && r(this.horizon.obstacles[0], this.tRex); s ? this.gameOver() : (this.distanceRan += this.currentSpeed * i / this.msPerFrame, this.currentSpeed < this.config.MAX_SPEED && (this.currentSpeed += this.config.ACCELERATION)); var e = this.distanceMeter.update(i, Math.ceil(this.distanceRan)); if (e && this.playSound(this.soundFx.SCORE), this.invertTimer > this.config.INVERT_FADE_DURATION) this.invertTimer = 0, this.invertTrigger = !1, this.invert(); else if (this.invertTimer) this.invertTimer += i; else { var n = this.distanceMeter.getActualDistance(Math.ceil(this.distanceRan)); n > 0 && (this.invertTrigger = !(n % this.config.INVERT_DISTANCE), this.invertTrigger && 0 === this.invertTimer && (this.invertTimer += i, this.invert())) } } this.crashed || (this.tRex.update(i), this.raq()) }, handleEvent: function (A) { return function (i, t) { switch (i) { case t.KEYDOWN: case t.TOUCHSTART: case t.MOUSEDOWN: this.onKeyDown(A); break; case t.KEYUP: case t.TOUCHEND: case t.MOUSEUP: this.onKeyUp(A) } }.bind(this)(A.type, t.events) }, startListening: function () { document.addEventListener(t.events.KEYDOWN, this), document.addEventListener(t.events.KEYUP, this), D ? (this.touchController.addEventListener(t.events.TOUCHSTART, this), this.touchController.addEventListener(t.events.TOUCHEND, this), this.containerEl.addEventListener(t.events.TOUCHSTART, this)) : (document.addEventListener(t.events.MOUSEDOWN, this), document.addEventListener(t.events.MOUSEUP, this)) }, stopListening: function () { document.removeEventListener(t.events.KEYDOWN, this), document.removeEventListener(t.events.KEYUP, this), D ? (this.touchController.removeEventListener(t.events.TOUCHSTART, this), this.touchController.removeEventListener(t.events.TOUCHEND, this), this.containerEl.removeEventListener(t.events.TOUCHSTART, this)) : (document.removeEventListener(t.events.MOUSEDOWN, this), document.removeEventListener(t.events.MOUSEUP, this)) }, onKeyDown: function (A) { D && A.preventDefault(), this.crashed || !t.keycodes.JUMP[A.keyCode] && A.type != t.events.TOUCHSTART || (this.activated || (this.loadSounds(), this.activated = !0), this.tRex.jumping || this.tRex.ducking || (this.playSound(this.soundFx.BUTTON_PRESS), this.tRex.startJump(this.currentSpeed))), this.crashed && A.type == t.events.TOUCHSTART && A.currentTarget == this.containerEl && this.restart(), this.activated && !this.crashed && t.keycodes.DUCK[A.keyCode] && (A.preventDefault(), this.tRex.jumping ? this.tRex.setSpeedDrop() : this.tRex.jumping || this.tRex.ducking || this.tRex.setDuck(!0)) }, onKeyUp: function (A) { var i = String(A.keyCode), s = t.keycodes.JUMP[i] || A.type == t.events.TOUCHEND || A.type == t.events.MOUSEDOWN; if (this.isRunning() && s) this.tRex.endJump(); else if (t.keycodes.DUCK[i]) this.tRex.speedDrop = !1, this.tRex.setDuck(!1); else if (this.crashed) { var e = h() - this.time; (t.keycodes.RESTART[i] || this.isLeftClickOnCanvas(A) || e >= this.config.GAMEOVER_CLEAR_TIME && t.keycodes.JUMP[i]) && this.restart() } else this.paused && s && (this.tRex.reset(), this.play()) }, isLeftClickOnCanvas: function (A) { return null != A.button && A.button < 2 && A.type == t.events.MOUSEUP && A.target == this.canvas }, raq: function () { this.drawPending || (this.drawPending = !0, this.raqId = requestAnimationFrame(this.update.bind(this))) }, isRunning: function () { return !!this.raqId }, gameOver: function () { this.playSound(this.soundFx.HIT), e(200), this.stop(), this.crashed = !0, this.distanceMeter.acheivement = !1, this.tRex.update(100, u.status.CRASHED), this.gameOverPanel ? this.gameOverPanel.draw() : this.gameOverPanel = new a(this.canvas, this.spriteDef.TEXT_SPRITE, this.spriteDef.RESTART, this.dimensions), this.distanceRan > this.highestScore && (this.highestScore = Math.ceil(this.distanceRan), this.distanceMeter.setHighScore(this.highestScore)), this.time = h() }, stop: function () { this.activated = !1, this.paused = !0, cancelAnimationFrame(this.raqId), this.raqId = 0 }, play: function () { this.crashed || (this.activated = !0, this.paused = !1, this.tRex.update(0, u.status.RUNNING), this.time = h(), this.update()) }, restart: function () { this.raqId || (this.playCount++, this.runningTime = 0, this.activated = !0, this.crashed = !1, this.distanceRan = 0, this.setSpeed(this.config.SPEED), this.time = h(), this.containerEl.classList.remove(t.classes.CRASHED), this.clearCanvas(), this.distanceMeter.reset(this.highestScore), this.horizon.reset(), this.tRex.reset(), this.playSound(this.soundFx.BUTTON_PRESS), this.invert(!0), this.update()) }, onVisibilityChange: function (A) { document.hidden || document.webkitHidden || "blur" == A.type || "visible" != document.visibilityState ? this.stop() : this.crashed || (this.tRex.reset(), this.play()) }, playSound: function (A) { if (A) { var i = this.audioContext.createBufferSource(); i.buffer = A, i.connect(this.audioContext.destination), i.start(0) } }, invert: function (A) { A ? (document.body.classList.toggle(t.classes.INVERTED, !1), this.invertTimer = 0, this.inverted = !1) : this.inverted = document.body.classList.toggle(t.classes.INVERTED, this.invertTrigger) } }, t.updateCanvasScaling = function (A, i, t) { var s = A.getContext("2d"), e = Math.floor(window.devicePixelRatio) || 1, n = Math.floor(s.webkitBackingStorePixelRatio) || 1, o = e / n; if (e !== n) { var h = i || A.width, a = t || A.height; return A.width = h * o, A.height = a * o, A.style.width = h + "px", A.style.height = a + "px", s.scale(o, o), !0 } return 1 == e && (A.style.width = A.width + "px", A.style.height = A.height + "px"), !1 }, a.dimensions = { TEXT_X: 0, TEXT_Y: 13, TEXT_WIDTH: 191, TEXT_HEIGHT: 11, RESTART_WIDTH: 36, RESTART_HEIGHT: 32 }, a.prototype = { updateDimensions: function (A, i) { this.canvasDimensions.WIDTH = A, i && (this.canvasDimensions.HEIGHT = i) }, draw: function () { var A = a.dimensions, i = this.canvasDimensions.WIDTH / 2, s = A.TEXT_X, e = A.TEXT_Y, n = A.TEXT_WIDTH, o = A.TEXT_HEIGHT, h = Math.round(i - A.TEXT_WIDTH / 2), r = Math.round((this.canvasDimensions.HEIGHT - 25) / 3), c = A.TEXT_WIDTH, g = A.TEXT_HEIGHT, d = A.RESTART_WIDTH, I = A.RESTART_HEIGHT, E = i - A.RESTART_WIDTH / 2, u = this.canvasDimensions.HEIGHT / 2; Q && (e *= 2, s *= 2, n *= 2, o *= 2, d *= 2, I *= 2), s += this.textImgPos.x, e += this.textImgPos.y, this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, h, r, c, g), this.canvasCtx.drawImage(t.imageSprite, this.restartImgPos.x, this.restartImgPos.y, d, I, E, u, A.RESTART_WIDTH, A.RESTART_HEIGHT) } }, E.MAX_GAP_COEFFICIENT = 1.5, E.MAX_OBSTACLE_LENGTH = 3, E.prototype = { init: function (A) { if (this.cloneCollisionBoxes(), this.size > 1 && this.typeConfig.multipleSpeed > A && (this.size = 1), this.width = this.typeConfig.width * this.size, Array.isArray(this.typeConfig.yPos)) { var i = D ? this.typeConfig.yPosMobile : this.typeConfig.yPos; this.yPos = i[s(0, i.length - 1)] } else this.yPos = this.typeConfig.yPos; this.draw(), this.size > 1 && (this.collisionBoxes[1].width = this.width - this.collisionBoxes[0].width - this.collisionBoxes[2].width, this.collisionBoxes[2].x = this.width - this.collisionBoxes[2].width), this.typeConfig.speedOffset && (this.speedOffset = Math.random() > .5 ? this.typeConfig.speedOffset : -this.typeConfig.speedOffset), this.gap = this.getGap(this.gapCoefficient, A) }, draw: function () { var A = this.typeConfig.width, i = this.typeConfig.height; Q && (A = 2 * A, i = 2 * i); var s = A * this.size * (.5 * (this.size - 1)) + this.spritePos.x; this.currentFrame > 0 && (s += A * this.currentFrame), this.canvasCtx.drawImage(t.imageSprite, s, this.spritePos.y, A * this.size, i, this.xPos, this.yPos, this.typeConfig.width * this.size, this.typeConfig.height) }, update: function (A, i) { this.remove || (this.typeConfig.speedOffset && (i += this.speedOffset), this.xPos -= Math.floor(i * V / 1e3 * A), this.typeConfig.numFrames && (this.timer += A, this.timer >= this.typeConfig.frameRate && (this.currentFrame = this.currentFrame == this.typeConfig.numFrames - 1 ? 0 : this.currentFrame + 1, this.timer = 0)), this.draw(), this.isVisible() || (this.remove = !0)) }, getGap: function (A, i) { var t = Math.round(this.width * i + this.typeConfig.minGap * A), e = Math.round(t * E.MAX_GAP_COEFFICIENT); return s(t, e) }, isVisible: function () { return this.xPos + this.width > 0 }, cloneCollisionBoxes: function () { for (var A = this.typeConfig.collisionBoxes, i = A.length - 1; i >= 0; i--) this.collisionBoxes[i] = new I(A[i].x, A[i].y, A[i].width, A[i].height) } }, E.types = [{ type: "CACTUS_SMALL", width: 17, height: 35, yPos: 105, multipleSpeed: 4, minGap: 120, minSpeed: 0, collisionBoxes: [new I(0, 7, 5, 27), new I(4, 0, 6, 34), new I(10, 4, 7, 14)] }, { type: "CACTUS_LARGE", width: 25, height: 50, yPos: 90, multipleSpeed: 7, minGap: 120, minSpeed: 0, collisionBoxes: [new I(0, 12, 7, 38), new I(8, 0, 7, 49), new I(13, 10, 10, 38)] }, { type: "PTERODACTYL", width: 46, height: 40, yPos: [100, 75, 50], yPosMobile: [100, 50], multipleSpeed: 999, minSpeed: 8.5, minGap: 150, collisionBoxes: [new I(15, 15, 16, 5), new I(18, 21, 24, 6), new I(2, 14, 4, 3), new I(6, 10, 4, 7), new I(10, 8, 6, 9)], numFrames: 2, frameRate: 1e3 / 6, speedOffset: .8 }], u.config = { DROP_VELOCITY: -5, GRAVITY: .6, HEIGHT: 47, HEIGHT_DUCK: 25, INIITAL_JUMP_VELOCITY: -10, INTRO_DURATION: 1500, MAX_JUMP_HEIGHT: 30, MIN_JUMP_HEIGHT: 30, SPEED_DROP_COEFFICIENT: 3, SPRITE_WIDTH: 262, START_X_POS: 50, WIDTH: 44, WIDTH_DUCK: 59 }, u.collisionBoxes = { DUCKING: [new I(1, 18, 55, 25)], RUNNING: [new I(22, 0, 17, 16), new I(1, 18, 30, 9), new I(10, 35, 14, 8), new I(1, 24, 29, 5), new I(5, 30, 21, 4), new I(9, 34, 15, 4)] }, u.status = { CRASHED: "CRASHED", DUCKING: "DUCKING", JUMPING: "JUMPING", RUNNING: "RUNNING", WAITING: "WAITING" }, u.BLINK_TIMING = 7e3, u.animFrames = { WAITING: {frames: [44, 0], msPerFrame: 1e3 / 3}, RUNNING: {frames: [88, 132], msPerFrame: 1e3 / 12}, CRASHED: {frames: [220], msPerFrame: 1e3 / 60}, JUMPING: {frames: [0], msPerFrame: 1e3 / 60}, DUCKING: {frames: [262, 321], msPerFrame: 125} }, u.prototype = { init: function () { this.blinkDelay = this.setBlinkDelay(), this.groundYPos = t.defaultDimensions.HEIGHT - this.config.HEIGHT - t.config.BOTTOM_PAD, this.yPos = this.groundYPos, this.minJumpHeight = this.groundYPos - this.config.MIN_JUMP_HEIGHT, this.draw(0, 0), this.update(0, u.status.WAITING) }, setJumpVelocity: function (A) { this.config.INIITAL_JUMP_VELOCITY = -A, this.config.DROP_VELOCITY = -A / 2 }, update: function (A, i) { this.timer += A, i && (this.status = i, this.currentFrame = 0, this.msPerFrame = u.animFrames[i].msPerFrame, this.currentAnimFrames = u.animFrames[i].frames, i == u.status.WAITING && (this.animStartTime = h(), this.setBlinkDelay())), this.playingIntro && this.xPos < this.config.START_X_POS && (this.xPos += Math.round(this.config.START_X_POS / this.config.INTRO_DURATION * A)), this.status == u.status.WAITING ? this.blink(h()) : this.draw(this.currentAnimFrames[this.currentFrame], 0), this.timer >= this.msPerFrame && (this.currentFrame = this.currentFrame == this.currentAnimFrames.length - 1 ? 0 : this.currentFrame + 1, this.timer = 0), this.speedDrop && this.yPos == this.groundYPos && (this.speedDrop = !1, this.setDuck(!0)) }, draw: function (A, i) { var s = A, e = i, n = this.ducking && this.status != u.status.CRASHED ? this.config.WIDTH_DUCK : this.config.WIDTH, o = this.config.HEIGHT; Q && (s *= 2, e *= 2, n *= 2, o *= 2), s += this.spritePos.x, e += this.spritePos.y, this.ducking && this.status != u.status.CRASHED ? this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, this.xPos, this.yPos, this.config.WIDTH_DUCK, this.config.HEIGHT) : (this.ducking && this.status == u.status.CRASHED && this.xPos++, this.canvasCtx.drawImage(t.imageSprite, s, e, n, o, this.xPos, this.yPos, this.config.WIDTH, this.config.HEIGHT)) }, setBlinkDelay: function () { this.blinkDelay = Math.ceil(Math.random() * u.BLINK_TIMING) }, blink: function (A) { var i = A - this.animStartTime; i >= this.blinkDelay && (this.draw(this.currentAnimFrames[this.currentFrame], 0), 1 == this.currentFrame && (this.setBlinkDelay(), this.animStartTime = A)) }, startJump: function (A) { this.jumping || (this.update(0, u.status.JUMPING), this.jumpVelocity = this.config.INIITAL_JUMP_VELOCITY - A / 10, this.jumping = !0, this.reachedMinHeight = !1, this.speedDrop = !1) }, endJump: function () { this.reachedMinHeight && this.jumpVelocity < this.config.DROP_VELOCITY && (this.jumpVelocity = this.config.DROP_VELOCITY) }, updateJump: function (A, i) { var t = u.animFrames[this.status].msPerFrame, s = A / t; this.speedDrop ? this.yPos += Math.round(this.jumpVelocity * this.config.SPEED_DROP_COEFFICIENT * s) : this.yPos += Math.round(this.jumpVelocity * s), this.jumpVelocity += this.config.GRAVITY * s, (this.yPos < this.minJumpHeight || this.speedDrop) && (this.reachedMinHeight = !0), (this.yPos < this.config.MAX_JUMP_HEIGHT || this.speedDrop) && this.endJump(), this.yPos > this.groundYPos && (this.reset(), this.jumpCount++), this.update(A) }, setSpeedDrop: function () { this.speedDrop = !0, this.jumpVelocity = 1 }, setDuck: function (A) { A && this.status != u.status.DUCKING ? (this.update(0, u.status.DUCKING), this.ducking = !0) : this.status == u.status.DUCKING && (this.update(0, u.status.RUNNING), this.ducking = !1) }, reset: function () { this.yPos = this.groundYPos, this.jumpVelocity = 0, this.jumping = !1, this.ducking = !1, this.update(0, u.status.RUNNING), this.midair = !1, this.speedDrop = !1, this.jumpCount = 0 } }, l.dimensions = { WIDTH: 10, HEIGHT: 13, DEST_WIDTH: 11 }, l.yPos = [0, 13, 27, 40, 53, 67, 80, 93, 107, 120], l.config = { MAX_DISTANCE_UNITS: 5, ACHIEVEMENT_DISTANCE: 100, COEFFICIENT: .025, FLASH_DURATION: 250, FLASH_ITERATIONS: 3 }, l.prototype = { init: function (A) { var i = ""; this.calcXPos(A), this.maxScore = this.maxScoreUnits; for (var t = 0; t < this.maxScoreUnits; t++) this.draw(t, 0), this.defaultString += "0", i += "9"; this.maxScore = parseInt(i) }, calcXPos: function (A) { this.x = A - l.dimensions.DEST_WIDTH * (this.maxScoreUnits + 1) }, draw: function (A, i, t) { var s = l.dimensions.WIDTH, e = l.dimensions.HEIGHT, n = l.dimensions.WIDTH * i, o = 0, h = A * l.dimensions.DEST_WIDTH, a = this.y, r = l.dimensions.WIDTH, c = l.dimensions.HEIGHT; if (Q && (s *= 2, e *= 2, n *= 2), n += this.spritePos.x, o += this.spritePos.y, this.canvasCtx.save(), t) { var g = this.x - 2 * this.maxScoreUnits * l.dimensions.WIDTH; this.canvasCtx.translate(g, this.y) } else this.canvasCtx.translate(this.x, this.y); this.canvasCtx.drawImage(this.image, n, o, s, e, h, a, r, c), this.canvasCtx.restore() }, getActualDistance: function (A) { return A ? Math.round(A * this.config.COEFFICIENT) : 0 }, update: function (A, i) { var t = !0, s = !1; if (this.acheivement) this.flashIterations <= this.config.FLASH_ITERATIONS ? (this.flashTimer += A, this.flashTimer < this.config.FLASH_DURATION ? t = !1 : this.flashTimer > 2 * this.config.FLASH_DURATION && (this.flashTimer = 0, this.flashIterations++)) : (this.acheivement = !1, this.flashIterations = 0, this.flashTimer = 0); else if (i = this.getActualDistance(i), i > this.maxScore && this.maxScoreUnits == this.config.MAX_DISTANCE_UNITS ? (this.maxScoreUnits++, this.maxScore = parseInt(this.maxScore + "9")) : this.distance = 0, i > 0) { i % this.config.ACHIEVEMENT_DISTANCE == 0 && (this.acheivement = !0, this.flashTimer = 0, s = !0); var e = (this.defaultString + i).substr(-this.maxScoreUnits); this.digits = e.split("") } else this.digits = this.defaultString.split(""); if (t) for (var n = this.digits.length - 1; n >= 0; n--) this.draw(n, parseInt(this.digits[n])); return this.drawHighScore(), s }, drawHighScore: function () { this.canvasCtx.save(), this.canvasCtx.globalAlpha = .8; for (var A = this.highScore.length - 1; A >= 0; A--) this.draw(A, parseInt(this.highScore[A], 10), !0); this.canvasCtx.restore() }, setHighScore: function (A) { A = this.getActualDistance(A); var i = (this.defaultString + A).substr(-this.maxScoreUnits); this.highScore = ["10", "11", ""].concat(i.split("")) }, reset: function () { this.update(0), this.acheivement = !1 } }, C.config = { HEIGHT: 14, MAX_CLOUD_GAP: 400, MAX_SKY_LEVEL: 30, MIN_CLOUD_GAP: 100, MIN_SKY_LEVEL: 71, WIDTH: 46 }, C.prototype = { init: function () { this.yPos = s(C.config.MAX_SKY_LEVEL, C.config.MIN_SKY_LEVEL), this.draw() }, draw: function () { this.canvasCtx.save(); var A = C.config.WIDTH, i = C.config.HEIGHT; Q && (A = 2 * A, i = 2 * i), this.canvasCtx.drawImage(t.imageSprite, this.spritePos.x, this.spritePos.y, A, i, this.xPos, this.yPos, C.config.WIDTH, C.config.HEIGHT), this.canvasCtx.restore() }, update: function (A) { this.remove || (this.xPos -= Math.ceil(A), this.draw(), this.isVisible() || (this.remove = !0)) }, isVisible: function () { return this.xPos + C.config.WIDTH > 0 } }, p.config = { FADE_SPEED: .035, HEIGHT: 40, MOON_SPEED: .25, NUM_STARS: 2, STAR_SIZE: 9, STAR_SPEED: .3, STAR_MAX_Y: 70, WIDTH: 20 }, p.phases = [140, 120, 100, 60, 40, 20, 0], p.prototype = { update: function (A, i) { if (A && 0 == this.opacity && (this.currentPhase++, this.currentPhase >= p.phases.length && (this.currentPhase = 0)), A && (this.opacity < 1 || 0 == this.opacity) ? this.opacity += p.config.FADE_SPEED : this.opacity > 0 && (this.opacity -= p.config.FADE_SPEED), this.opacity > 0) { if (this.xPos = this.updateXPos(this.xPos, p.config.MOON_SPEED), this.drawStars) for (var t = 0; t < p.config.NUM_STARS; t++) this.stars[t].x = this.updateXPos(this.stars[t].x, p.config.STAR_SPEED); this.draw() } else this.opacity = 0, this.placeStars(); this.drawStars = !0 }, updateXPos: function (A, i) { return A < -p.config.WIDTH ? A = this.containerWidth : A -= i, A }, draw: function () { var A = 3 == this.currentPhase ? 2 * p.config.WIDTH : p.config.WIDTH, i = p.config.HEIGHT, s = this.spritePos.x + p.phases[this.currentPhase], e = A, n = p.config.STAR_SIZE, o = t.spriteDefinition.LDPI.STAR.x; if (Q && (A *= 2, i *= 2, s = this.spritePos.x + 2 * p.phases[this.currentPhase], n *= 2, o = t.spriteDefinition.HDPI.STAR.x), this.canvasCtx.save(), this.canvasCtx.globalAlpha = this.opacity, this.drawStars) for (var h = 0; h < p.config.NUM_STARS; h++) this.canvasCtx.drawImage(t.imageSprite, o, this.stars[h].sourceY, n, n, Math.round(this.stars[h].x), this.stars[h].y, p.config.STAR_SIZE, p.config.STAR_SIZE); this.canvasCtx.drawImage(t.imageSprite, s, this.spritePos.y, A, i, Math.round(this.xPos), this.yPos, e, p.config.HEIGHT), this.canvasCtx.globalAlpha = 1, this.canvasCtx.restore() }, placeStars: function () { for (var A = Math.round(this.containerWidth / p.config.NUM_STARS), i = 0; i < p.config.NUM_STARS; i++) this.stars[i] = {}, this.stars[i].x = s(A * i, A * (i + 1)), this.stars[i].y = s(0, p.config.STAR_MAX_Y), Q ? this.stars[i].sourceY = t.spriteDefinition.HDPI.STAR.y + 2 * p.config.STAR_SIZE * i : this.stars[i].sourceY = t.spriteDefinition.LDPI.STAR.y + p.config.STAR_SIZE * i }, reset: function () { this.currentPhase = 0, this.opacity = 0, this.update(!1) } }, m.dimensions = {WIDTH: 600, HEIGHT: 12, YPOS: 127}, m.prototype = { setSourceDimensions: function () { for (var A in m.dimensions) Q ? "YPOS" != A && (this.sourceDimensions[A] = 2 * m.dimensions[A]) : this.sourceDimensions[A] = m.dimensions[A], this.dimensions[A] = m.dimensions[A]; this.xPos = [0, m.dimensions.WIDTH], this.yPos = m.dimensions.YPOS }, getRandomType: function () { return Math.random() > this.bumpThreshold ? this.dimensions.WIDTH : 0 }, draw: function () { this.canvasCtx.drawImage(t.imageSprite, this.sourceXPos[0], this.spritePos.y, this.sourceDimensions.WIDTH, this.sourceDimensions.HEIGHT, this.xPos[0], this.yPos, this.dimensions.WIDTH, this.dimensions.HEIGHT), this.canvasCtx.drawImage(t.imageSprite, this.sourceXPos[1], this.spritePos.y, this.sourceDimensions.WIDTH, this.sourceDimensions.HEIGHT, this.xPos[1], this.yPos, this.dimensions.WIDTH, this.dimensions.HEIGHT) }, updateXPos: function (A, i) { var t = A, s = 0 == A ? 1 : 0; this.xPos[t] -= i, this.xPos[s] = this.xPos[t] + this.dimensions.WIDTH, this.xPos[t] <= -this.dimensions.WIDTH && (this.xPos[t] += 2 * this.dimensions.WIDTH, this.xPos[s] = this.xPos[t] - this.dimensions.WIDTH, this.sourceXPos[t] = this.getRandomType() + this.spritePos.x) }, update: function (A, i) { var t = Math.floor(.06 * i * A); this.xPos[0] <= 0 ? this.updateXPos(0, t) : this.updateXPos(1, t), this.draw() }, reset: function () { this.xPos[0] = 0, this.xPos[1] = m.dimensions.WIDTH } }, f.config = { BG_CLOUD_SPEED: .2, BUMPY_THRESHOLD: .3, CLOUD_FREQUENCY: .5, HORIZON_HEIGHT: 16, MAX_CLOUDS: 6 }, f.prototype = { init: function () { this.addCloud(), this.horizonLine = new m(this.canvas, this.spritePos.HORIZON), this.nightMode = new p(this.canvas, this.spritePos.MOON, this.dimensions.WIDTH) }, update: function (A, i, t, s) { this.runningTime += A, this.horizonLine.update(A, i), this.nightMode.update(s), this.updateClouds(A, i), t && this.updateObstacles(A, i) }, updateClouds: function (A, i) { var t = this.cloudSpeed / 1e3 * A * i, s = this.clouds.length; if (s) { for (var e = s - 1; e >= 0; e--) this.clouds[e].update(t); var n = this.clouds[s - 1]; s < this.config.MAX_CLOUDS && this.dimensions.WIDTH - n.xPos > n.cloudGap && this.cloudFrequency > Math.random() && this.addCloud(), this.clouds = this.clouds.filter(function (A) { return !A.remove }) } else this.addCloud() }, updateObstacles: function (A, i) { for (var t = this.obstacles.slice(0), s = 0; s < this.obstacles.length; s++) { var e = this.obstacles[s]; e.update(A, i), e.remove && t.shift() } if (this.obstacles = t, this.obstacles.length > 0) { var n = this.obstacles[this.obstacles.length - 1]; n && !n.followingObstacleCreated && n.isVisible() && n.xPos + n.width + n.gap < this.dimensions.WIDTH && (this.addNewObstacle(i), n.followingObstacleCreated = !0) } else this.addNewObstacle(i) }, removeFirstObstacle: function () { this.obstacles.shift() }, addNewObstacle: function (A) { var i = s(0, E.types.length - 1), e = E.types[i]; if (this.duplicateObstacleCheck(e.type) || A < e.minSpeed) this.addNewObstacle(A); else { var n = this.spritePos[e.type]; this.obstacles.push(new E(this.canvasCtx, e, n, this.dimensions, this.gapCoefficient, A, e.width)), this.obstacleHistory.unshift(e.type), this.obstacleHistory.length > 1 && this.obstacleHistory.splice(t.config.MAX_OBSTACLE_DUPLICATION) } }, duplicateObstacleCheck: function (A) { for (var i = 0, s = 0; s < this.obstacleHistory.length; s++) i = this.obstacleHistory[s] == A ? i + 1 : 0; return i >= t.config.MAX_OBSTACLE_DUPLICATION }, reset: function () { this.obstacles = [], this.horizonLine.reset(), this.nightMode.reset() }, resize: function (A, i) { this.canvas.width = A, this.canvas.height = i }, addCloud: function () { this.clouds.push(new C(this.canvas, this.spritePos.CLOUD, this.dimensions.WIDTH)) } } }]) });一般网页使用方法很简单,如果在一般的网页中使用直接添加<div id="container"></div> <script src="runner.js"></script> <script> initRunner('#container'); </script>其中runner.js可以为任意地址,你可以把runner放在本地,也可以把runner放在OSS(阿里云对象储存)等储存。Typecho博客我们还可以将这段代码嵌入到博客里去,当然因为在这里图个方便,我直接使用iframe方法来引入,比较方便,我在这贴下我的方法<iframe align="center" width="100%" height="200px" src="https://tx.ddg.ink/dinogame/index.html" frameborder="no" border="0" scrolling="no" marginwidth="0" marginheight="0" ></iframe>很简单啊,就一句话就可以了,当然你也可以选择常规的方式去嵌入。我的方法是引入我OSS(阿里云对象储存)存放的html文件,所以要保证你的OSS(阿里云对象储存)和你的网站活的一样久。index.html的网页源码如下<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"> <title>Runner</title> </head> <body> <div id="test"></div> <script src="https://tx.ddg.ink/dinogame/runner.js"></script> <script> initRunner( '#test' ); </script> </body> </html>你可以自己存放在本地服务器去引用,js同理注意在typecho中的markdown语法!!!你的代码!!!这样是嵌入代码,记得是英文感叹号。不要直接复制我的代码使用,因为设置了Referer白名单防止盗链,直接使用是无效的。本方法支持手机,电脑,等设备玩耍。本文转自:XSY的FUN天地
2020年06月13日
1,229 阅读
0 评论
0 点赞
2020-06-11
Font Awesome 图标字体使用教程
Font Awesome Font Awesome 是为 Twitter Bootstrap 设计的图标字体,通过Web Font的方式来显示一些图标,好处是图标可以被任意缩放、改变颜色,你需要做的只是像修改文字样式那样修改图标样式,现在非常多的网站还有博客都是使用的这套图标。 基本使用1.在站点的在head处引入官方的font-awesome.min.css<link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"> 2.其他博客或者网站就在你的header头部引入就可以了 3.Handsome主题直接在:设置外观-开发者设置-自定义输出header头部的HTML代码 4.引入完成,就去这个图标库里去找你想要的图标 图标库 然后复制下来这串代码,然后就可以把这个 i 标签放在任何位置。 5.举个栗子 比如我要在我博客右侧的统计信息评论前面加上这个图标,就找到这个部分的源码,然后找合适的位置粘贴进去就行,当然也可以直接在现有的class里去添加,在现有的class添加就只用 “fa fa-grav” 就可以了,如果要替换现有的图标直接在现有的class修改 进阶使用下面是一些参数使用方法,如放大,翻转,动态等,使用的时候直接在基础用法的后面加参数,详情请看代码部分 1.图标放大,为了增加图标大小相对于它们的容器,使用fa-lg(33%递增) fa-2x, fa-3x,fa-4x或fa-5x类。 fa-lg fa-2x fa-3x fa-4x fa-5x<i class="fa fa-camera-retro fa-lg"></i> fa-lg <i class="fa fa-camera-retro fa-2x"></i> fa-2x <i class="fa fa-camera-retro fa-3x"></i> fa-3x <i class="fa fa-camera-retro fa-4x"></i> fa-4x <i class="fa fa-camera-retro fa-5x"></i> fa-5x 2.旋转并翻转,若要对图标进行任意旋转和旋转,可以使用fa-rotate和fa-flip-类 normal fa-rotate-90 fa-rotate-180 fa-rotate-270 fa-flip-horizontal fa-flip-vertical<i class="fa fa-shield"></i> normal<br> <i class="fa fa-shield fa-rotate-90"></i> fa-rotate-90<br> <i class="fa fa-shield fa-rotate-180"></i> fa-rotate-180<br> <i class="fa fa-shield fa-rotate-270"></i> fa-rotate-270<br> <i class="fa fa-shield fa-flip-horizontal"></i> fa-flip-horizontal<br> <i class="fa fa-shield fa-flip-vertical"></i> fa-flip-vertical 3.组合图标,如果想要将多个图标组合起来,使用fa-stack类,作为父容器,fa-stack-1x作为正常比例的图标,fa-stack-2x作为大一些的图标。还可以使用fa-inverse类来切换图标颜色,在父容器中通过添加更大的图标类来控制整体大小。fa-twitter on fa-square-o fa-flag on fa-circle fa-terminal on fa-square fa-ban on fa-camera<span class="fa-stack fa-lg"> <i class="fa fa-square-o fa-stack-2x"></i> <i class="fa fa-twitter fa-stack-1x"></i> </span>fa-twitter on fa-square-o<br> <span class="fa-stack fa-lg"> <i class="fa fa-circle fa-stack-2x"></i> <i class="fa fa-flag fa-stack-1x fa-inverse"></i> </span>fa-flag on fa-circle<br> <span class="fa-stack fa-lg"> <i class="fa fa-square fa-stack-2x"></i> <i class="fa fa-terminal fa-stack-1x fa-inverse"></i> </span>fa-terminal on fa-square<br> <span class="fa-stack fa-lg"> <i class="fa fa-camera fa-stack-1x"></i> <i class="fa fa-ban fa-stack-2x text-danger"></i> </span>fa-ban on fa-camera 4.动态图标,先引入一个css动画,引入方式和上面一样。使用这个CSS动画来实现动态图标,使用fa-spin使任意图标种植旋转,可以还使用fa-pulse使其进行方位旋转<link rel="stylesheet" href="https://itggg.bj.bcebos.com/cdn/font-awesome-animation.min.css"> 旋转类Loading...Loading...Loading...Loading...Loading...<i class="fa fa-spinner fa-spin fa-3x fa-fw"></i> <span class="sr-only">Loading...</span> <i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i> <span class="sr-only">Loading...</span> <i class="fa fa-refresh fa-spin fa-3x fa-fw"></i> <span class="sr-only">Loading...</span> <i class="fa fa-cog fa-spin fa-3x fa-fw"></i> <span class="sr-only">Loading...</span> <i class="fa fa-spinner fa-pulse fa-3x fa-fw"></i> <span class="sr-only">Loading...</span> 其他13种动画效果,序号请参照下方代码1. | 2. | 3. | 4. | 5. | 6. | 7.8. | 9. | 10.11. | 12. | 13.<i class="fa fa-wrench faa-wrench animated fa-3x"></i> <i class="fa fa-bell faa-ring animated fa-3x"></i> <i class="fa fa-envelope faa-horizontal animated fa-3x"></i> <i class="fa fa-thumbs-up faa-vertical animated fa-3x"></i> <i class="fa fa-exclamation-triangle faa-flash animated fa-3x"></i> <i class="fa fa-thumbs-up faa-bounce animated fa-3x"></i> <i class="fa fa-plane faa-float animated fa-3x"></i> <i class="fa fa-heart faa-pulse animated fa-3x"></i> <i class="fa fa-trophy faa-tada animated fa-3x"></i> <i class="fa fa-space-shuttle faa-passing animated fa-3x"></i> <i class="fa fa-space-shuttle faa-passing-reverse animated fa-3x"></i> <i class="fa fa-circle faa-burst animated fa-3x"></i> <i class="fa fa-star faa-falling animated fa-3x"></i> 鼠标点击动态,修改默认的动态参数 animated参数说明:animated 循环动态 animated-hover 鼠标移动到图标上动态 效果演示:移动鼠标到图标上 | <i class="fas fa-bell faa-ring animated-hover"></i> <i class="fas fa-spinner faa-spin animated-hover"></i> 怎么样?你学会了吗? 本文转自:Flat tire Blog
2020年06月11日
1,225 阅读
0 评论
0 点赞
2020-06-04
更换Typecho默认Gravatar头像源地址
介绍Gravatar是Globally Recognized Avatar的缩写,是gravatar推出的一项服务,意为“全球通用头像”。如果在Gravatar的服务器上放置了你自己的头像,那么在任何支持Gravatar的blog或者留言本上留言时,只要提供你与这个头像关联的email地址,就能够显示出你的Gravatar头像来。由于Typecho使用默认头像地址国内访问比较慢,我们可以替换带有cdn加速的地址来解决博客全球通用头像Gravatar不显示或显示缓慢的问题。修改方法方法1打开根目录/var/Typecho/Common.php文件搜索$url = $isSecure ? 'https://secure.gravatar.com' : 'http://www.gravatar.com';大约937行左右,将其和下面的$url .= '/avatar/';删除或注解掉在下面添加$url = $isSecure ? 'https://cdn.v2ex.com/gravatar/' : 'https://gravatar.loli.net/avatar/';添加完成应是如下代码: //$url = $isSecure ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'; //$url .= '/avatar/'; $url = $isSecure ? 'https://cdn.v2ex.com/gravatar/' : 'https://gravatar.loli.net/avatar/';方法2网站根目录下的config.inc.php文件,加入以下代码:/** 更换Gravatar头像源 */ define('__TYPECHO_GRAVATAR_PREFIX__', 'https://gravatar.loli.net/avatar/');以上两种选择其一即可!其他镜像源https://secure.gravatar.com/avatar/https://gravatar.loli.net/avatar/http://gravatar.ihuan.me/avatar/https://cdn.v2ex.com/gravatar/http://dn-qiniu-avatar.qbox.me/avatar/以上镜像源为博主收集,如果你有更好的镜像源欢迎推荐。
2020年06月04日
2,357 阅读
1 评论
1 点赞
2020-06-03
目前不错的国内外JavaScript库CDN加速服务
我们做网站博客等避免不了要用到JavaScript,有时候为了方便,会寻找JavaScript库的CDN的加速解决方案,又不想把JS放在本地,想白嫖。所以博主就推荐一些目前比较主流的国内外公共库CDN。国内又拍云JS加速库又拍云为您托管常用的JavaScript库,您可以在自己的网页上直接通过script标记引用这些资源。这样做不仅可以为您节省流量,还能通过我们的CDN加速,获得更快的访问速度。Staticfile CDN七牛云存储提供,我们的目标是提供这样一个仓库,让它尽可能全面收录优秀的开源库,并免费为之提供CDN加速服务,使之有更好的访问速度和稳定的环境。BootCDNBootstrap BootCDN中文网开源项目免费 CDN 加速服务 - 我们致力于为Bootstrap、jQuery、Angular、Vue.js 一样优秀的开源项目提供稳定、快速、免费的 CDN 加速服务。BootCDN是运营时间最长、用户量最大、最早同时支持HTTPS(SSL)和 HTTP/2.0 协议的中立免费 CDN 。75CDN360前端静态资源库是由奇舞团支持并维护的开源项目免费 CDN 服务,支持 HTTPS和 HTTP/2,囊括上千个前端资源库和 Google 字体库。字节跳动静态资源公共库跳动静态资源库支持多协议、资源动态拼接、快速检索及资源的动态更新,安全、稳定、实时。烧饼大佬的公益公共库常用前端公共库 & 和谐使用 Google 公共库、字体库的方法国外jsDelivrjsDelivr is a public open-source CDN(Content Delivery Network) where anyone can submit a project to behosted and delivered by our network.(有中国节点,还支持Github,强烈推荐!)CDNJSThe free and open source CDN for web relatedlibraries to speed up your website!暂时就介绍这些,如果有你更好的推荐,欢迎留言。
2020年06月03日
1,218 阅读
0 评论
0 点赞
2020-06-02
又拍云CDN/云存储配置图片教程
[scode type="yellow"]Handsome主题设置[/scode]个人收藏!图片转自:Bixan Blog
2020年06月02日
1,235 阅读
0 评论
0 点赞
1
2
3
4
5