一系列入门杂碎

621 阅读4分钟

工作不忙,闲来无事,搞点新鲜东西玩玩啊。

最近,我用很长的一段时间自我反省,发现自己以前是多么的无知,仅现在的技术水平简直low到爆。
目前使用的技术栈主要以vue为主,node的express、Element-组件库等。这些东西可以说用的比较流利了,使用这些技术,自己也可以独立开发。但是这些用久了之后,可以说其他的就几乎没有接触过,就只能做一个web端的前端开发。
意识到自己技术的局限性、以及自己对所运用的技术深度根本还不够。深度不够,广度也不够。可以这么评价自己把:高不成低不就,满瓶不摇半瓶摇
如果,有老前端的,请帮我指到一条发展路线规划,目前实在过于迷茫😞,我还是比较愿意往技术方面发展的。
接下来,我将汇报最近的学习状态:

MVVM原理解读

这是我第二次看MVVM原理代码,第一次也就只知道大概的里面的类及作用。可以说是比上一次更能够理解一些了把。

vue采用数据劫持配合发布者-订阅者模式,通过object.defineProperty()来劫持各个属性的settergetter,当数据发生变化的时候,通知订阅者去攻击视图,触发相应回调。
我想这些应该也是面试经常遇到的问题,但是更加深入的提问,里面有哪些类,各自作用又是什么呢?

上图是我从百度上找的一张图片,可以清晰的看到,MVVM需要具有一个指令解析器Compile、数据监听器Observer、观察者Watcher、proxy代理。
Compile:
实现指令解析器。
通过基类传入的el,vm, 获取文档碎片对象,遍历获取所有元素节点、文本节点,编译模板。
元素节点通过遍历截取指令关键字(text、html、model等)。如果是方法例如:@v-on,就需要分情况考虑。v-on可以与model等合并到一起,先按-拆分,在按照拆分;而@就需要另外考虑。
此外,Compile里还需要删除有指令的标签属性,更新视图。

   if (this.isDirective(name)) {//是一个指令 v-text v-html v-model v-on:click
                const [, directive] = name.split('-');
                const [dirName, eventName] = directive.split(":");//text html model on
                //更新数据 数据驱动视图
                compileUtil[dirName](node, value, this.vm, eventName);

                //删除有指令的标签上的属性
                node.removeAttribute('v-' + directive);
            } else if (this.isEventName(name)) {
                let [, eventName] = name.split('@');
                compileUtil['on'](node, value, this.vm, eventName);
            }

文本节点直接将获取text属性,调用compileUtil。
compileUtil:
编译器。里面除了setgetpudatecompileUtil还会根据Compile传递的属性为其写各个不同的功能。例如: text方法:需要先识别有无{{,有绑定观察者,触发编译器内的updater更新;无则可以直接赋值更新不变。
Watcher:
主要是观察监听。获取旧值保存,更新时,比较新值和旧值是否一样,不一样就触发回调更新值。这里主要有个Dep,设置Dep的target属性,在保存完旧值后,需要将其置空。

getOldVal() {	//保存旧值
        Dep.target = this;
        const oldVal = compileUtil.getVal(this.expr, this.vm);
        Dep.target = null;
        return oldVal;
    }
    update() {	//	更新操作
        const newVal = compileUtil.getVal(this.expr, this.vm);
        if (newVal !== this.oldVal) {
            this.cb(newVal);
        }
    }

Dep:
依赖收集器。主要是收集观察者。将观察者添加到数组中。如果要更新则遍历,触发观察者的update。
Observer:
遍历属性,劫持并监听。主要是Object.defineProperty()内设置setget

get() {
       //初始化
       //订阅者数据变化时,往Dep中添加观察者
    	Dep.target && dep.addSub(Dep.target);
        return value;
},
 set: (newValue) => {
       this.observer(newValue);
     	if (newValue !== value) {
           value = newValue;
         }
       //告诉Dep通知变化
        dep.notify();
}

Node爬虫入门

使用express安装一些依赖包,就可以实现简单的爬虫。

1.1 初始化项目

npm init -y

1.2 项目依赖包

依赖包名称功能描述
superagentHTTP请求
cheerio解析HTML
art-template模板引擎
nodemailer发送电子邮件
node-schedule定时任务

1.3 发送请求

找到目标网站的url,导入superagentcheerio等相关依赖,使用superagent请求网址。获取的数据使用cheerio解析成html,提取所需数据。

function getConstellationData() {
    return new Promise((resolve, reject) => {
        request.get('https://www.d1xz.net/yunshi/today/Sagittarius/').end((err, res) => {
            if (err) return console.log('数据请求失败')
            // 把字符串解析成html,并可用jQuery核心选择器获取内容
            const $ = cheerio.load(res.text);
            let fortuneValue = $('.luck_main .fraction strong').text().split('%');
            fortuneValue.pop();
            let fortuneArr = {}
            let names = ['感情', "健康", "财运", "工作", "综合"];
            for (let i = 1; i < fortuneValue.length; i++) {
                fortuneArr[names[i]] = fortuneValue[i]
            }
            const fortuneDetail = $('.luck_main .det .txt p').text();
            let luckColor = $('.quan_yuan li .words_t').text().slice(0, 1)
            let luckNum = $('.quan_yuan li .words_t').text().slice(1, 2)
            let fortuneImg = 'https://www.d1xz.net/statics/d1xz/pc/public/images/big_xz_pic/10.png?v=6f3101f'
            let fortune = {
                fortuneImg,
                fortuneArr,
                fortuneDetail,
                luckColor,
                luckNum
            }
            resolve(fortune)
        })
    })

}

1.4 模板引擎发送邮件

注意事项:邮件只允许行内样式
编辑好一个html,使用art-template模板引擎编辑参数。在进行模板引擎数据替换时,代码如下:

//导入模板引擎
const template = require('art-template')
let html = template(path.join(__dirname, './love.html'), { fortune });
服务器名称服务器地址SSL协议端口号非SSL协议端口号
IMAPimap.163.com993143
SMTPsmtp.163.com465/99425
POP3pop.163.com995110
在此,我是用的是qq邮箱发送的,需要到qq邮箱的设置中开启smtp。
const nodemailer = require('nodemailer');
let transporter = nodemailer.createTransport('smtps://发件人邮箱:qmorlhzlytoqgjgb@smtp.qq.com');
 // //设置电子邮件数据
    let mailOptions = {
        from: "XXX<发件人邮箱>",//发件人邮箱
        to: "XXX<收件人邮箱>",//收件人邮箱
        subject: '点个赞把!',
        html: html//html内容
    };
    transporter.sendMail(mailOptions, (err, info) => {
        if (err) {
            console.log(err)
        }
        console.log('邮件发送成功', info.response)
    })

想要定时发送,可以了解以下schedule依赖包。
此外,爬取百度图片时,特别需要说明。必须要爬取acjson文件下请求的url,否则获取到的就时undefined

PWA入门

依旧使用的是express。利用node爬取百度图片后,使用fs模块将其已json格式保存。前端使用Ajax获取后端传递的json图片数据。

//使用ajax获取数据渲染。
let content = document.getElementById('content')
let xhr = new XMLHttpRequest();

xhr.open('get', '/images', true)
xhr.responseType = 'json'
let str = ``
xhr.onload = function () {
    let arr = xhr.response;
    arr.forEach(item => {
        str += `<li><img src="${item}"></li>`
    })
    content.innerHTML = str
}
xhr.send();

此外,还需要加载我们的serviceWorker

 window.addEventListener('load',()=>{
            //解决离线缓存的问题 把缓存取出来缓存
            if('serviceWorker' in navigator){
                //当前支持了serviceWorker
                navigator.serviceWorker.register('/sw.js').then(
                    registeration=>{
                        console.log(registeration)
                    }
                )
            }
        })
//sw.js
const { skips } = require("debug");
const CACHE_NAME = "cache_v" + 1;//默认情况 sw文件变化后会重新注册serviceWorker
const CACHE_LIST = [
    "/",
    "/index.html",
    "/index.css",
    "/main.js",
    "/images"
]
self.addEventListener('fetch', (e) => {
    console.log(e.request.url)
})
//需要缓存的内容
function preCache() {
    return caches.open(CACHE_NAME).then(cache => {
        //添加列表到缓存中
        return cache.addAll(CACHE_LIST);
    })
}
self.addEventListener('install', (e) => {
    //如果上一个serviceWork不销毁 需要手动skipWating
    e.waitUtil(
        preCache().then(skipWaiting)
    )
})
//激活当前serviceWorker,让serviceWorker立即生效,self.clients.claim()
function clearCache() {
    return caches.keys().then(keys => {
        return Promise.all(keys.map(key => {
            if (key != CACHE_NAME) {
                return caches.delete(key)
            }
        }));
    })
}
//当前serviceWorker安装完毕后
self.addEventListener('activate', (e) => {
    e.waitUtil(
        Promise.all([clearCache(), self.clients.claim()])
    )
})