Anne


  • Home

  • About

  • Tags

  • Categories

  • Archives

VUS-SSR项目部署

Posted on 2019-01-03

Vue-SSR : 项目部署

抱歉这篇文章距离上篇很久,一方面是项目有点忙,一方面玩的也很用力。上次发了几个钓鱼的文章主题联想,我在朋友圈也发了一遍,很多人(假装有很多)想看vue ssr相关的东西,可能从零到一的东西太多了,也不需要我再重复发一遍。

ssr项目的部署也是困扰过我一段时间

非SSR项目部署

在做这个项目之前,前端的部署都是极为简单的,流程就是

  1. npm run build 编译打包
  2. 将打包出来的 dist 包单独放到一个库里,这里有好多个项目,push到放项目编译包的远程仓库
  3. 登陆服务器,在服务器上把包 pull 下来
  4. 如果代码托管了七牛,会登陆七牛刷新一下资源

当然,这个步骤里面省略了 nginx 配置,默认认为你的 nginx 已经配好,域名解析也做好了。

SSR项目部署

在做之前也是网上搜了不少大神的文章,看了很多别人的项目代码,讲到部署的少之又少,我所能理解的就是 npm run build 然后 npm run start ,但是问题是我又不能把整个项目都放到服务器上,生产环境我只需要把打包后的文件放到服务器上,nginx还是要配的,假设你nginx配好了,注意nginx配置的端口要跟node的端口一致,不知道部署的时候,百思不得其解,想明白了其实就是部署一个node的项目,我以前也没有发布过node的项目,迷糊了一些时间。

流程如下:

  1. npm run build 编译打包
  2. 【睁大眼睛】👀 要将1⃣️打包出来的 dist/ 文件夹 2⃣️ package.json 3⃣️ server.js 4⃣️ public/文件夹 这四样东西拿出来,放到某个远程仓库
  3. 登陆服务器,在服务器上把包 pull 下来
  4. 在服务器上npm install,这一步需要
  5. 【👀】服务器下载 pm2 进程管理工具,你可以用或者不用, pm2 start < 项目名 > --watch

请您提出疑问

我不知道如何描述的更清楚一些,如果你看到文章还是有疑问。不如在评论区留下你的疑问,我会根据您的提问来完善这个文章。

完!

Vue-SSR: head Mixin 实现头部信息管理

Posted on 2018-10-23

上周发了我第一篇技术博客,传送门1:JS中的数组过滤,从简单筛选到多条件筛选,感谢大家的支持,尤其是提出疑问,发现错误的同学,感谢你们。发完博客以后,我用 hexo 搭了一个 github pages, 绑定了我之前买的域名,传送门2: http://blog.yidol.cn/,以后我的博客会在GitHub发一遍,然后掘金抄送一遍。

近两个月都在忙着搭建 vue-ssr 的项目,因为公司产品是媒体类,SEO 很重要,第一周是尝试用 nuxt 搭建了一个项目,nuxt 确实是开箱即用,比较爽,就是配置的时候可能要看看 nuxt 的文档,还要看看 webpack 的文档,很多人使用 vue-cli3 产生了同样的感受。由于公司给的时间也够,我决定参考尤雨溪的官方例子🌰 传送门3: vue-hacknews-2.0 搭建了我司的新 PC 端项目,整个项目是用 webpack4+vue2+vue-ssr 从 0 到 1,踩过一些坑,多谢网上各个平台的同学们贡献的文章,我打算陆续写文章分享项目搭建的过程,希望也能够帮助到大家。

  下面进入这篇文章的主题,尤大大的例子里是做了一个 tilte 的 Mixin 方法,可以修改各个页面的 title,但是我司的需求可能是不同的页面不仅是要不同的 title,还要不同的 description,author,keywords,网上有很多人使用 vue-meta, 感兴趣的小伙伴可以搜索一下用法,今天我想讨论的是改造尤大大项目里的 title mixin 为 head mixin,满足我司需求。

尤大大的title mixin

  打开 vue-hacknews 项目 src/util/title.js ,可以看到以下代码或者 传送门4: vue SSR 指南 Head 管理

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
// 获取模版里的 title
function getTitle (vm) {
const { title } = vm.$options
if (title) {
return typeof title === 'function'
? title.call(vm)
: title
}
}

// 如果有 title 了就加载新的 title,没有就还有默认的顶着,默认的 title 在哪里,稍后告诉你
// 下面俩一个是服务器端渲染时调用,一个是客户端渲染是调用,为啥俩不一样,可查看文末知识点

const serverTitleMixin = {
created () {
const title = getTitle(this)
if (title) {
this.$ssrContext.title = `Vue HN 2.0 | ${title}`
}
}
}

const clientTitleMixin = {
mounted () {
const title = getTitle(this)
if (title) {
document.title = `Vue HN 2.0 | ${title}`
}
}
}

export default process.env.VUE_ENV === 'server'
? serverTitleMixin
: clientTitleMixin

  文件 src/app.js 在这里全局引入 Mixin

1
2
3
4
5
6
...
import titleMixin from './util/title'
...
// mixin for handling title
Vue.mixin(titleMixin)
...

  这里是默认 title 的地方src/server.js

1
2
3
4
5
6
7
...
//在render函数里
const context = {
title: 'Vue HN 2.0', // default title
url: req.url
}
...

  具体组件里的用法 src/views/UserView.vue

1
2
3
4
5
6
7
8
9
10
export default {
name: 'user-view',
...
title () {
return this.user
? this.user.id
: 'User not found'
},
...
}

Head Mixin的改造过程

  首先是明确我的需求,如文章开头所说,仅仅是 title 是不符合我的需求的,我还需要能够自定义 description,author,keywords。

组件里用法

  尤大大的 title 是返回一个字符串,我把我需要的塞到了一个对象里,需要自定义的就 return 出去,不需要的就还是默认的就行。

1
2
3
4
5
6
7
8
9
10
11
export default {
name: 'article-list',
...
head(){
return {
'title': '文章列表',
'author': '大侠'
};
},
...
}

默认的头信息

  同样在 server.js 里

1
2
3
4
5
6
7
8
// 同样也在render 函数里
const context = {
'title': '可爱王', // 默认title
'author': 'Anne', // 默认author
'keywords': '我是keywords', // 默认keywords
'description': '我是description', //默认description
'url': req.url // 我是重要的一行代码,但是我跟这篇文章没关系
};// 没错我很无聊,打了这么多无聊的注释

引入全局head mixin

  同样在 src/main.js 里

1
2
3
import headMixin from './utils/head';
// head()
Vue.mixin(headMixin);

定义head Mixin

  在 src/utils/head.js 里,在这里是判断了是否有 head,是否有各个我需要的东西,有就加载新的,没有就还是默认的。

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
function getHead (vm) {
const { head } = vm.$options;

if (head) {
return typeof head === 'function' ?
head.call(vm) :
head;
}
}

const serverHeadMixin = {
created () {
const head = getHead(this);

if (head) {
if (head.title) this.$ssrContext.title = `${head.title}-可爱王`;
if (head.author) this.$ssrContext.author = `${head.author}-可爱王`;
if (head.keywords) this.$ssrContext.keywords = head.keywords;
if (head.description) this.$ssrContext.description = head.description;
}
}
};

const clientHeadMixin = {
mounted () {
const head = getHead(this);

if (head) {
if (head.title) document.title = `${head.title}-可爱王`;
if (head.author) document.querySelector('meta[name="author"]').setAttribute('content', `${head.author}-可爱王`);
if (head.keywords) document.querySelector('meta[name="keywords"]').setAttribute('content', head.keywords);
if (head.description) document.querySelector('meta[name="description"]').setAttribute('content', head.description);
}
}
};

export default process.env.VUE_ENV === 'server' ?
serverHeadMixin :
clientHeadMixin;

知识点一:混入 (mixins)

  在做这个项目之前,我没有用过这个东西,传送门5: vue官方文档对混入的介绍

混入 (mixins) 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。

  简而言之,就是你可以自定义一个钩子函数,在每一个 Vue 实例里引用,比如这篇文章里提到的 head() , 帅呆了。

知识点二:服务器端渲染与客户端渲染的生命周期不同

  在所有的生命周期钩子函数里,只有 beforeCreate 和 created 会在服务器端渲染过程中调用,官方文档有提到这个,所以在开发过程中要一定要注意这点。

完!

题外话:关于未来文章的规划

  😁如果你还在看的话,帮忙留个言吧! 上周的文章在掘金得到了一百多个赞,开心,特别感谢我的朋友 Dylan 同学的纠错以及掘金网友 Auroral 提醒递归优化的实例代码与 deepclone 无关联。前端从业两年多,一直没有输出文章,上周突发奇想要整理出自己的博客,能够梳理自己的知识,分享出来也能够帮助到大家, 也希望自己能够坚持下去。想写的太多,精力有限,我想列一些想写的文章,一篇一篇的出,走过路过如果看到了这篇文章,可以评论一下哪篇是你想看的,民意比较多的我就先写啦。<( ̄︶ ̄)>

  1. vue 单页应用的多 layout 实现

  2. 从零到一:用 webpack4 搭一个 vue 项目

  3. 从零到一:用 vue-cli3 搭一个项目

  4. 从零到一:用 nuxt 搭一个 vue-ssr 项目

  5. 从零到一:用 github 和 hexo 搭一个自己的线上博客

  6. Vue-ssr 系列 基于 vue-hacknhews 2.0 想到什么写什么咯

  7. 前端开发中一些实用的工具类网站

从零到一已经有很多人写过啦,但我还是列到了列表里,如果不幸胜出了,我就尽力写的不同一些吧。

JS中的数组过滤,从简单筛选到多条件筛选

Posted on 2018-10-16

在上家公司工作的时候,有一个需求是在前端部分完成筛选功能,一次拿到所有数据,然后根据条件筛选。通常情况下筛选是后台给接口,在数据量不大的情况下,也有人可能会遇到前端筛选这样的情况,特别写了这篇文章分享给大家,有问题请指出,互相学习。

一般情况下的单条件筛选,数组的filter方法就能够满足需求,本文讨论的重点是多条件下的复合筛选,并列出了几个相关知识点。

以下是很多个🌰🌰🌰🌰

1
2
3
4
5
6
7
8

// 这个是例子中的被筛选数组
var aim = [
{name:'Anne', age: 23, gender:'female'},
{name:'Leila', age: 16, gender:'female'},
{name:'Jay', age: 19, gender:'male'},
{name:'Mark', age: 40, gender:'male'}
]

单条件单数据筛选

根据单个名字筛选,用filter方法,判断name是否为目标名字即可

1
2
3
4
5
6
7

// 根据单个名字筛选
function filterByName(aim, name) {
return aim.filter(item => item.name == name)
}
// 输入 aim 'Leila' 期望输出为 [{name:'Leila', age: 16, gender:'female'}]
console.log(filterByName(aim,'leila'))

单条件多数据筛选

根据多个名字筛选,这里是用for循环遍历目标数组,然后用find方法找到后push到结果数组里,用find方法是重名情况下也能得到想要的结果。for循环可以用数组的一些遍历方法替代,代码可以更简化,示例就是大概表达个意思。

1
2
3
4
5
6
7
8
9
10
11
12
13

// 根据多个名字筛选
function filterByName1(aim, nameArr) {
let result = []
for(let i = 0; i < nameArr.length; i++) {
result.push(aim.find(item => item.name = nameArr[i]))
}
return result
}
// 输入 aim ['Anne','Jay']
//期望输出为 [{name:'Anne', age: 23, gender:'female'},{name:'Jay', age: 19, gender:'male'}]
console.log(filterByName1(aim,['Leila','Jay']))
// 有BUG 改进后

多条件单数据筛选

根据单个名字或者单个年龄筛选,用filter方法,判断条件之间是或的关系。

1
2
3
4
5
6

// 根据名字或者年龄筛选
function filterByName2(aim, name, age) {
return aim.filter(item => item.name == name || item.age == age)
}
console.log(filterByName2(aim,'Leila',19))

多条件多数据筛选

我最初是用了很笨的双for循环去做,发现很慢,而且并没有达到预期的效果。具体的心路历程已经太遥远,简单介绍以下这个筛选算法。

首先是把筛选条件都塞到一个对象里,用object对象的keys方法获取到筛选的条件名,及需要筛选的是哪个条件,是name?age? gender?

然后使用filter方法对目标数据进行筛选,🌰如下⬇️

根据名字和年龄多元素筛选

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

//根据名字和年龄多元素筛选
export function multiFilter(array, filters) {
const filterKeys = Object.keys(filters)
// filters all elements passing the criteria
return array.filter((item) => {
// dynamically validate all filter criteria
return filterKeys.every(key => {
//ignore when the filter is empty Anne
if(!filters[key].length) return true
return !!~filters[key].indexOf(item[key])
})
})
}
/*
* 这段代码并非我原创,感兴趣的可以去原作者那里点个赞
* 作者是:@author https://gist.github.com/jherax
* 这段代码里我只加了一行,解决部分筛选条件清空时候整体筛选失效的问题
*/

var filters = {
name:['Leila', 'Jay'],
age:[]
}
/* 结果:
* [{name: "Leila", age: 16, gender: "female"},
* {name: "Jay", age: 19, gender: "male"}]
*/

例如这里,判断每条数据的name值是否在filters.name数组里,是的话返回true,判断filters.age是空数组的话直接返回true,空数组是模拟了age条件被清空的情况,我们仍然能得到正确的筛选数据。

知识点1: Object.key() 获取数组索引或者对象属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14

var arr = ['a', 'b', 'c'];
console.log(Object.keys(arr));
// ["0", "1", "2"]


var obj = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.keys(obj));
// ["0", "1", "2"]


var anObj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(anObj));
// ["2", "7", "100"] 猜猜为啥?

知识点2: js里的falsy

falsy : 0 , false, “”, null, undefined, NaN

在判断语句中,只有上面6种情况会是false,其余的都是true

1
2
3
4
5
6
7
8
var a;
if(a!=null&&typeof(a)!=undefined&&a!=''){
//a有内容才执行的代码
}

if(!!a){
//a有内容才执行的代码...
}

知识点3: Array.every 与 Array.some的区别

我的理解是在遍历数组的时候:

Array.every的条件是「与」的关系,全真为真,及条件全为true则为true,有一个false就返回false

Array.some的条件是「或」的关系,有真为真,条件有一个true就返回true,条件全为false的时候才返回false

下面举个🌰

1
2
3
4
5
6
7
8

// 判断每个名字都为Anne?
let dataEvery = aim.every(item => item.name === 'Anne') // false
let dataEvery = aim.some(item => item.name === 'Anne') // true

// 判断每个名字都是字符串?
let dataEvery = aim.every(item => typeof item.name === 'string') // true
let dataEvery = aim.some(item => typeof item.name === 'string') // true

知识点4: 数组的深拷贝与浅拷贝

最近参与一些前端的面试工作,深拷贝与浅拷贝是我最爱问的问题之一。一个问题就考察了数据类型,数组操作,递归算法等。

因为数组是js里的引用类型,单纯复制时复制的是其引用关系。在对获取的数据进行筛选时,我并不希望影响原始数据,所以我要用到「深拷贝」得到与原始数据数据结构完全相同又相互独立的数据,而不是只复制其引用关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// 我常用方法,如果项目很大,不推荐
let obj1 = JSON.parse(JSON.stringify(obj))

// deepclone
function deepClone(o1, o2) {
for (let k in o2) {
if (typeof o2[k] === 'object') {
o1[k] = {};
deepClone(o1[k], o2[k]);
} else {
o1[k] = o2[k];
}
}
}

想一想:递归算法的优化

这个知识点与本文关系不大。😄 抱歉之前的误导。

这个是看掘金小册前端面试指南看到的,讲算法的时候提了一下递归算法的优化,初见的时候又被惊艳到,还没有在项目里用到。感兴趣的可以试试,这个是斐波那契数列和。可以自己在浏览器里敲一下,试试不用缓存与用缓存的运算次数差别。

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
let count = 0;
function fn(n) {
let cache = {};
function _fn(n) {
if (cache[n]) {
return cache[n];
}
count++;
if (n == 1 || n == 2) {
return 1;
}
let prev = _fn(n - 1);
cache[n - 1] = prev;
let next = _fn(n - 2);
cache[n - 2] = next;
return prev + next;
}
return _fn(n);
}

let count2 = 0;
function fn2(n) {
count2++;
if (n == 1 || n == 2) {
return 1;
}
return fn2(n - 1) + fn2(n - 2);
}

完!

Anne

3 posts
2 tags
RSS
GitHub Instagram
© 2019 Anne
Powered by Hexo
|
Theme — NexT.Muse v5.1.4