今天正好有个老朋友聊起来jquery源码,他对于源码不了解,我抱着学习交流的心态,给他讲解了核心实现。(好像自己也鸽了好长时间)

顺便在哪个cdn服务商找个jquery文件打开, 我这里用的1.2.3版本为例,最新版本也差不多,只有两三处变化https://cdnjs.cloudflare.com/ajax/libs/jquery/1.2.3/jquery.js

源码分析

17-20行传入选择器,返回自身new出来的init方法,估计你们也没用过$()的第二个参数,这里省略掉

var jQuery = window.jQuery = function(selector) {
    return new jQuery.prototype.init(selector);
}

26-27行这就是为什么总是用$开头的原因,挂载到window对象下,属于全局变量

// Map the jQuery namespace to the '$' one
window.$ = jQuery;

36-547行剔除我们不需要的保留核心,留下init方法,内部做了jquery实例与选择器的判断,这里我们忽略掉,简化

jQuery.fn = jQuery.prototype = {
    init: function(selector) {
        var nodes = document.querySelectorAll(selector);
        for (var i in nodes) {
            this[i] = nodes[i];
        }
        return this;
    }
    //此处省略十万字
}

549行来上一段这个,jquery原型链传递给jquery原型下init方法的原型,回头再看new时候的代码,很清楚明了

jQuery.prototype.init.prototype = jQuery.prototype;

完整实现

在jQuery的原型上继续增加功能就很接近初版jQuery了,这里我是简单实现了text()方法

    var jQuery= function (selector) {
        return new jQuery.fn.init(selector);
    }

    jQuery.fn = jQuery.prototype = {
        init: function (selector) {
            var nodes = document.querySelectorAll(selector);
            for (var i in nodes) {
                this[i] = nodes[i];
            }
            return this;
        },
        element: function (callback) {
            for (var i = 0; i < this.length; i++) {
                callback(this[i]);
            }
        },
        text: function (content) {
            if (content == '' || content) {
                this.element(function (node) {
                    node.innerHTML = content;
                })
                return content;
            } else {
                return this[0].innerHTML;
            }
        },
    }

    jQuery.prototype.init.prototype = jQuery.prototype;

    window.$ = jQuery;

结束

核心其实一点不复杂,插件的实现我倒是很喜欢,自身的功能我看来大部分全是用插件实现的,工具自身的巧妙设计加上便利性。

在传统页面制作上jquery一把梭用的很舒服,但MVVM的出现改变了大家的思考方式,只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,对于项目管理轻松不少。

如果有简单需求的单页上,jquery还是有用武之地的,上MVVM只能是徒增麻烦。

最近感觉好卡啊

tx香港像炸了?既然备案了还是考虑再搬进国内8

之前用过面板,纯手搭,现在还是用的宝塔老版本,计划备份站点,重置服务器,几天前在屋里虚拟化设备上用docker配置过实例,php+nginx的站点可以统一使用这套实例的配置alpine-nginx-php7

看了下上一篇文章发布时间还是在两个月之前,哇,一下在家玩了一个多月了

想下在家都干嘛了,睡觉,玩游戏,看电影,写代码,看书,参加活动,拼模型,捡垃圾,适当的运动,房间整理。

大致的时间分配如下图
QQ截图20190603202936.png

看小米手环每天睡觉的时间差不多都在10个小时,steam收藏家的游戏买了还要玩?当然是玩手游啦,荒野乱斗简单快速的玩法真的不错,固定的四张地图场景,还有一张活动地图,固定的地图玩法可以,在时间段内推出新活动,新活动会对场景物体进行微调,增加一些特定玩法,队伍的奖励机制也很巧妙,除非你是倒数123,都会有奖励,每场比赛类似于排位赛,胜利会获得奖杯(英雄个人奖杯与总奖杯),总奖杯只会一直累加,失败只会减少英雄个人奖杯,玩长时间真的有毒。


- 阅读剩余部分 -

把最近整的一些小玩意整理分享一下

手机号登录,分析一下页面可以知道一般是有两个按钮(获取验证码,登录)两个框(输入手机号,输入验证码)

所以有了下面这个玩意(不看具体功能,只看结构)

<template>
    <div class="login-wrapper">
        <div class="title-bar">登录</div>
        <div class="wrapper phone-wrapper">
            <span class="title">手机号</span>
            <input class="input phone" type="text" placeholder="手机号">
        </div>
        <div class="wrapper code-wrapper">
            <span class="title">验证码</span>
            <input class="input code" type="number" placeholder="验证码">
            <div class="send">获取验证码</div>
        </div>
        <div class="wrapper btn-wrapper">
            <div class="input btn">登录</div>
        </div>
    </div>
</template>

这个时候就可以开始写逻辑了,也是来简单分析一下,登录需要点击,获取验证码需要点击并且能倒数秒数,也就是动态修改文字,体验好一点可以检查限定手机号位数,验证码位数。

那就差不多是下面这个样子

<template>
    <div class="login-wrapper">
        <div class="title-bar">登录</div>
        <div class="wrapper phone-wrapper">
            <span class="title">手机号</span>
            <input class="input phone" type="text" placeholder="手机号"
                   :value="phone"
                   ref="phone" v-on:change="changePhone" v-on:input="changePhone">
        </div>
        <div class="wrapper code-wrapper">
            <span class="title">验证码</span>
            <input class="input code" type="number" placeholder="验证码"
                   :value="code"
                   ref="code" v-on:change="changeCode" v-on:input="changeCode">
            <div @click="loginCode" class="send">{{codeText}}</div>
        </div>
        <div class="wrapper btn-wrapper">
            <div class="input btn" @click="login">登录</div>
        </div>
    </div>
</template>

<script>
        name: "LoginPhone",
        data() {
            return {
                phone: '',  //输入框中的手机号
                code: '',  //输入框中的验证码
                codeText: '获取验证码',  //倒计时显示文字
                timingBoard: 60,  //倒计时数
                timer: null,  //一个定时器,用来倒数验证码
            }
        },
        methods: {
            loginCode() {},   //获取验证码
            login() {},       //登录
            changePhone() {}, //检查手机号长度
            changeCode() {},  //检查验证码长度
        }
</script>

有了这些已经足够你实现出一个基本的手机号登录界面了,如需完全代码请点击下面gist链接

完整代码参阅: https://gist.github.com/flxxyz/64ceb06a0754d67a771b3e3e7dc94d48

说实话用了这么长时间的vue,都没看过API,这几天重构博客偶然发现Vue.directive,挺厉害的样子

总是看到这里用Vue.use(ElementUi),那里用Vue.use(axios),一直停留在了用的层面,正好我发现编写markdown解析实例的消耗好像有点大,直接处理成指令或许会方便很多(真的方便了很多,少写了一堆方法)

简单描述一下流程吧

渲染文章的组件在挂载的生命周期中,会查询本地记录中是否存在对应的文章,不存在就发起请求线上查找,否则404。
文章为markdown内容,考虑让前端处理直接解析出来(毕竟前端性能过剩233),减少后端逻辑处理负担,一致性什么现在是不需要考虑的。
markdown解析器就用marked,完成逻辑如下

//main.js

import Vue from 'vue'
import App from './App'
import markdown from './markdown';

//注入markdown解析器
Vue.use(markdown.install)
Vue.prototype.$marked = markdown.marked

new Vue({
    store,
    router,
    render: h => h(App)
}).$mount('#app')

集成marked制成插件形式暴露

//markdown.js

import marked from 'marked'
import('highlight.js/styles/atom-one-dark.css')

marked.setOptions({
    renderer: new marked.Renderer(),
    pedantic: false,
    gfm: true,
    tables: true,
    breaks: false,
    sanitize: false,
    smartLists: true,
    smartypants: false,
    xhtml: false,
    highlight(code) {
        return require('highlight.js').highlightAuto(code).value;
    },
})

let install = (Vue) => {
    if (install.installed) return;
    Vue.directive('markdown', {
        bind: (el, binding, vnode) => {
            el.innerHTML = marked(binding.value)
        },
        update: (el, binding, vnode) => {
            el.innerHTML = marked(binding.value)
        }
    })
}

export default {
    marked,
    install,
}

在标签上使用v-markdown指令

//Test.vue

<template>
    <div>
        <div v-if="isNotFound">404</div>
        <div v-else v-markdown="article"></div>
    </div>
</template>

<script>
    const 这是一个查找文章的接口 = function () {
        return new Promise((resolve, reject) => {resolve(id)})
    }

    export default {
        name: "Test",
        data() {
            return {
                article: '',
                isNotFound: true,
            }
        },
        methods: {
            handlerArticle(id) {
                //查找本地文章
                let a = this.findArticle(id, async (id) => {
                    return await 这是一个查找文章的接口(id);
                })
                if (a == null) {
                    return 404;
                }

                return a;
            },
            findArticle(id, callback) {
                // let res = '## Test';
                let res = null;
                if (res === null) {
                    return callback(id);
                }

                return res;
            }
        },
        mounted() {
            //用id来查找文章
            let a = this.handlerArticle(123);

            if (a === 404) {
                //跳到错误页面
            }

            //处理loading
            this.isNotFound = false;
            this.article = a;  //将markdown内容直接保存到变量
        }
    }
</script>

完整代码参阅: https://gist.github.com/flxxyz/93e009d32ecd7e0c6785a52571577cd7

蹭了学生优惠,买了个阿里云轻服务器,5M带宽转国外线路减少丢包概率还不错,ns联机美滋滋,不过据说港服联机服务要出了,不知道联机质量会怎么样

firewall中继栗子

# 打开ip伪装
firewall-cmd --add-masquerade --permanent

# 添加端口协议
firewall-cmd --add-forward-port=port=中转后的端口:proto=tcp:toport=酸酸乳端口:toaddr=酸酸乳地址 --permanent
firewall-cmd --add-forward-port=port=中转后的端口:proto=udp:toport=酸酸乳端口:toaddr=酸酸乳地址 --permanent

# 重载一下
firewall-cmd --reload

koolshare里面大家好像用的都是StarWind V2V Converter这款软体,再就是用PE里面的写盘工具

然鹅,在macos不能玩这些windows的工具,搜索发现virtual box自带的命令集,真香!

VBoxManage --help一下什么都有,新建,修改,删除,网络适配器,DHCP,共享文件夹...

.img转换.vdi脱离GUI,shell冲冲冲!

$ VBoxManage convertdd openwrt-koolshare-mod-v2.22-r8838-af7317c5b6-x86-64-combined-squashfs.img 1.vdi

一个虚拟机转盘完成,秒转

This page loaded in 0.000982 seconds