js拦截页面跳转并获取目标地址

  1. navigation.onnavigate = function () {
  2. // 这里可以获取到最终跳转到的url
  3. var url = arguments[0].destination.url;
  4. console.log('url: ', url);
  5. return window.event.returnValue = false;
  6. }

关于Chrome跨域The request client is not a secure context and the resource is in more-private address space loca相关提示的解决

最近想使用serve 配置一个本地的 chrome 脚本注入功能, 没想到浏览器提示:

Access to script at ‘http://localhost:85/index.js‘ from origin ‘http://www.xxx.com‘ has been blocked by CORS policy: The request client is not a secure context and the resource is in more-private address space local.

貌似是chrome有设置, 在地址栏中输入:
chrome://flags/#block-insecure-private-network-requests

然后选Disabled ,relaunch 后就能恢复正常了, 根据翻译:

block-insecure-private-network-requests
防止非安全上下文向更私密的IP地址发出子资源请求。如果1)IP1是本地主机,而IP2不是,或者2)IP1是私有的,而IP2是公共的,则IP地址IP1比IP2更私有。这是全面实施CORS-RFC1918的第一步:https://wicg.github.io/cors-rfc1918–Mac、Windows、Linux、Chrome OS、Android、Fuchsia
阻止不安全的专用网络请求

应该是处于安全考虑, 禁止向私有地址请求和发生数据

直播服务器搭建方法

直播服务器搭建流程

  1. 服务器上安装node-media-server
  2. 本地安装ffmpeg
  3. 测试推流
  4. 浏览器查看直播内容

1. 安装node-media-server

  1. ## 在服务器上启动node-media-server 服务
  2. docker run --name nms -d -p 1935:1935 -p 8000:8000 -p 8443:8443 illuspas/node-media-server

2. 本地安装 ffmpeg

  1. 下载解压对应版本的ffmpeg到本地: https://github.com/BtbN/FFmpeg-Builds/releases
  2. 添加环境变量

3. 测试推流

  1. ## 在本地找到视频文件目录, 执行推流命令
  2. ffmpeg -re -i hello.mp4 -c copy -f flv rtmp://localhost/live/hello

4. 浏览器查看直播

使用NodePlayer.js 播放直播内容: https://github.com/illuspas/NodePlayer.js

  1. <canvas id="video" width="640" height="480" data-url="ws://localhost:8000/live/hello"></canvas>
  2. <input type="button" onclick="play()" value="play">
  3. <script src="NodePlayer.js"></script>
  4. <script>
  5. function play() {
  6. var url = document.getElementById("video").dataset.url;
  7. var np = new Module.NodePlayer();
  8. np.setPlayView('video');
  9. np.setScaleMode(1);
  10. np.on('start', () => {
  11. Module.print('NodePlayer on start');
  12. });
  13. np.on('close', () => {
  14. Module.print('NodePlayer on close');
  15. });
  16. np.on('error', (err) => {
  17. Module.print('NodePlayer on error', err);
  18. });
  19. // np.enableVideo(true);
  20. // np.enableAudio(true);
  21. np.start(url);
  22. }
  23. </script>

相关下载

  1. node-media-server: https://github.com/illuspas/Node-Media-Server
  2. ffmpeg: https://github.com/BtbN/FFmpeg-Builds/releases
  3. NodePlayer: https://github.com/illuspas/NodePlayer.js

Espruino单片机上的javascript

  话说一直想用javascript语法写单片机程序, 因为我本身是web开发出身, 太熟悉js语法了, 以至于看到c 或 python都感觉很别扭, 于是就在网上找到了这个espruino, espruino是一个固件, 可以让esp8266等芯片支持使用js语法编程, 大大减少了web人员学习单片机开发的成本, 甚至可以让本身会js的人直接上手, 了解基础api后, 就可以直接开发自己的单片机项目了, 这里是官网: https://www.espruino.com/ , Espruino文档: http://www.espruino.com/Reference#software

  但是, 官网提供的开发工具用着很不习惯, 而且代码都在一个文件中, 很不方便管理.

  于是我就自己根据espruino的aip, 自己写了个命令行工具, 可以使用自己熟练的ide, 然后配合命令行工具进行开发, 执行的时候就像nodejs一样方便, 目前这个命令行工具叫espjs, 文档地址: https://www.kancloud.cn/shuai/espjs

espjs开源地址 github: https://github.com/zhaishuaigan/espjs
espjs国内下载: https://fetch.ngapp.net/soft/espjs/espjs-latest.zip

  这里简单说明一下使用方法:

  1. 将此压缩包里面的文件放到不包含空格和中文的目录中. 如 c:\espruino-tools
  2. 配置系统环境变量path, 添加 c:\espruino-tools
  3. 进入项目目录, 在目录的地址栏输入 cmd, 进入命令行.
  4. 输入espjs flash esp01s 烧写espruino固件
  5. 输入espjs upload 上传当前目录中的代码到设备

然后设备就开始运行代码了, 之后修改代码只需要执行upload 即可更新代码,
实例可参考 demo 目录下的文件
index.js 或 main.js 会被当做入口文件加载执行

注意事项:
1: 端口是自动选择的, 插上设备后会自动选择, 如果有多个设备, 可以使用port命令切换设备
2: 默认的波特率是115200, 如需修改请到config.json中修改
3: 如果要增加开发板支持, 请到config.json 的Flash字段追加
4: 模块不支持远程加载, 例如 require(“MQTT”) 会提示模块不存在, 解决方法是 手动下载mqtt模块(modules add MQTT), 然后使用 require(“modules/MQTT.min.js”) 进行引用.

小程序客服消息处理

三种消息类型:

  1. // 文本消息
  2. {
  3. "signature": "ee6e400de7972484ec6f3014c2f77504925a4707",
  4. "timestamp": "1552298008",
  5. "nonce": "540004383",
  6. "openid": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  7. "encrypt_type": "aes",
  8. "msg_signature": "74c419155e49cefab8ab1dbd440b9389acc47e2a",
  9. "URL": "http:\/\/qiang.lt.ngapp.net\/wechat\/noti/fy",
  10. "ToUserName": "zhaishuaigan",
  11. "FromUserName": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  12. "CreateTime": 1552293166,
  13. "MsgType": "text",
  14. "Content": "hello",
  15. "MsgId": 1,
  16. "Encrypt": "PloOW0ucj9SkMpMC...."
  17. }
  18. // 事件消息
  19. {
  20. "signature": "3e5860da822266b9f03f8d5380615f9be0ae2db7",
  21. "timestamp": "1552301914",
  22. "nonce": "693467019",
  23. "openid": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  24. "encrypt_type": "aes",
  25. "msg_signature": "eda0cdd567b35df4501ee2041e0d191db81798f2",
  26. "ToUserName": "gh_cc23a0a84984",
  27. "FromUserName": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  28. "CreateTime": 1552301914,
  29. "MsgType": "event",
  30. "Event": "user_enter_tempsession",
  31. "SessionFrom": "open-type='contact'",
  32. "Encrypt": "oMP\/xo2RdcbK07vvoxxxx....."
  33. }
  34. // 图片消息
  35. {
  36. "signature": "ebd79f0c44f01dc26ef83ffeeadbdb3af5b960da",
  37. "timestamp": "1552302190",
  38. "nonce": "1322948029",
  39. "openid": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  40. "encrypt_type": "aes",
  41. "msg_signature": "06613ca44e189d95140166898f80a27ab10baa80",
  42. "ToUserName": "gh_cc23a0a84984",
  43. "FromUserName": "oPzrj5EAP25lzOVW6qa0m8MUlLXA",
  44. "CreateTime": 1552302190,
  45. "MsgType": "image",
  46. "PicUrl": "http:\/\/mmbiz.qpic.cn\/mmbiz_jpg\/WwPGxFUiaTRZ6zVvTTGVbhfa9Vic801ux7OHobAAiaD3xRMYeJzbic4ISvwn736dpK0OMTlaYvX7GoTRgE8LqObkIQ\/0",
  47. "MsgId": 22223624286040849,
  48. "MediaId": "3WiHLigPtkJtqoLvPD2HgPsAtb3vzDvTWyo0sP5s-dshtS7oZOlCW7c3RuD1nwBt",
  49. "Encrypt": "gictSCCy+Zxxxx...."
  50. }

ThinkPHP 5.1保存消息代码

  1. $request = request()->param();
  2. $data = [
  3. 'signature' => $request['signature'],
  4. 'timestamp' => $request['timestamp'],
  5. 'nonce' => $request['nonce'],
  6. 'openid' => $request['openid'],
  7. 'encrypt_type' => $request['encrypt_type'],
  8. 'msg_signature' => $request['msg_signature'],
  9. 'to_username' => $request['ToUserName'],
  10. 'from_username' => $request['FromUserName'],
  11. 'msg_type' => $request['MsgType'],
  12. 'msg_id' => isset($request['MsgId']) ? $request['MsgId'] : '',
  13. 'encrypt' => isset($request['Encrypt']) ? $request['Encrypt'] : '',
  14. ];
  15. $msgInfo = [];
  16. switch ($request['MsgType']) {
  17. case 'text':
  18. $msgInfo['text'] = $request['Content'];
  19. break;
  20. case 'image':
  21. $msgInfo['pic'] = $request['PicUrl'];
  22. $msgInfo['media_id'] = $request['MediaId'];
  23. break;
  24. case 'event':
  25. $msgInfo['event'] = $request['Event'];
  26. $msgInfo['session_from'] = $request['SessionFrom'];
  27. break;
  28. }
  29. $data['msg_info'] = json_encode($msgInfo);
  30. CustomerMessage::create($data);
  31. return '';

数据库表结构设计

  1. <?php
  2. use think\migration\Migrator;
  3. use think\migration\db\Column;
  4. class CreateCustomerMessageTable extends Migrator
  5. {
  6. public function change()
  7. {
  8. $this->table('customer_message')
  9. ->addColumn(Column::string('signature')
  10. ->setDefault('')
  11. ->setComment('签名'))
  12. ->addColumn(Column::integer('timestamp')
  13. ->setDefault(0)
  14. ->setComment('时间戳'))
  15. ->addColumn(Column::string('nonce')
  16. ->setDefault('')
  17. ->setComment('随机数'))
  18. ->addColumn(Column::string('openid')
  19. ->setDefault('')
  20. ->setComment('客户id'))
  21. ->addColumn(Column::string('encrypt_type')
  22. ->setDefault('')
  23. ->setComment('加密方式'))
  24. ->addColumn(Column::string('msg_signature')
  25. ->setDefault('')
  26. ->setComment('消息签名'))
  27. ->addColumn(Column::string('to_username')
  28. ->setDefault('')
  29. ->setComment('消息接收者'))
  30. ->addColumn(Column::string('from_username')
  31. ->setDefault('')
  32. ->setComment('消息来源'))
  33. ->addColumn(Column::string('msg_type')
  34. ->setDefault('')
  35. ->setComment('消息类型'))
  36. ->addColumn(Column::text('msg_info')
  37. ->setNull(true)
  38. ->setComment('消息内容'))
  39. ->addColumn(Column::string('msg_id')
  40. ->setDefault('')
  41. ->setComment('消息id'))
  42. ->addColumn(Column::text('encrypt')
  43. ->setNull(true)
  44. ->setComment('加密数据'))
  45. ->addColumn(Column::dateTime('create_time')
  46. ->setDefault('CURRENT_TIMESTAMP')
  47. ->setComment('创建时间'))
  48. ->addColumn(Column::dateTime('update_time')
  49. ->setDefault('CURRENT_TIMESTAMP')
  50. ->setComment('更新时间'))
  51. ->addColumn(Column::dateTime('delete_time')
  52. ->setNull(true)
  53. ->setComment('删除时间'))
  54. ->create();
  55. }
  56. }

写给刚入行的程序员

源地址: 顶级程序员

1.作为前端开发者,使用双显示器能大幅提高开发效率。

2.学编程最好的语言不是PHP,是English。

3.自己做的东西交付之前先测试一遍。

4.问别人之前最好先自己百度,google一下,以免问出太低级的问题。

5.把觉得不靠谱的需求放到最后做,很可能到时候需求就变了,或者取消了。

6.读好书,垃圾书会浪费你时间。

7.不要炫技,面向人脑编程更便于维护。

8.没事别重复造轮子,你造的轮子大多数时候只有你觉得好用。接手你的轮子的人会在背后骂你上百遍。

9.不要先写框架再写实现。最好反过来,从原型中提炼框架。

10.新技术一定不要找书,书一旦印出来就过时了。

11.请勿久坐,多喝水,尤其是遇到很久都解决不了的问题的时候,多走动走动。

12.考虑可维护性比考虑性能更重要。

13.越难解决的bug往往犯的错误越低级。

14.比起鼓励师,不如给程序员找一个靠谱的产品经理。

15.熬夜低效率写代码,不如好好睡觉。

16.你遇到的问题,大多数人都遇到过,并且网上都有完整的解决方案,你找不到,只是你懒得去找。

17.多沟通,不少加班工作是由于沟通少造成的。

18.普通程序员+google=超级程序员。实在不行,百度也可以,学会利用搜索引擎来辅助自己解决问题。

19.早点找女朋友,生活作息会更健康。你懂的!

20.永远别小看程序媛。即使是青铜,说不定背后有个王者在帮她。

nodejs开发的神器 now

now是什么?

now 允许您轻松、快速和可靠地将JavaScript(Node.js)或Docker支持的网站、应用程序和服务带到云中。实际上,包含package.json或Dockerfile的任何目录都可以通过一个命令:now传输到云。

每次部署一个项目,now 将提供一个新的、唯一的URL(甚至在上传完成之前)。这些URL将看起来像这样(我的应用程序-随机字符串):my-app-erkgfjtrna.now.sh 。

当您部署到生产时,您只需选择适当的别名(自定义域)即可。

官网地址: https:/zeit.co

使用方法

  1. 下载命令行工具: npm install -g now
  2. 创建开发目录 mkdir my-project && cd my-project
  3. 创建package.json
    1. {
    2. "name": "koa",
    3. "version": "1.0.0",
    4. "description": "",
    5. "main": "index.js",
    6. "scripts": {
    7. "start": "node index.js"
    8. },
    9. "author": "",
    10. "license": "ISC",
    11. "dependencies": {
    12. "koa": "^2.6.1"
    13. }
    14. }
  4. 创建index.js
    1. const Koa = require('koa');
    2. const app = new Koa();
    3. app.use(ctx => {
    4. ctx.body = 'Hello Koa';
    5. });
    6. app.listen(80);
  5. 登录 now login 然后输入邮箱地址收取验证邮件, 点击邮件里的验证链接, 这里需要翻墙, 因为验证页面有个js在google上.
  6. 执行 now --public 会输出类似下面的结果.
    1. > Deploying D:\xxxx\my-project under shuai
    2. > Synced 2 files (366B) [1s]
    3. > Using Node.js 8.11.3 (default)
    4. > https://my-project-lcjucjkwmi.now.sh [in clipboard] (sfo1) [3s]
    5. > Building
  7. 执行完成后, 就可以打开上面的地址看到运行结果

别名使用

now --public && now alias shuai
即可生成一个 shuai.now.sh 的地址, 方便记忆

使用自己的域名

now --public && now alias shuai.com
需要根据提示验证域名所有权就能使用自己的域名访问了, 而且自动生成https证书

Vagrant+Virtual Box 快速搭建开发环境

  1. Vagrant.configure("2") do |config|
  2. config.vm.box = "ubuntu/xenial64"
  3. # config.vm.network "forwarded_port", guest: 80, host: 80
  4. # config.vm.network "forwarded_port", guest: 3306, host: 3306
  5. config.vm.network "private_network", ip: "10.0.0.3"
  6. config.vm.provision "shell", inline: <<-SHELL
  7. # 更换aliyun软件源
  8. cp /etc/apt/sources.list /etc/apt/sources.list.bak
  9. echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial main restricted universe multiverse' > /etc/apt/sources.list
  10. echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-security main restricted universe multiverse' >> /etc/apt/sources.list
  11. echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main restricted universe multiverse' >> /etc/apt/sources.list
  12. echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-proposed main restricted universe multiverse' >> /etc/apt/sources.list
  13. echo 'deb http://mirrors.aliyun.com/ubuntu/ xenial-backports main restricted universe multiverse' >> /etc/apt/sources.list
  14. apt-get update
  15. # 安装docker
  16. apt-get -y install apt-transport-https ca-certificates curl software-properties-common
  17. curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
  18. add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
  19. apt-get -y update
  20. apt-get -y install docker-ce docker-compose
  21. # 使用aliyun加速docker镜像
  22. mkdir -p /etc/docker
  23. echo '{' > /etc/docker/daemon.json
  24. echo ' "registry-mirrors": ["https://kag9wqej.mirror.aliyuncs.com"]' >> /etc/docker/daemon.json
  25. echo '}' >> /etc/docker/daemon.json
  26. systemctl daemon-reload
  27. systemctl restart docker
  28. # 把vagrant用户添加到 docker 组
  29. usermod -G docker vagrant
  30. # ssh登录后, 进入/vagrant目录, 并启动docker compose , 然后 输出一下当前正在运行的容器
  31. echo 'cd /vagrant && docker-compose up -d && docker ps' >> /home/vagrant/.bashrc
  32. SHELL
  33. end

Ant Design

一个服务于企业级产品的设计体系,基于『确定』和『自然』的设计价值观和模块化的解决方案,让设计者专注于更好的用户体验。

官网: https://ant.design/index-cn
文档: https://ant.design/docs/react/introduce-cn

Ant Design of React
这里是 Ant Design 的 React 实现,开发和服务于企业级后台产品。

特性

  • 提炼自企业级中后台产品的交互语言和视觉风格。
  • 开箱即用的高质量 React 组件。
  • 使用 TypeScript 构建,提供完整的类型定义文件。
  • 全链路开发和设计工具体系。

支持环境

  • 现代浏览器和 IE9 及以上(需要 polyfills)。
  • 支持服务端渲染。
  • Electron

安装

使用 npm 或 yarn 安装#
我们推荐使用 npm 或 yarn 的方式进行开发,不仅可在开发环境轻松调试,也可放心地在生产环境打包部署使用,享受整个生态圈和工具链带来的诸多好处。

  1. $ npm install antd --save
  2. $ yarn add antd

如果你的网络环境不佳,推荐使用 cnpm。

浏览器引入

在浏览器中使用 script 和 link 标签直接引入文件,并使用全局变量 antd。

我们在 npm 发布包内的 antd/dist 目录下提供了 antd.js antd.css 以及 antd.min.js antd.min.css。你也可以通过UNPKG 进行下载。

强烈不推荐使用已构建文件,这样无法按需加载,而且难以获得底层依赖模块的 bug 快速修复支持。
注意:3.0 之后引入 antd.js 前你需要自行引入 moment。

示例

  1. import { DatePicker } from 'antd';
  2. ReactDOM.render(<DatePicker />, mountNode);

引入样式:

  1. import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'

按需加载

下面两种方式都可以只加载用到的组件。

  • 使用 babel-plugin-import(推荐)。

    1. // .babelrc or babel-loader option
    2. {
    3. "plugins": [
    4. ["import", { "libraryName": "antd", "libraryDirectory": "es", "style": "css" }] // `style: true` 会加载 less 文件
    5. ]
    6. }

    注意:webpack 1 无需设置 libraryDirectory。

    然后只需从 antd 引入模块即可,无需单独引入样式。等同于下面手动引入的方式。

    1. // babel-plugin-import 会帮助你加载 JS 和 CSS
    2. import { DatePicker } from 'antd';
  • 手动引入

    1. import DatePicker from 'antd/lib/date-picker'; // 加载 JS
    2. import 'antd/lib/date-picker/style/css'; // 加载 CSS
    3. // import 'antd/lib/date-picker/style'; // 加载 LESS

Vant - 有赞移动端 Vue 组件库


logo



logo


A Vue.js 2.0 Mobile UI at YouZan

Build Status
downloads
Coverage Status
npm version
license

特性

  • 50+ 个经过有赞线上业务检验的组件
  • 单元测试覆盖率超过 90%
  • 完善的中英文文档和示例
  • 支持 babel-plugin-import
  • 支持 TypeScript
  • 支持 SSR

安装

  1. npm i -S vant

快速上手

方式一. 使用 babel-plugin-import (推荐)

  1. # 安装 babel-plugin-import 插件
  2. npm i babel-plugin-import -D
  1. // 在 .babelrc 或 babel-loader 中添加插件配置
  2. // 注意:webpack 1 无需设置 libraryDirectory。
  3. {
  4. "plugins": [
  5. ["import", {
  6. "libraryName": "vant",
  7. "libraryDirectory": "es",
  8. "style": true
  9. }]
  10. ]
  11. }

接着你可以在代码中直接引入 Vant 组件,插件会自动将代码转化为方式二中的按需引入形式。

  1. import { Button } from 'vant';

方式二. 按需引入组件

  1. import Button from 'vant/lib/button';
  2. import 'vant/lib/vant-css/base.css';
  3. import 'vant/lib/vant-css/button.css';

方式三. 导入所有组件

  1. import Vue from 'vue';
  2. import Vant from 'vant';
  3. import 'vant/lib/vant-css/index.css';
  4. Vue.use(Vant);

CDN

  1. <!-- 引入样式 -->
  2. <link rel="stylesheet" href="https://unpkg.com/vant/lib/vant-css/index.css">
  3. <!-- 引入组件 -->
  4. <script src="https://unpkg.com/vant/lib/vant.min.js"></script>

更多内容请参考 快速上手.

贡献代码

修改代码请阅读我们的 开发指南

使用过程中发现任何问题都可以提 Issue 给我们,当然,我们也非常欢迎你给我们发 PR

浏览器支持

现代浏览器以及 Android 4.0+, iOS 6+.

手机预览

可以手机扫码以下二维码访问手机端 demo:

qrcode

链接

开源协议

本项目基于 MIT 协议,请自由地享受和参与开源。