Abo

一些零散的笔记与目标


11904651_p0

オレは海贼王になる男だ!

​ ——路飞

webstorm

  1. lorem可以生成随机字符串

element

  1. el-col加起来24

target

  • [ ] 大创-介绍页面

  • [ ] Android入门

  • [x] 算法pdf

vuejs实战

先浏览高阶 Vue+Nodejs+MongoDB 大概feeling

可跳过不应该错过,可以回头看

Vuejs SSR同构

Vue+Nodejs+MongoDB –DAY 1

  • 微信公众号的消息回复平台,让用户和公众号进行互动
  • 一个是微信的网站app
  • 一个是微信小程序实现消息的展示,以及小程序内的商城支付
  • 一个网站的管理后台,实现数据爬虫爬取
  • 这些不同端的产品,公用一个nodejs后台,所有的数据端接口,无论是网页的,服务器端渲染,还是基于…各种东西都在nodejs,跟vue ssr
  • 其中微信的公众号集成开发会消耗很多时间
  1. 订阅号适合个人开发者跟小公司,没门槛比如技术博客,小文章,服务号像公司运营的平台,有审核认证的门槛,企业号比较适合公司,比如快递公司内部的考勤体系
  • 服务号有权限之类的,比如支付权限,而订阅号是没有的,订阅号可以每天都发文章,而服务号每个月只能发4篇文章,其实我觉得最大区别就是支付权限吧……订阅号可以转成服务号,一旦转换就不可逆
  1. 小程序推出不到一年,现在的门槛还是很低的,验证一个公司业务是否可行,最小成本的方式就可以通过服务号或者小程序,验证代购之类的
  • 一般只有注册公司,才可以使用正常的支付功能
  1. 如何申请公众号以及小程序,无论是哪个公众号,都需要一个唯一的没有用过的邮箱,只有经过认证的公众号才能获取用户的详细资料信息,能语音识别,上传素材多媒体等等。认证需要挂靠公司,认证的费用是300块钱,提供个人身份证,营业情况
  2. 申请域名的时候不要急着申请SSR证书,因为有免费的SSR证书,服务器的话建议大厂,比如阿里云,会节省一些认证步骤,
  3. dnspod以及域名备案以及阿里云
  4. 码云可以免费私有化

总结

一脸懵逼:申请公众号-选购域名跟备案解析域名-选购跟配置服务器-安装Nodejs/配置Nginx端口代理跟域名指向-安装MongoDB-配置git跟配置PM2(本地跟服务器双操作),此路不通,打算换个途径了,先看着

Vue+Nodejs+MongoDB –DAY 2

  • 消息机制 公众号的界面介绍以及下方的点击框
  • 用户的回复不论是消息还是图片、语音会输出到后台,然后我们进行检测然后进行智能回复,此为微信化开发的大致
  • 网页接入,通过公众号可以跳转到网页,导入接口,调用核心API组件,比如微信支付
  • 用户管理,获取用户基本信息以及分组,便于推广
  • 如果产品不涉及钱的问题,订阅号就可以满足

  • 小程序

  • 依附于微信场景
  • 囊括了一个web应用所具备的能力
  • 通过第三方平台可以放大小程序的能力范围
  • 优势:小体积,大速度,方便
  • 可以直接注册也可有在订阅号里面申请认证,同样只有服务号才能申请开通微信支付的功能
  • 公众号第三方平台 开放接入(也是需要公司/企业证)
  • 管理中心 公众号/小程序-> 绑定公众号跟小程序 -> 有了测试号,可以统一跨平台的uni-id
  1. Sass样式预处理器

  2. less(嵌套)

  3. Sass

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // color.sass
    $grey: #ccc
    // base.sass
    import './color.sass'
    a
    color: $grey

    //pages.sass
    import './base.sass'
    import './font.sass'
    .title
    font-size: $baseFont
    a
    font-size: $middleFont

    Koa Express

    身边逐渐都在使用Koa而淘汰Express

    • express有很多中间件,所以使用express的人很多
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //express.js
    var express = require('express')
    var app = express()
    // 外联行驶
    var mid = function(req,res,next){
    req.body='mark'
    next()
    res.send(req.body + 'done')
    }
    app.use(mid)
    app.use(function(req,res,next){
    //申请中间件,req主要用来获取请求的信息,res返回处理的结果,把当前函数的控制权转交给下一个代码的单元来处理,如果next里面传递一个参数的话,这也是符合nodejs的约定,就是说,如果这个时候出错了,它的错误信息作为一个参数,在next里面传递下去,也可以在这个中间件里面做很多事情,比如对body追加内容,可以内联的形式,也可以外联,内敛就是在这里:
    req.body='saved'
    next();
    // 外联的话就是定义在use外面
    })
    app.listen(3000)

    // 当一个http请求进来后,首先会进入到mid这个中间件来,然后对body设置一个初始的字符串,然后调用next(),就会进入到下一个代码的单元,也就是新的一个use,就是saved那里,再调用next(),这是没有其他代码单元,就会回到mid里面去,去执行send,所以等代码运行结束后,我们在浏览器收到的内容为:mark saved done

    以上即是express中间件的一个形态

    如若我需要在中间件内加入异步代码:比如查一段数据,对远端api的调用,我们这里设置一个延时的函数,只要它是一个异步的任务,我们利用callback的形式,来控制中间件的控制劝。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    //express.js
    var express = require('express')
    var app = express()
    var asyncIO = function(cb){
    setTimeout(function(){
    cb()
    },500)
    }
    var mid = function(req,res,next){
    req.body='mark'
    next()
    res.send(req.body + 'done')
    }
    app.use(mid)
    app.use(function(req,res,next){
    asyncIO(function(){
    req.body='saved'
    next();
    })

    })
    app.listen(3000)

    如果异步的代码多了,尤其是并发的异步,层层的回调会让测试跟维护代码很复杂,特别是异常处理,都交给了下一层不透明,所以express的异步回调机制有点靠不住,再加上js越来越强,所以koa就横空出世了,那么它的中间件怎么来实现呢?我们传进去的function不再是普通function,而是一个generator函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    //koa.js
    var koa = require('koa')
    var app = koa();
    var asyncIO = function() {
    return new Promise(function(resolve){
    setTimeout(function(){
    resolve()
    },500)
    })
    }
    var mid = function () {
    return function *(next){
    this.body = 'mark'
    yeild next
    this.body += 'done'
    }
    }
    app.listen(3000)
    app.use(mid) //调用中间件
    app.use(function *(next){
    yeild asyncIO()
    this.body += 'saved'
    yield next //通过yeild来调用next
    })

    结果跟express差不多,但是至少没有了回调的过程,扁平化了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    //Koa2.js
    const Koa = require('koa')
    const app = new Koa() //新版本要用到new关键字
    const asyncIO = () => {
    return new Promise(resolve => setTimeout(resolve,500))
    }
    const mid = () => async(ctx,next) => {
    ctx.body = 'mark'
    await next()
    ctx.body = ctx.body + 'done'
    }
    app.use(mid())
    app.use(async(ctx,next)=> {
    await asyncIO()
    ctx.body += 'saved'
    await next()
    } )
    app.listen(3000)

express 提供了next模式,可以在中间件做异步操作,但是仅限于异步完成后通知下一个中间件。而该中间件本身是无法执行异步完成之后的逻辑,next仅仅是一个同步函数,,执行完就结束了。koa用到了async await ,所有中间件本身的异步逻辑完成之后还可以完成后该中间件的后置逻辑,一次请求会往返该中间件两次,很多逻辑就会只变得异常简单,代码易于维护。、 异常处理在express 中其实挺坑爹的,但是koa中异常处理非常简单。不管是同步还是异步,用promise包装之后都能被捕获。

前两年的grant依然在很多公司内部使用,但是gulp出现了,然后webpack统一了四海江湖,成为前端工作标配

webpack

核心概念:一个是入口,一个是输出,一个是loader,一个是plugin,这几个在webpack里面扮演着重要的角色,不管是图片还是样式,都可以看做是前端的静态资源,都会一股脑子扔进webpack的肚子里面,在他肚子里面有各个器官,就像它有各个loader一样,这些的loader把吃到肚子的这些乱七八糟的东西,要啥分析啥,plugin就像植入的大脑芯片,本来就是外面的东西,用于加强webpack,最后以webpack的输出把所有的养分分配到应该去的地方,下面以小程序举例子

小程序

1
2
3
4
5
6
//quickstart项目
//pages文件夹 里面于两个页面文件夹,一个是index首页,一个是日志页面logs,里面各有对应的js、wxss、wxml、json文件
//utils文件夹 里面有个工具函数 util.js
app.js //
app.json
app.wxss

聊聊pages文件夹,我们使用vue的时候,往往会把页面的js、wxss、wxml等放在一个文件,我这里指的是html、css、js,比如从上到下是模板、脚本、样式,

然后我们来分析小程序里面的页面,比如wxml里面,它自成的模板里面还需要标签之类的,我们可以利用webpack引入类似(pug、jet)模板,可以简化我们的写法,比如根据缩进判断标签的嵌套层次

1
2
3
view.container
view.userInfo(bindtap = 'bindViewTap') //括号里面是属性
view.userinfo-nickname {{userinfo.nickname}}

当然,这一段在小程序里面是不被识别的,那我们这么处理呢?

首先在vue里面我们的处理方式,是加上template:

1
2
3
4
5
<template lang='pug'>
view.container
view.userInfo(bindtap = 'bindViewTap') //括号里面是属性
view.userinfo-nickname {{userinfo.nickname}}
</template>

模板写完开始写脚本(js)、样式,对于样式我们用sass进行编译

1
<style lang='sass'>

所以处理完之后,一个pages文件夹里面的页面文件夹里面就只有一个文件了,把wxml后缀名改一下,我们可以借助webpack对后缀名进行识别然后编译,后缀名改成mina,接下来万事俱备,只剩下webpack的集成了

大体上的流程是这样的:我们从这个项目里面来启动一个任务,比如build这样的一个task,在任务里面确定需要被编译的这些文件的路径以及要输出的路径,比如遍历pages里面一个个后缀名为mina的页面,从里面拿到template/script/style,然后针对他们进行相对应的plugin的操作,比如针对模板的话,我们会用pug进行编译,对于脚本,比如里面引用了async跟await,需要对他进行。。的编译,样式的话就是sass,等到全部编译之后,我们就把这些内容输出到指定的文件夹下面,在这个过程中,把这些模板样式脚本全部抽离出来的中间件就可以看做是我们的loader

接下来我们在根目录新建一个文件夹,就是quickstart项目:新建文件夹 tasks 里面建立一个build.js

在build.js里面我们可以通过renderConf.entry来指定它的入口文件,然后声明一个编译器compiler来传入这个renderConf,最后再调用compiler里面的watch({},(err,stats))来监听整个文件的变化,这个就是主要的核心代码,那么在配置之前,可能还需要先来删除一下我们已经编译过的目录,来清空这个目录,重新新建目录跟文件,需要通过

//伪代码

rm(‘rf’,assetsPath)

mkdir(assetsPath)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
require('shelljs/global') // 因为我们需要调用系统命令来新建和删除一些文件夹
const webpack = require('webpack')
const fs = require('fs') //来读取一些文件
const _ = require('lodash') //来引入一些工具函数
const { resolve } = require('path')//通过path引用resolve
const r = url => resolve(process.cwd(),url)//拿到运行脚本的路径
const webpackConf = require('./webpack.fonf')//拿到webpack的配置文件
const config = require(r('./mina-config')) //我们在mina-config约定一些页面所在的位置,包括一些变量
const assetsPath = r('./mina')//拿到我们需要部署的文件夹的目录,我们需要把编译后的文件全部扔到mina里面去
rm('-rf',assetsPath) //删除旧的文件夹
mkdir(assetsPath) //新建新的文件夹
var renderConf = webpackConf//声明renderConfig
renderConf.entry = () => _.reduce(config.json.pages,(en,i) => {
en[i] = resolve(process.cwd(),'./',`${i}.mina`) //$是字符串拼接
return entry
})// 定义入口文件,进行一个遍历,通过lodash上面的reduce,我们传入所有的页面pages,逐个拿到他们里面的mina的文件夹路径
//关于config.json.pages,其实就是我们app.json里面的pages字段
//是时候定义出口了
renderConf.entry = entry()
renderConf.entry.app = config.app
renderConf.output = {
path: r('./mina') //配置路径,resolve到根目录下的mina
filename: '[name].js' //名字保持同名
}

var compiler = webpack(renderConf)
//写入小程序的app.json文件
fs.writeFileSync(r('./mina/app.json'),JSON.stringfy(config.json),'utf8') //传入config.JSON,把整个小程序配置的内容写入到mina下
compiler.watch({
aggregateTimeout: 300
poll: true

}, (err,stats) => {
//打印在编译过程中产生的信息
process.stdout.write(stat.toString({
color: true,
module: false,
children:true,
chunks: true,
chunkModules: true
}) + '\n\n')
})

接下来在tasks里面再新建webpack.conf.js

通过module.exports暴露出一个配置对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
const {resolve} = require('path')
const r = url => resolve(__dirname,url)
const webpack = require('webpack')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ProgreeBarPlugin = require('progree-bar-webpack-plugin')
//引入一个插件,就是 webpack里面的一个插件,专门针对文本进行词法分析,把匹配的文本内容摘离出来
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const ExtractSass = new ExtractTextPlugin({
filename: '[name].wxss' //如果后缀名是wxss,就把里面的样式给拎出来
})
module.exports = {
devtool: false,
output: {
path: r('./mina') //拿到根目录下面的mina
filename: '[name].js' //同名的js
},
resolve: {
alias: { //依赖
utils: r('../utils/utils') //工具类函数
}
}
module: { //配置模块
rules: [ //声明规则
{
//对js的babel的编译
test: /\.js$/, // $是表示结尾
loader: 'babel-loader',
exclude: /node_module/,
options: {
presets: {
//配置项,就是我们在调用babel-loader的时候对它所施加的参数
['env', { modules: false}]
}

}
},
{
//第二条规则
test: /\.sass$/,
use: extractSass.extract({
use: [
{loader: 'css-loader'},
{
loader: 'postcss-loader',
option {
plugin: (loader) => [
require('autoprefixer')({
//如果是浏览器的话
browsers: [
'last 2 version'
]
})
]
}
}
{
loader: 'sass-loader',
option: {
//配置缩进
indentedSyntax: true
}
}
],
fallback: 'style-loader' //如果都失败就用style-loader
})
},
{
//规则:匹配所有的mina文件
test: /\.mina$/,
loader: 'wechat-mina-loader', //自己实现的loader
options: {
path: r('../') //上层目录
dist: './mina'
}
}
]
},
plugins: [ //配置用到的插件
extractSass,
new CopyWebpackPlugin([ //拷贝文件的一个插件
{
from: {
glob: 'pages/**/*.json' //pages下面的所有的json文件
},
to: ''
},
{
from: 'static',
to: 'static'
}
]),
//下一个插件,优化:模块合并
new webpack.optimize.ModuleConcatnationPlugin(),
//js压缩
new webpack.optimize.uglifyJsPlugin({
sourceMap: false
}),
new ProgressBarPlugin() //进度条的插件
]
}

在根目录里再新建一个文件mina-config.js,也是通过exports暴露出一个配置对象

1
2
3
4
5
6
7
8
9
module.exports = {
'json': {
//app.json里面的内容
//通过它来配置小程序里面的页面或者样式
}
'style': {

}
}

在根目录下再新建一个vender.js,来对一些函数进行一些封装,包括暴露一些全局的变量,因为在webpack里面编译的时候需要在小程序拿到一些外部的变量。

Vue+Nodejs+MongoDB –DAY 3

  • 购买阿里云,等待了解机制结构,以及域名,然后部署博客

js中的reduce

1
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
1
2
3
4
5
6
7
8
9
10
const array1 = [1, 2, 3, 4];
const reducer = (accumulator, currentValue) => accumulator + currentValue;

// 1 + 2 + 3 + 4
console.log(array1.reduce(reducer));
// expected output: 10

// 5 + 1 + 2 + 3 + 4
console.log(array1.reduce(reducer, 5));
// expected output: 15

lodash中的reduce

.reduce(collection, [iteratee=.identity], [accumulator])

iteratee 会传入4个参数:(accumulator, value, index|key, collection)。

故一个是用数组调用,一个是拿_调用reduce,注意参数不一样

(重构小程序失败,已弃坑)

Vue.js SSR 实现思路

SSR:server-side rendering 服务端渲染,直接对前端返回数据并且是渲染好的html页面,不是返回一个空的html页面,剩下的数据全部借助vue来发出一个个异步的请求获取到数据后填充到页面中,为什么要这么干?最直接的页面是为了SEO问题,无论是angularjs跟react都面临都面临seo优化的问题,当然这么干,首屏加载可以更快,用户体验更好。最重要的还是SEO,产品希望被百度谷歌收录进行排名,进一步被用户搜索到,进一步实现品牌的推广,这一切的先决条件就是爬虫爬得到,比如百度,那肯定带数据的完整的html页面才是它们的最爱,任何异步的东西都可能让爬虫望而却步,那在异步的基础上做的技术条件能否让爬虫有机会获取到呢?答案是可以的,但是要付出比较高的技术代价,成本不太乐观,那么在vue里面如何实现SSR呢?如何输出带数据的html页面呢?

我们通过伪代码的形式来理解vue跟ssr

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//app.js
const app = new Vue({}) //实例
const store = new Vuex.Store({}) //数据模型
//视图组件
const router = new Router({
routes: [
{path: '/p1',component:Page1}
{path: '/p2',component:Page2}
{path: '/p3',component:Page3}
]
})

// entry-server.js
//暴露一个能拿到上下文对象的函数
export default context {
router.push(context.url)//把当前htttp请求的url地址push到router里面
//返回一个promise
//通过context的url交给路由,然后通过getmatchedComponent拿到对应的组件,遍历组件,是否需要服务端数据,需要的话就请回来,搞完之后再渲染,所以是在服务端完成,而不是在浏览器
return promise.all(router.getMatchedComponents().map(
component => {
if(component.fetchServerData) {
return component.fetchServerData(store)
}
}
))
.then(() => {
context.state = store.state
return app
})
}
store.repalceState(window.__initisl_state__)
app.$mount('#app')

Nuxt前后端同构SSR框架

如果只是极少数页面需要seo,可以借助webpack插件来做prerendering,也就是预渲染。

react社区推出nuxtjs框架后,vue也开发了真正属于自己的前后端同步的框架就是nuxt.js,如果你想有个更高水平的SSR方案来提供更加好的公众体验,通过nuxt.js构建的项目能让你用同一套代码实现客户端页面的开发又能满足SEO

在nuxt里面已经集成了webpack,也不用我们手动搭建ssr本身,省时省力,我们可以基于nuxt来开发了,但还没达到稳定的状态。

先确保已经装了vue脚手架 -g

vue init next/koa xxx

assets资源目录,未编译的静态资源,比如sass之类的

components用来组织组件

layouts是布局,项目使用到前端页面的所使用的默认布局组件

middleware放应用的中间件

pages放视图/路由,根据文件路径生产 路由配置

plugins放vuejs实例化之前需要运行的插件

static放静态文件,这里的静态文件是不会被nuxt的webpack进行编译构建的

server里面放nodejs后台的东西 mongodb之类的

store里面放vuex状态树的 文件

backpack.config.js webpack配置

nuxt.config.js nuxt配置

可以把assets放到static里面,middleware放到server里面

然后更改nuxt.config.js配置

pug/jade后端模板引擎

比如网页里面有图片文字,这些都可以看成网页中的数据,可以是写死的内容,可以是数据库的内容,如果是写死直接返回浏览器,如果是动态数据,还需要检索出来替换到html里面,替换的过程就需要某种技术来实现。比如替换到占位符里面,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- var text = 'abc'
p#desc
a.link(href='xxx') 链接 <strong>abc</strong>
span #{text} //替换变量

if isText
p aaa //p标签,内容是aaa
else
p bbb

- obj = {a:1,b:2}
- for (var k in obj)
p = obj[k]

- each v,key in obj
p #{key}: #{v}

maxin sec(name)
p abc #{name}

+sec(1)
+sec(2)

注意.link指的是class

可以有原生标签

模型工具操作数据库

mongoose 连接nodejs mongodb的一个库

核心三个概念

schema -> model -> entity

为什么推荐GraphQL 而不是 Restful API

lesson1

Vue+Nodejs+MongoDB –DAY 4

隧道:Ngrok魔法隧道

移动端音乐app

other

狗屁不通文章生成器

https://suulnnka.github.io/BullshitGenerator/index.html