nextjs路由定制,路由嵌套,自定义路由,pages配置

众所周知,nextjs使用项目根目录下的pages文件夹作为默认的路由路径,也就是说在pages下配置的文件夹会自动作为对应的路由路径,那么如何配置自己理想的项目结构?

经过查找在配置server.js时,使用next生成应用dir属性设置(server.js不止这点儿代码)。

1
2
3
4
5
const next = require("next");
const app = next({
dir: "./client", // base directory where everything is, could move to src later
dev
});

如此设置便可以达到下图的项目结构效果,同时打包的内容在client下的.next文件夹里,pages作为路由的页面入口,components文件夹作为主要开发的业务组件,引入到pages目录里,如此便可以将路由和业务区分开来。

ps: 当然如果项目不大,可以直接在根目录新建components目录,不必非要放在client下。

img点击并拖拽以移动

但是如此build编译打包会报错是为什么呢?

因为没有指定文件夹,会默认在根目录编译,那么找不到pages文件夹就会报错,可以在package.json文件下build时增加你的client目录,如图

img

那为什么费这么大劲配置server.js呢,不能一键启动吗,我不需要太复杂的东西?

既然如此就不需要server.js,直接在scripts各命令后加上client目录名即可,因为next内部封装了小服务器(node_modules/next/dist/server/lib/start-server.js),这个client就相当于dir名字了。

img

mathJS应用

最近开发遇到存计算公式在字段里,前端取出来使用的问题。本来想着使用eval计算字符串的,且不说eval本身,直接使用也涉及到js的精度问题(eg: 0.1+0.2)上网查到使用eval制作简单计算器,与这个问题思路相同,但是同样没有直接解决精度问题,后来看到mathjs既能解决eval问题又能解决精度问题,着实好用。

mathjs

mathJS是一个广泛用于javascript和nodejs的数学库。

它具有支持符号计算的灵活表达式解析器,大量内置函数和常量,并提供了一个集成解决方案来处理不同的数据类型,例如数字,大数,复数,分数,单位和 矩阵。 强大且易于使用。介绍译自官网=》math.js | an extensive math library for JavaScript and Node.js

特点

​ 1、支持数字,大数,复数,分数,单位,字符串,数组和矩阵。
​ 2、与JavaScript的内置Math库兼容。
​ 3、包含一个灵活的表达式解析器。
​ 4、进行符号计算。
​ 5、带有大量内置函数和常量。
​ 6、也可以用作命令行应用程序。
​ 7、在任何JavaScript引擎上运行。
​ 8、很容易扩展。
​ 9、开源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// functions and constants
math.round(math.e, 3) // 2.718
math.atan2(3, -3) / math.pi // 0.75
math.log(10000, 10) // 4
math.sqrt(-4) // 2i
math.derivative('x^2 + x', 'x') // 2*x+1
math.pow([[-1, 2], [3, 1]], 2)
// [[7, 0], [0, 7]]

// expressions
math.eval('1.2 * (2 + 4.5)') // 7.8
math.eval('12.7 cm to inch') // 5 inch
math.eval('sin(45 deg) ^ 2') // 0.5
math.eval('9 / 3 + 2i') // 3 + 2i
math.eval('det([-1, 2; 3, 1])') // -7

// chaining
math.chain(3)
.add(4)
.multiply(2)
.done() // 14

具体使用详见官网,话说回来我是这样使用的。

1
2
3
4
5
6
// 设置math参数 
math.config({
number: 'BigNumber'
});
let formulaStr = "0.1+0.2"
math.format(math.evaluate(formulaStr)) // 0.3

Vue封装动画插件,渐隐渐现效果

通过js封装的Vue渐隐渐现效果大体两种方法:1、通过Velocity.js 2、原生js写动画

1、通过Velocity.js

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>list transition</title>
<script src="./vue.js"></script>
<script src="./velocity.min.js"></script>
</head>

<body>
<div id="app">
<fade :show="show">
<div>woshi content</div>
</fade>
<button @click="handleBtnClick">qiehunbhzuan</button>
</div>
<script>
Vue.component('fade', {
props: ['show'],
template: `
<transition
@before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
@before-leave="handleBeforeLeave"
@leave="handleLeave"
@after-leave="handleAfterLeave">
<slot v-if="show"></slot>
</transition>
`,
methods: {
handleBeforeEnter(el) {
el.style.opacity = '0'
},
handleEnter(el, done) {
Velocity(
el,
{ opacity: 1 },
{
duration: 1000,
complate: done
}
)
},
handleAfterEnter(el) {},
handleBeforeLeave(el) {},
handleLeave(el, done) {
Velocity(
el,
{ opacity: 0 },
{
duration: 1000,
complate: done
}
)
},
handleAfterLeave(el) {}
}
})

var app = new Vue({
el: '#app',
data: {
show: false
},
methods: {
handleBtnClick() {
this.show = !this.show
}
}
})
</script>
</body>
</html>

自行引入vuejs文件,Velocityjs文件,其中多余的动画钩子函数,可以自行去除。

2、通过原生js

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>list transition</title>
<script src="./vue.js"></script>
<script src="./velocity.min.js"></script>
</head>

<body>
<div id="app">
<fade :show="show">
<div>woshi content</div>
</fade>
<button @click="handleBtnClick">qiehunbhzuan</button>
</div>
<script>
Vue.component('fade', {
props: ['show'],
template: `
<transition
@before-enter="handleBeforeEnter"
@enter="handleEnter"
@after-enter="handleAfterEnter"
@before-leave="handleBeforeLeave"
@leave="handleLeave"
@after-leave="handleAfterLeave">
<slot v-if="show"></slot>
</transition>
`,
methods: {
handleBeforeEnter(el) {
el.style.opacity = '0'
},
handleEnter(el, done) {
el.style.transition = 'all 1s'
setTimeout(() => {
done()
})
},
handleAfterEnter(el) {
el.style.opacity = '1'
},
handleBeforeLeave(el) {},
handleLeave(el, done) {
el.style.opacity = '0'
el.style.transition = 'all 1s'
// setTimeout(() => {
// done()
// }, 1000)
},
handleAfterLeave(el) {}
}
})

var app = new Vue({
el: '#app',
data: {
show: false
},
methods: {
handleBtnClick() {
this.show = !this.show
}
}
})
</script>
</body>
</html>

其中done函数的调用必须是异步的,也就是同步任务之后,这样才可以在动画全部设置之后,在进行下一步。在handleLeave函数中注释了done函数的调用,因为如果调用,动画完成后会销毁组件。

手机端测试html页面

mac上调试手机端,大致分为三种方法。前两种方法虽然使用mac系统,但是windows上操作是基本一样的。

1、利用Hbuilder(mac,windows)

首先打开Hbuilder,如图:

img

打开web服务器,然后如图显示,初始都是设置的默认的内置web服务器,

img

然后点击右下角的外置web服务器设置,然后点击新建,写个名字,url中写本机的ip地址,必须是本机的,这里的ip我是胡编的。如http://192.168.2.6:8020

后边的端口号可以自行调整,就写这个也没什么问题。其他参数不用管,点击确定,发现服务器就添加上了。

img

然后回到web服务器设置的第一界面,将前三个HTML类文件,PHP类文件,RHTML类文件项选择为自己配置的外置服务器即可。然后,直接运行即可,把浏览器中的网址发给手机浏览器打开,即可显示页面。

注意:手机和电脑必须在同一wifi下。

2、使用visual code的live-server扩展(mac,windows)

使用过visual code的同学,肯定使用过live-server把。它默认是127.0.0.1,而这个ip不能联合手机使用。首先打开设置,在上方搜索安装好的live-server插件,输入liveserver就会出来。然后设置上你的计算机的ip地址。

img

再打开go-live时,发现网页ip地址不再是127.0.0.1,然后网址在手机浏览器上打开,就可以显示了。

注意:手机和电脑必须在同一wifi下。

3、使用phpstudy(windows下)

下载phpstudy后,直接设置端口参数,把路径设置成你的项目路径。然后点击启动,即可在手机端打开对应的网址。

注意:手机和电脑必须在同一wifi下。

封装一个函数正则匹配获取当前页面中的class类名

这是一道刷到的面试题,感觉在某些框架里也看到过类似的用法,正则匹配类名,id什么的,当然不一定跟我写的一样,如有更好办法,欢迎分享。

1
2
3
4
5
6
7
8
9
10
function getClass() {
var arr = [];
var str2 = document.getElementsByTagName("html")[0].innerHTML;
var reg = /class=['|"]?([\w+\s]+)['|"]?/g;
var flag1 = str2.replace(reg, function ($0, $1) {
arr.push($1);
});
return arr;
}
console.log(getClass());

言归正传,此题主要考察正则表达式。其中获取页面内容,使用的document.getElementsByTagName(“html”)[0].innerHTML。但这方法,会包括注释里的内容。

函数中正则是匹配class的内容,但是为什么写[‘|”]?呢?因为html中设置class有三种方式:class=”value” class=’value’ class=value ,所以使用非贪婪获取单引号,双引号,或者没有。真正需要的class的值使用小括号当做捕获组内容。然后因为一个元素可能含有多个类名,所以匹配字符和空格,并且是贪婪的(+)。

然后在接下来的replace函数中,将匹配的$1捕获组也就是匹配的小括号内容也就是class里的值添加到数组中,解释一下这里$0返回的是整个的class匹配,也就是正则对象的匹配内容class=”value”这样的。最后返回数组。

移动端内滚动效果

最近看到一个移动端顶部固定,主体部分滚动的效果。但是它不是简单的fixed定位,如果这样滚动条在外侧,即整个页面。

而接下来介绍的这种方法,滚动的是主体部分,可以看到滚动条不会到顶部。

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
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html *{
padding: 0;
margin: 0;
}
.container {
height: 100%;
overflow: hidden;
}
.header {
height: 50px;
background-color: aquamarine;
}
.main {
position: absolute;
top: 50px;
bottom: 0;
left: 0;
right: 0;
background-color: rgb(243, 243, 138);
overflow-y: scroll;
}
.main div {
height: 400px;
}
</style>
</head>

<body>
<div class="container">
<div class="header"></div>
<div class="main">
<div>ddd</div>
<div>ddd</div>
<div>ddd</div>
<div>ddd</div>
</div>
</div>
</body>

</html>

在chrome的f12移动调试模式,可以看到效果。

这里有一篇文章讲这种效果的。 移动端实现内滚动的4种方案 - 知乎

img

新增一种内滚动的方式,之前写react的时候遇到的。样式如下设置:

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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>test inner scroll</title>
<style>
*{
padding: 0;
margin: 0;
}
html,body{
height: 100%;
width: 100%;
position: relative;
overflow: hidden;
}
div#root{
height: 100%;
width: 100%;
position: relative;
display: flex;
}
div.main{
/*height:100%;*/
width: 100%;
overflow-y: scroll;
}
header{
height: 100px;
background-color: antiquewhite;
position: fixed;
width: 100%;
top: 0;
}
section,footer{
height: 1000px;
}
section{
background-color: aquamarine;
}
</style>
</head>
<body>
<div id="root">
<div class="main">
<header></header>
<section></section>
<footer></footer>
</div>
</div>
</body>
</html>

可以看到滚动条,但是实际的滚动条从header下边就开始了,被header挡住了,一般这种情况配合透明色或者浅色的背景header效果不错。这种内滚动中,html,body充当的窗口,而div#root有点特殊,他需要设置display:flex来使后代元素的overflow-y:auto;起作用,个中原理我认为是flex盒子的高度均由内容撑起,并且创建BFC。还有一种方法就是不设置flex而把后代元素的height:100%设置,这样也可以实现。

img

页面切换语言的解决方法(偏向小站,静态页面)

首先在html结构中,把需要转换的结构都加上类名,最好加在含有 文本的最近的父级上,因为我们要利用文本节点来替换。

然后构造出类似json这种感觉的数据,方便替换操作。还有声明一个变量flag,记录当前使用的什么语言。

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
var flag = 'cn';
var langArr = [
{ 'en': '简体中文', 'cn': 'English' },
{ 'en': 'About me', 'cn': '关于我' },
{ 'en': 'Experience', 'cn': '学习经历' },
{ 'en': 'Skill tree', 'cn': '技能树' },
{ 'en': 'Call me', 'cn': '联系我' },
{ 'en': 'Zhuang Cheng Xiang', 'cn': '庄城祥' },
{ 'en': 'I am a Weber who loves life and enjoys learning.', 'cn': '我是一个爱生活,乐学习的Weber' },
{ 'en': 'The beginning of the front end', 'cn': '从零开始的前端' },
{ 'en': 'I have been interested in webpage technology very early,but I have never had a chance and enough time. In the freshman\'s winter vacation,I started to get started. Although the middle of the year has been intermittent,the difficulty has continued to rise, but I have not given up.I am fortunate to have grown up in this era of rapid web development.The ubiquitous tutorials, websites, and almost just beginning to learnare accompanied by the new features of this h5, c3, and ES6, which is exciting.', 'cn': '很早就对网站网页技术有兴趣,但一直没机会和足够的时间。在大一的寒假开始入门,到现在虽然中间断断续续,难度持续攀升,但姑且还没有放弃。我庆幸成长在这个web高速发展的年代。随处可见的教程,网站,几乎刚开始学习就伴随这h5,c3,ES6的新特性,这是令人兴奋的。' },
{ 'en': 'Advanced steps', 'cn': '进阶的步子' },
{ 'en': 'Career has higher requirements, and ever-increasing mobile devices requirea good experience. The browser keeps updating and gradually reaching the specification,and new technologies are applied. This is a challenge for the old technology and a mustfor every front end.', 'cn': '职业有了更高的要求,不断增加的移动设备,更是需要良好的体验。浏览器不停的更新并逐渐达到规范,新技术得以应用。这对旧技术是挑战同时也是每一个前端都是必经之路。' },
{ 'en': 'Road resistance and length', 'cn': '道阻且长' },
{ 'en': 'At the same time, it is even more difficult for novices. The ever-increasing contentof ES6 requires a solid foundation of js, various framework principles, and countlesslibraries. However, the cool page presented to people\'s vision -the sense of accomplishment, gave me reasons to move forward.', 'cn': '同时对于新手,就更是不易。不断增加的ES6内容,需要巩固的js基础,各种框架原理,还有数不清的类库。但是,呈现给人们视野中的炫酷网页——成就感,给了我前进的理由。' },
{ 'en': 'Stronger wings', 'cn': '羽翼渐丰' },
{ 'en': 'The deeper I learn, the more I know that I know less,and it has inspired my passion and interest in learning.Gradually have a general concept of the front end,the goal is more clear. Not impetuous, humbly learning, accumulate richly and break forth vastly.', 'cn': '学的越深入,越知道自己懂得少,更激发了我的学习热情和兴趣。逐渐对前端有了大体的概念,目标更明确。不浮躁,虚心学习,厚积而薄发。' },
{ 'en': 'Roast me', 'cn': '吐槽我吧' },
{ 'en': 'Foundation', 'cn': '基础' },
{ 'en': 'Proficiency in English html,css,javascript', 'cn': '熟练应用html,css,javascript' },
{ 'en': 'Understand jQuery/Nodejs', 'cn': '了解jQuery/Nodejs' },
{ 'en': 'Understand basic web security issues', 'cn': '了解基本web安全问题' },
{ 'en': 'Understand semanticization', 'cn': '了解语义化' },
{ 'en': 'Understand common algorithms', 'cn': '了解常用算法' },
{ 'en': 'Promotion', 'cn': '提升' },
{ 'en': 'Familiar with html5,css3', 'cn': '熟悉html5,css3' },
{ 'en': 'Understand ES6', 'cn': '了解ES6' },
{ 'en': 'Understand sass/less', 'cn': '了解sass/less' },
{ 'en': 'Learn about some browser compatibility issues', 'cn': '了解部分浏览器兼容问题' },
{ 'en': 'Learn about some performance improvement issues', 'cn': '了解部分性能提升问题' },
{ 'en': 'Understand Vue and other mvvm framework', 'cn': '了解Vue等mvvm框架' },
{ 'en': 'Call me', 'cn': '联系我' }
]

接着就是逻辑上了,点击时如果当前语言为中文(cn)则遍历langArr数组,依次对应将文本节点的值替换,这就要求html带有文字结构的顺序必须和数组的语言数据的顺序是一致的。这样才能通过遍历通过对应的序号,替换值。然后替换完后,要把当前的语言状态也修改了,当前为英文(en)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// $(".langSwitch:eq(0)").text(langArr[0].flag);
// var leng1 = $(".langSwitch").length;
var leng2 = langArr.length;
// console.log(leng2);
// console.log(leng1);
// console.log(langArr[0].en);
// console.log($(".langSwitch:eq(0)").text());

// 通过对应的文本节点遍历转换成对应的语言,flag为当前的语言
$(".toggle-inner,.label-text").click(function () {
if (flag == 'cn') {
for (let i = 0; i < leng2; i++) {
$(".langSwitch:eq(" + i + ")").text(langArr[i].en);
}
flag = 'en';
} else {
for (let j = 0; j < leng2; j++) {
$(".langSwitch:eq(" + j + ")").text(langArr[j].cn);
}
flag = 'cn';
}
// console.log("after "+flag);
});

如此一来,一个相对简单的,语言切换就完成了,如图。

你也可以移步到www.peanutone.com

img

img

网上也有其他比较复杂的方法,大多是后端操作,本文仅供参考。

给阿姨来一杯卡普基诺~

支付宝
微信