目录
前言
俗话说得好 “磨刀不误砍柴工”,一个优秀的项目除了离不开优秀的程序员外,一个好的框架能让项目做起来事半功倍。在下面的文章中将重点介绍为什么在官网的项目中选择了nuxt和tailwind css这两个框架以及其优点。
一、项目的需求
“知己知彼 百战百胜”,框架的选用并不是根据自己喜好而盲目的去选择,只有了解项目的需求,才能更加精准找出合适的框架。
以下是项目的主要需求:
1.官网要做响应式,适应不同尺寸的屏幕。
2. 优化网站结构和内容。
3.代码要规范,并且要求简洁和具有很强的可读性方便后期维护。
二、Tailwind Css
在过去的传统样式中主要面临着以下几个问题:
1. 给标签添加一个样式需要绞尽脑汁想类名,既要语义化,又要符合代码规范,还要和它作用相符合。
2. 每个类中往往会有很多个样式规则,只有结构的语义、样式完全相同时才能做到真正的复用,若存在差异,就难以实现样式复用。
3.如果将 html 或 jsx 结构做迁移,我们同时还要将相应的 css 迁移,迁移后的样式也可能随上下文环境变得错乱。
例如在写以下页面时(图1),通过对比旧官网采用传统样式和新官网采用Tailwind Css。可以直观的看出,在写相同页面时,前者不仅要写多个类名并且存在多个样式规则,难以实现复用。反观后者:
(1)提供了大量的预定义样式类,这些类名都有语义化的名称,例如 bg-red-500
表示背景颜色为红色的样式类。
(2)使用工具类实现样式复用,如 w-1/2
表示元素宽度为父元素的一半,这种方式比传统的 CSS 方式更加简洁明了。
(3)采用基于类名的方式来为 HTML 元素添加样式,而不是直接编写 CSS 代码。这使得开发者只需要关注 HTML 结构和所需的样式类,而无需关心具体的 CSS 样式规则。
图1
旧官网的代码
<article class="g-con">
<section class="g-main">
<a-timeline mode="alternate">
<a-timeline-item v-for="(item, i) in timeData" :key="i">
<template #dot>
<div class="cDot"></div>
<!-- <ClockCircleOutlined style="font-size: 32px" /> -->
</template>
<div class="card">
<div class="card-con">
<div class="fT">
{{ item.fT }}
</div>
<div class="sT">
{{ item.sT }}
</div>
<div class="tT" v-html="item.tT">
</div>
<div class="card-ul" v-if="item.li">
<ul>
<li class=" card-ul-li" v-for="(li, j) in item.li" :key="j + 'li'">
{{ li }}
</li>
</ul>
</div>
</div>
</div>
</a-timeline-item>
</a-timeline>
</section>
</article>
.development {
&-head {
position: relative;
width: 100%;
&-img {
width: 100%;
}
}
.bT {
padding: 60PX;
text-align: center;
}
.con {
padding: 40PX;
.main {
// flex: 0 1 1560Px;
max-width: 1560Px;
margin: 0 auto;
}
}
.cDot {
width: 32Px;
height: 32Px;
background-color: #0092FF;
border-radius: 32Px;
border: 2PX solid rgb(102, 190, 255);
}
.card {
padding: 0 60PX 0 60PX;
&-con {
// max-width: 370PX;
max-width: 100%;
}
.fT {
margin-bottom: 20PX;
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 42Px;
line-height: 16Px;
letter-spacing: 0.1em;
color: #0092FF;
}
.sT {
/* 中标 */
margin-bottom: 20PX;
font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 24Px;
line-height: 29Px;
letter-spacing: 0.1em;
color: #000000;
}
.tT {
margin-bottom: 20PX;
font-family: 'Source Han Sans CN';
font-style: normal;
font-weight: 350;
font-size: 16Px;
line-height: 22Px;
color: #000000;
}
&-ul {
padding: 20PX 40PX;
text-align: left;
background: #F9F9F9;
li:before {
content: "";
width: 8Px;
height: 8Px;
display: inline-block;
border-radius: 50%;
background: #0092FF; //这里不是color
vertical-align: middle;
margin-right: 14Px;
}
}
}
/deep/ {
.ant-timeline-item-right {
.card {
display: flex;
justify-content: flex-end;
}
}
.ant-timeline-item-tail {
left: calc(50% - 2Px) !important;
background: #f0f0f0;
width: 6Px;
}
}
}
</style>
新官网的代码
<!-- 企业发展历程 -->
<div class="mt-[60px]">
<h1 class="text-center text-[38px] font-semibold">企业发展历程</h1>
<div class="mt-[60px]">
<div v-for="(item, index) in milestoneData" :key="item.year" class="flex">
<div class="flex-1 hidden sm:block" :class="{ 'order-1': index % 2 === 1, 'order-3': index % 2 === 0 }"></div>
<div class="mr-[25px] sm:mx-[45px] xl:mx-[90px] sm:order-2 relative">
<div
class="relative z-10 w-[40px] h-[40px] rounded-full bg-[rgba(39,102,213,0.6)] flex justify-center items-center ">
<div class="w-[32px] h-[32px] rounded-full bg-[#2766D5]"></div>
</div>
<div class="absolute z-0 w-[2px] h-full bg-[#CECECE] top-0 left-1/2"></div>
</div>
<div class="flex-1 pb-[20px]" :class="{ 'sm:order-1': index % 2 === 0, 'sm:order-3': index % 2 === 1 }">
<div :class="{ 'sm:text-right': index % 2 === 0 }">
<h2 class="text-[24px] text-[#2766D5] font-semibold">{{ item.year }}</h2>
<h2 class="text-[24px] font-semibold">{{ item.title }}</h2>
<p class="mt-[5px]">{{ item.description }}</p>
</div>
<ul v-if="item.events" class="mt-[20px] p-[20px] bg-[#F9F9F9] list-disc list-inside marker:text-blue-600">
<li v-for="(event, index) in item.events" :key="index">{{ event }}</li>
</ul>
</div>
</div>
</div>
</div>
由此不难看出Tailwind Css使代码看起来更加简洁同时使用起来更加方便。除此之外,Tailwind Css还有一个很大的优点就是遵循响应式设计,提供了多个屏幕尺寸下的样式类,如 sm:text-lg
表示在小屏幕上文字大小为大号。其抛弃了旧官网将代码分成pc端和移动端的写法,直接写样式类这样只需在同一个页面就可以制作出在网站在不同设备下适应屏幕。
Tailwind 提供 5 个断点:
- sm 适用于最小宽度为 640px 的设备;
- md 适用于最小宽度为 768px 的设备;
- lg 适用于最小宽度为 1024px 的设备;
- xl 适用于最小宽度为 1280px 的设备;
- 2xl 适用于最小宽度为 1536px 的设备。
例如在写下面这个页面时(图2),由于需要做响应式,所以就得在不同的尺寸下展示不同的列数:在pc端时展示六列(图2),在平板时展示三列(图3),在手机端时则需要展示两列( 图4),如果使用属性:justify-content:space-between,确实可以让每个模块均匀分布,但是在平板展示时就会出问题(图5),严重影响美观。但是通过样式类结合calc()函数,然后根据该函数计算可以让图片或者模块在不同的尺寸屏幕下展示不同的列数,并且样式不会出现类似图5的问题。
通过图6可以看出来通过样式类与calc()函数结合即
w-[calc(50%-13px)] md:w-[calc(33.33%-20px)] lg:w-[calc(25%-20px)] xl:w-[calc(20%-20px)]
使得图2的六个模块能够在不同尺寸的屏幕下展示不同的列数,这样的写法极大的简化了代码,无需再用两份文件用来装PC端和手机端的代码,同时也方便后期的维护。总的来说,Tailwind CSS 的原理就是通过提供大量预定义的、有语义化的样式类,以及采用基于类名的方式来添加样式,达到快速开发的目的。
Tailwindcss的官方文档: https://tailwindcss.com/docs/installation
三、Nuxt.js
Nuxt是一个基于Vue.js的服务端渲染框架,它能够帮助我们更快地构建SEO友好、高性能的应用程序。Nuxt集成了许多常见的Vue插件和模块,如Vuex、Vue Router和Axios等,使得我们可以轻松地构建单页应用(SPA)或多页应用(MPA)。
下面我们将通过两张图来详细介绍什么是客户端渲染模式和什么是服务端渲染(SSR)
客户端渲染模式
1.根据HTML文件构建DOM树和CSSOM树。构建DOM树期间,如果遇到JS,阻塞DOM树及CSSOM树的构建,优先加载JS文件,加载完毕,在继续构建DOM树和CSSOM树。
2.构建渲染树(Render Tree)。
3.页面重绘(repain)与重排(reflow ,也有称回流)。
页面渲染完成后,若JS操作了DOM节点,根据JS对DOM操作的大小,浏览器对页面进行重绘或是重排。
缺点:1、SEO问题。
2、首屏速度问题。
3、消耗性能问题。
服务端渲染(SSR)
用户输入URL访问页面 -> 服务端接受请求->将对应的请求的数据渲染完一个网页->用户
优点:1、更好的SEO,由于搜索引擎爬虫抓取工具可以直接查看完全渲染的页面。
2、首屏渲染速度快。
SSR简单来说就是将页面在服务端渲染完成后在客户端直接展示。
由于Nuxt 支持服务器端渲染,这意味着应用程序的首次加载时,服务器会将页面直接渲为HTML,并发送给用户的浏览器,这样用户就能够更快地看到页面内容,而不需要等待所有的 JavaScript 和数据都被下载和执行,这样大大减少用户等待时间,提供给用户良好的体验。除此之外,服务端渲染还提高了搜索引擎优化的效果,可以帮助网站在搜索引擎中获得更高的排名,从而增加网站的曝光率和可见度,吸引更多的有意向的用户访问网站,从而提高流量,同时网站可以更好地适应搜索引擎的算法和规则,为用户提供更有价值的内容和更好的用户体验,从而增加用户的满意度和忠诚度,进一步提高网站的流量和转化率。
值得注意的是:Nuxt是一个服务器渲染应用程序,由于在服务器端没有DOM环境,一些生命周期函数(如mounted)可能不会被正常执行。例如:在制作官网加入海普的页面时,由于需要引入高德地图,其中在高德地图组件中就用到了mounted生命周期函数,代码如下
<script>
import AMapLoader from '@amap/amap-jsapi-loader'
export default {
mounted() {
this.initMap();
},
methods: {
initMap() {
AMapLoader.load({
key: "6798352c451bb894f1c78d88e6af0621",
version: "2.0",
plugins: [''],
}).then((AMap) => {
this.map = new AMap.Map("container", {
zoom: 19,
center: [113.95147, 22.554819],
});
},
},
}
</script>
结果页面直接报错“window is not defined”(图7)。
这是因为在引入AMapLoader时,即
import AMapLoader from '@amap/amap-jsapi-loader'
只会在服务端运行 ,由于在服务端中mounted生命周期函数不会被正常执行,所以initMap()方法在服务端不会被执行,因此initMap()方法根本拿不到AMapLoader,这就导致了“window is not defined”错误的出现。其实官方文档有给出解决方案(图8)
可能很多人并不理解官方给的例子,我们不妨将process.client在控制台打印出来(图9)
从打印结果不难看出来,当在客户端时process.client=true,
当在服务端(SSR)时process.client=false
所以通过if(process.client)判断,代码如下
let AMapLoader
if (process.client) {
AMapLoader = require('@amap/amap-jsapi-loader')
}
这样就可以使initMap方法在客户端中拿到AMapLoader。
四、总结
以上就是我对nuxt和tailwind css这两个框架的介绍及其用法,还有所会遇到一些问题跟解决办法。总而言之,Nuxt和Tailwind CSS两个框架都是非常优秀的前端工具,它们分别解决了服务端渲染和CSS样式书写的问题。使用它们可以让我们更快地构建出美观而高性能的应用。