首页
统计
赞助
留言
关于
更多
友链
壁纸
直播
Search
1
Joe — 一款个人类型Typecho主题
33,514 阅读
2
Joe开源目录程序系统
12,312 阅读
3
Typecho自定义后台编辑器功能
8,529 阅读
4
Joe主题实现自动更新
7,702 阅读
5
Joe主题自定义搭配色教程
4,576 阅读
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
登录
Search
https://78.al
累计撰写
76
篇文章
累计收到
3,785
条评论
首页
栏目
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
页面
统计
赞助
留言
关于
友链
壁纸
直播
搜索到
76
篇与
HaoOuBa
的结果
2021-02-20
原生JS实现一个验证码功能
定义一个用于显示验证码的canvas<canvas width="100" height="40"></canvas>生成JS的业务逻辑// 获取canvas let canvas = document.querySelector("canvas") let context = canvas.getContext("2d"); // 定义初始化验证码内容 let nums = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R','S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x','y', 'z']; drawCode() // 绘制验证码 function drawCode() { context.beginPath() /* 绘制背景色 */ context.fillStyle = "cornflowerblue"; context.fillRect(0, 0, canvas.width, canvas.height) /* 绘制验证码 */ context.fillStyle = "white"; context.font = "25px Arial"; let rand = [], x = [], y = [] for (let i = 0; i < 5; i++) { rand[i] = nums[Math.floor(Math.random() * nums.length)] x[i] = i * 16 + 10; y[i] = Math.random() * 20 + 20; context.fillText(rand[i], x[i], y[i]); } /* rand就是生成后的结果, 后面用来判断验证码输入框是否与该值相等 */ console.log(rand); //画3条随机线 for (let i = 0; i < 3; i++) { drawline(canvas, context); } // 画30个随机点 for (let i = 0; i < 30; i++) { drawDot(canvas, context); } } // 随机线 function drawline(canvas, context) { //随机线的起点x坐标是画布x坐标0位置,y坐标是画布高度的随机数 context.moveTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height)); //随机线的终点x坐标是画布宽度,y坐标是画布高度的随机数 context.lineTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height)); context.lineWidth = 0.5; context.strokeStyle = 'rgba(50,50,50,0.3)'; context.stroke(); } // 随机点 function drawDot(canvas, context) { let px = Math.floor(Math.random() * canvas.width); let py = Math.floor(Math.random() * canvas.height); context.moveTo(px, py); context.lineTo(px + 1, py + 1); context.lineWidth = 0.2; context.stroke(); }
2021年02月20日
679 阅读
6 评论
6 点赞
2021-02-20
Vue限制输入框内容只能输入金额或数字
<template> <input @input="formatValue(value)" v-model="value"> </template> <script> export default = { data(){ return { value: "" } }, methods:{ // 只允许输入数字,其他一律不允许输入 formatValue(val){ this.value = this.value.replace(/[^\d]/g, "") }, // 只允许输入金额类型,最大两位小数(如:3.88) formatValue(val){ val = val.replace(/(^\s*)|(\s*$)/g, ""); if (!val) return this.value = ""; val = val.replace(/[^\d.]/g, ""); val = val.replace(/^\./g, ""); val = val .replace(".", "$#$") .replace(/\./g, "") .replace("$#$", "."); val = val.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3"); this.value = val; }, } } </script>
2021年02月20日
704 阅读
5 评论
2 点赞
2021-02-20
Typecho开启Gzip压缩加速网站
Gzip简介GZip压缩,是一种网站速度优化技术,也是一把SEO优化利器,许多网站都采用了这种技术,以达到提升网页打开速度、缩短网页打开时间的目的。网站采用Gzip压缩,还有一个好处,就是让你少了一份流量超标的担心。因为Gzip开启以后会将输出到用户浏览器的数据进行压缩的处理,这样就会减小通过网络传输的数据量,而这个,也正是提升网页打开时间的原因所在。首先看未开启的效果(本主题为例)从上图可以看到,这个api接口的大小是21kb,请求时间539ms接着开启gzip压缩很明显的可以看到区别,压缩后只有4.5kb大小,并且时间缩短到了99ms,极大的优化了网站速度开启方法打开typecho目录下的 index.php,并在开头添加 ob_start('ob_gzhandler'); 即可。
2021年02月20日
2,529 阅读
11 评论
31 点赞
2021-02-20
Joe主题实现自动更新
Joe主题更新到5.0.0版本后,因为属于重构版本,所以很多功能没有加上,需要频繁更新,但是每次更新都需要下载,然后删除老版本,在上传新版本,今天群里有个人分享的自动更新教程写的很好,于是我把补充的详细点{mtitle title="START"/}第一步,克隆主题1、首先进入博客的 themes 文件夹下2、点击 终端 按钮,出现一个黑色的窗口3、 在这个窗口内输入以下指令并回车git clone https://github.com/HaoOuBa/Joe.git出现下图的样子,表示成功4、刷新当前页面,会发现多出一个叫 Joe 的目录第二步,设置自动更新主题1、进入宝塔 计划任务 页面2、任务类型选择 Shell 脚本3、任务名称,可以随便写一个,例如我写的是:Joe主题更新4、执行周期,就是多久更新一次,这个可以随便写,例如我设置的是每30分钟检测一次更新5、脚本内容,填写如下,注意需要将网站目录替换成你的#!/bin/sh cd /www/wwwroot/网站目录/usr/themes/Joe git pull完整的设置内容如下第四步,判断是否正常1、上面步骤都完成后,点击这里的 执行2、然后点击 执行 右侧的 日志 按钮,如果内容显示如下,则代表没有任何问题{mtitle title="END"/}
2021年02月20日
7,702 阅读
62 评论
66 点赞
2021-02-18
苹果cms设置允许跨域
打开苹果cms站点,找到如下位置:application/api/controller/Provide.php在对应的位置填写如下内容:允许部分域名使用$origin = isset($_SERVER['HTTP_ORIGIN'])? $_SERVER['HTTP_ORIGIN'] : ''; // 允许跨域的域名写在数组里, $allow_origin = array('http://xxx.com','http://xxx.cn' ); if(in_array($origin, $allow_origin)){ header('Access-Control-Allow-Origin:'.$origin); }允许全部人使用header('Access-Control-Allow-Origin:*');
2021年02月18日
2,512 阅读
9 评论
18 点赞
2021-02-13
JS通过解构或Object.assign去合并2个对象
在封装插件的时候,经常会碰到传入参数和默认参数的问题,如果调用者没有传递参数,那么使用插件的内置属性,如果传递了,那么就设置成传递的参数,例如:这是一个弹窗插件class Dialog { constructor(options = {}) { // 插件的默认配置 const defaultOption = { title: "提示", size: "small", show: false } for (let key in options) { defaultOption[key] = options[key] } } } new Dialog({ title: '标题', size: 'mini' })传统的会使用上面的for循环,然后将默认参数里的参数替换掉,在ES6出来后,上面的写法就可以改成下面的简写第一种方式class Dialog { constructor(options = {}) { // 插件的默认配置 const defaultOption = { title: "提示", size: "small", show: false, // 通过展开运算符 ...options } } }第二种方式class Dialog { constructor(options = {}) { // 插件的默认配置 const defaultOption = { title: "提示", size: "small", show: false } // 通过Object.assign方法 const newOption = Object.assign(defaultOption, options) } }
2021年02月13日
449 阅读
0 评论
6 点赞
JoeQQ小程序上线及使用教程文档
2021年02月13日
2,714 阅读
99 评论
31 点赞
2021-02-13
必备条件,缺一不可!备案的域名(个人/企业备案都行。没有的话,找别人借一个二级域名也行)域名https(已经0202年了,还不会https的自己解决)使用本站Joe 4.7.6之前版本主题(如果不是,有问题概不处理及解决!因为小程序图片功能引用Joe 4.7.6之前版本主题)QQ群:457337579安装插件1、首先进群文件下载Joe小程序专用插件(Typecho-Joe-Theme插件文件夹里面)2、下载后解压并上传到Typecho站点的 usr/plugins 目录里3、进入 博客后台 并启用 JoePrograme 插件4、点击 JoePrograme 插件右侧的 设置 按钮5、填写 接口Token (随意填写,不是中文就行,后面会用到)6、关闭 是否开启页面评论列表 选项,此项务必要关闭!!!否则小程序审核时无法通过!!!7、保存,接着就没插件什么事了小程序网页端配置1、皆坐!好好看,好好学,不会操作的一步一步跟着来2、打开QQ小程序官网,并注册(有账号的直接登录)3、找到 开发设置 页面,相信不是瞎子都能找到4、依次生成下方3个5、接着填写服务器域名,域名必须 备案 !并且能够访问到你的博客!6、找到 基本设置 页面,相信不是瞎子都能找到7、从第一个依次填写到最后一个,服务类目、标签、基础库可参考下图进行填写5、以上事情做完了?接着看下面的小程序端配置小程序客户端配置1、皆坐!好好看,好好学,不会操作的一步一步跟着来2、群文件下载 JoeQQ小程序源码(Typecho-Joe-Theme QQ小程序 文件夹里)3、解压下载的小程序源码到电脑任意文件夹,别解压了你自己都找不到4、下载并安装 QQ小程序开发者工具,点击前往下载 (开发者工具Stable版)5、打开 QQ小程序开发者工具6、选择 新建项目,项目目录选择上方 第3步解压的目录,AppID输入 小程序网页端配置 教程里 第4步 里生成的AppID,项目名称瞎鸡儿写7、打开 编辑器 选项卡,打开 joe.config.js,修改里面的配置,token填写的是 安装插件 步骤里 第5步 填写的token8、修改后,看左侧的小程序预览 是否有问题,如果不显示,控制台报错等,检查你的配置9、无问题,则点击 上传 按钮,填写的内容如下,版本号填写 1.0.0,备注就看自己怎么写了10、上传完成后,即可 关闭这个开发者工具,进入下面的一个步骤提交发布,等待审核隐藏内容,请前往内页查看详情
2021-02-13
JoeQQ小程序页面专用
本页面为Joe小程序演示专用一级标题上面是一级标题的样式二级标题上面是二级标题的样式三级标题上面是三级标题的样式四级标题上面是四级标题的样式五级标题上面是五级标题的样式六级标题上面是六级标题的样式段落:《南国三部曲》产生于二十世纪九十年代。当时,作者曾从省机关贬官到郊外,以其亲身经历创作了这部《南国三部曲》作品。《南国三部曲》是以反腐败为主题,描述了在党的领导下,广大工人、农民、学生与腐败分子进行斗争曲折、复杂、惊险故事。歌颂了广大劳动人民群众,捍卫国家与人民财产,坚持走社会主义集体化道路,追求共产主义信仰的献身精神。加粗:我们使用 右手 进行吃饭。斜体:哎呀!我 歪倒 了!!!斜体加粗:你看!那个 女孩子 正在跳舞!删除线:这个内容是错误的,已经废弃引用:欢迎来到德莱联盟图片:无序列表:苹果橘子香蕉有序列表猴子猫子狗子表格:表头表头表头内容内容内容内容内容内容行内代码:我们在前端开发的时候,经常用到 div 标签代码块:let a = 1; let b = 2; console.log(a + b); // 3
2021年02月13日
1,632 阅读
6 评论
29 点赞
2021-02-09
Joe开源目录程序系统
首先直接看效果演示前台页面预览地址:{anote icon="fa-unlink" href="https://hefollo.com" type="success" content="https://hefollo.com"/}后台上传预览地址:{anote icon="fa-unlink" href="http://files.js.cn/admin" type="info" content="files.js.cn/admin"/}程序介绍1、前台目录程序采用 files.photo.gallery2、后台上传为开源Joe上传,支持粘贴上传、点击上传、拖拽上传、上传成功失败进度条等3、默认上传密码(在文件里可以看到,以及限制上传的文件格式)源码下载隐藏内容,请前往内页查看详情注意事项1、PHP扩展安装:GD、mbstring、fileinfo、exif(不开启部分图片读取不到!!!!)(宝塔默认已安装GD、mbstring扩展)2、请务必保证根目录有 _uploads 文件夹,否则可能会报错!3、如何修改上传密码、允许上传的类型?{message type="info" content="打开 admin/index.php 文件,开头就可以看见"/}
2021年02月09日
12,312 阅读
1001 评论
158 点赞
Typecho自定义后台编辑器功能
首先看下效果图{message type="info" content="上面的增加按钮很简单,append一个li标签就可以实现,主要是在于向文本框中插入内容,以及输入键盘按键也能实现插入对应的功能。在网上百度了一番,都是互相抄袭,而且也不封装一下,有bug都没人解决,很无奈自己折腾了一个"/}使用方法{message type="warning" content="首先在你的主题 functions.php 里增加一个插件函数,这个函数的用途是在编辑文章和编辑页面里面引入自定义JS"/}Typecho_Plugin::factory('admin/write-post.php')->bottom = array('Editor', 'edit'); Typecho_Plugin::factory('admin/write-page.php')->bottom = array('Editor', 'edit'); class Editor { public static function edit() { echo "<script src='" . Helper::options()->themeUrl . '/typecho/editor/joe.extend.js' . "'></script>"; echo "<script src='" . Helper::options()->themeUrl . '/typecho/editor/joe.editor.js' . "'></script>"; } }下面的 joe.extend.js 没压缩也没加密,下面是 joe.extend.js 源码(function ($) { $.fn.extend({ /* 按键盘实现插入内容 */ shortcuts: function () { this.keydown(function (e) { var _this = $(this); e.stopPropagation(); if (e.altKey) { switch (e.keyCode) { case 67: _this.insertContent('[code]' + _this.selectionRange() + '[/code]'); break; } } }); }, /* 插入内容 */ insertContent: function (myValue, t) { var $t = $(this)[0]; if (document.selection) { this.focus(); var sel = document.selection.createRange(); sel.text = myValue; this.focus(); sel.moveStart('character', -l); var wee = sel.text.length; if (arguments.length == 2) { var l = $t.value.length; sel.moveEnd('character', wee + t); t <= 0 ? sel.moveStart('character', wee - 2 * t - myValue.length) : sel.moveStart('character', wee - t - myValue.length); sel.select(); } } else if ($t.selectionStart || $t.selectionStart == '0') { var startPos = $t.selectionStart; var endPos = $t.selectionEnd; var scrollTop = $t.scrollTop; $t.value = $t.value.substring(0, startPos) + myValue + $t.value.substring(endPos, $t.value.length); this.focus(); $t.selectionStart = startPos + myValue.length; $t.selectionEnd = startPos + myValue.length; $t.scrollTop = scrollTop; if (arguments.length == 2) { $t.setSelectionRange(startPos - t, $t.selectionEnd + t); this.focus(); } } else { this.value += myValue; this.focus(); } }, /* 选择 */ selectionRange: function (start, end) { var str = ''; var thisSrc = this[0]; if (start === undefined) { if (/input|textarea/i.test(thisSrc.tagName) && /firefox/i.test(navigator.userAgent)) str = thisSrc.value.substring(thisSrc.selectionStart, thisSrc.selectionEnd); else if (document.selection) str = document.selection.createRange().text; else str = document.getSelection().toString(); } else { if (!/input|textarea/.test(thisSrc.tagName.toLowerCase())) return false; end === undefined && (end = start); if (thisSrc.setSelectionRange) { thisSrc.setSelectionRange(start, end); this.focus(); } else { var range = thisSrc.createTextRange(); range.move('character', start); range.moveEnd('character', end - start); range.select(); } } if (start === undefined) return str; else return this; } }); })(jQuery);上面的shortcuts方法主要用于实现按下键盘插入内容接着看 joe.edit.js的内容/* 增加自定义功能 */ const items = [ { title: '回复可见', id: 'wmd-hide-button', svg: '<svg t="1612402690962" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15751" width="20" height="20"><path d="M554.666667 438.101333V277.333333h-85.333334v160.768L330.112 357.717333l-42.666667 73.898667L426.666667 512l-139.221334 80.384 42.666667 73.898667L469.333333 585.898667V746.666667h85.333334v-160.768l139.221333 80.384 42.666667-73.898667L597.333333 512l139.221334-80.384-42.666667-73.898667L554.666667 438.101333z" p-id="15752" fill="#9b9b9b"></path></svg>', text: '\n[@hide]这里的内容回复后才能看见[/hide]\n' } ]; items.forEach(_ => { let item = $(`<li class="wmd-button" id="${_.id}" title="${_.title}">${_.svg}</li>`); item.on('click', function () { $('#text').insertContent(_.text); }); $('#wmd-button-row').append(item); });
2021年02月08日
8,529 阅读
73 评论
104 点赞
2021-02-08
Typecho实现评论显示操作系统和评论来源
{message type="info" content="首先打开 functions.php 文件,粘贴下面的代码" /}// 获取浏览器信息 function getBrowser($agent) { if (preg_match('/MSIE\s([^\s|;]+)/i', $agent, $regs)) { $outputer = 'Internet Explore'; } else if (preg_match('/FireFox\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('Firefox/', $regs[0]); $FireFox_vern = explode('.', $str1[1]); $outputer = 'FireFox'; } else if (preg_match('/Maxthon([\d]*)\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('Maxthon/', $agent); $Maxthon_vern = explode('.', $str1[1]); $outputer = 'MicroSoft Edge'; } else if (preg_match('#360([a-zA-Z0-9.]+)#i', $agent, $regs)) { $outputer = '360 Fast Browser'; } else if (preg_match('/Edge([\d]*)\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('Edge/', $regs[0]); $Edge_vern = explode('.', $str1[1]); $outputer = 'MicroSoft Edge'; } else if (preg_match('/UC/i', $agent)) { $str1 = explode('rowser/', $agent); $UCBrowser_vern = explode('.', $str1[1]); $outputer = 'UC Browser'; } else if (preg_match('/QQ/i', $agent, $regs)||preg_match('/QQ Browser\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('rowser/', $agent); $QQ_vern = explode('.', $str1[1]); $outputer = 'QQ Browser'; } else if (preg_match('/UBrowser/i', $agent, $regs)) { $str1 = explode('rowser/', $agent); $UCBrowser_vern = explode('.', $str1[1]); $outputer = 'UC Browser'; } else if (preg_match('/Opera[\s|\/]([^\s]+)/i', $agent, $regs)) { $outputer = 'Opera'; } else if (preg_match('/Chrome([\d]*)\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('Chrome/', $agent); $chrome_vern = explode('.', $str1[1]); $outputer = 'Google Chrome'; } else if (preg_match('/safari\/([^\s]+)/i', $agent, $regs)) { $str1 = explode('Version/', $agent); $safari_vern = explode('.', $str1[1]); $outputer = 'Safari'; } else{ $outputer = 'Google Chrome'; } echo $outputer; } // 获取操作系统信息 function getOs($agent) { $os = false; if (preg_match('/win/i', $agent)) { if (preg_match('/nt 6.0/i', $agent)) { $os = 'Windows Vista · '; } else if (preg_match('/nt 6.1/i', $agent)) { $os = 'Windows 7 · '; } else if (preg_match('/nt 6.2/i', $agent)) { $os = 'Windows 8 · '; } else if(preg_match('/nt 6.3/i', $agent)) { $os = 'Windows 8.1 · '; } else if(preg_match('/nt 5.1/i', $agent)) { $os = 'Windows XP · '; } else if (preg_match('/nt 10.0/i', $agent)) { $os = 'Windows 10 · '; } else{ $os = 'Windows X64 · '; } } else if (preg_match('/android/i', $agent)) { if (preg_match('/android 9/i', $agent)) { $os = 'Android Pie · '; } else if (preg_match('/android 8/i', $agent)) { $os = 'Android Oreo · '; } else { $os = 'Android · '; } } else if (preg_match('/ubuntu/i', $agent)) { $os = 'Ubuntu · '; } else if (preg_match('/linux/i', $agent)) { $os = 'Linux · '; } else if (preg_match('/iPhone/i', $agent)) { $os = 'iPhone · '; } else if (preg_match('/mac/i', $agent)) { $os = 'MacOS · '; }else if (preg_match('/fusion/i', $agent)) { $os = 'Android · '; } else { $os = 'Linux · '; } echo $os; }{message type="warning" content="comments.php 中找到合适位置(比如评论作者的后面)添加以下代码" /}<?php getOs($comments->agent); ?><?php getBrowser($comments->agent); ?>
2021年02月08日
3,076 阅读
23 评论
44 点赞
2021-02-08
Vue面包屑导航实现方案
例如想实现一个 首页 / 项目列表 / 我的项目 这样的面包屑1、首先在路由js文件里写上面包屑对应的名称router.jsexport default [ { path: "/", children: [ { path: "/todoList", component: TodoList, name: "todoList" meta: { breadName: "项目列表" } }, { path: "/todoList/mylist", component: MyList, name: "mylist" meta: { breadName: "我的项目" } }, ] } ]2、编写面包屑组件<template> <a-breadcrumb class="breadcrumb"> <a-breadcrumb-item v-for="(breadcrumb, index) in breadcrumbList" :key="index"> {{breadcrumb.meta.breadName}} </a-breadcrumb-item> </a-breadcrumb> </template> <script> export default { computed: { breadcrumbList () { // 先定义一个变量 用于存放计算出来的导航数组 let breadArr = [] // 获取当前页面的路由, 并将路由字符串截取第一个/, 然后组成数组 let path = this.$route.path.substr(1).split("/") // >>> ["todoList", mylist] // 获取所有页面的路由地址,通过this.$router.options拿到, 具体样子可以打印看看 const allRouter = this.$router.options.routes[0].children // 然后循环allRouter找到里面中符合的path的2个,将他们存起来 allRouter.forEach(_ => { // 判断path的每一项是否有allRouter里的某项 if (path.some(_item => _item === _.name)) { breadArr.push(_) } }) console.log(breadArr) // 打印下看看数据是否正确, 如果为两项, 并且每项里面都有meta内容, 则正确 // 因为这个数组里是没有 首页 这一项的, 我们自己手动添加一个就好, 此时用到unshift breadArr.unshift({ path: "/", meta: { breadName: "首页" } }) // 最后computed 需要return出去, return出去这个数组就好了 return breadArr } } } </script>
2021年02月08日
548 阅读
0 评论
7 点赞
1
...
5
6
7