为了响应快速开发企业网站,并且能够适配移动端,完整的使用tailwind css写一套还挺复杂。
虽然有很多的UI框架,这些框架开发管理系统还可以,有着统一的UI风格,企业网站主要面向C端用户,有着不同设计风格需求,那么之前的bootstrap布局的页面还是很不错的选择。
比如就可以在模板王中下载一套项目代码,通过将内容和文字做一些修改,即可给客户使用。
接下来是改造的过程:
改造最初通过询问AI,给出了2个方案;
- 第一,使用bootstrap-vue-next,然后配合tailwind css进行改造【使用的此方法,改动量很大,放弃】;
- 第二,将js和css文件迁移的public目录下,然后在项目中加载,这样只需要将html文件修改为.vue的文件类型,然后修改很少的链接跳转方式即可。
本文中采用第二种方案。
<font style=“background-color:#D9EAFC;”>迁移过程最痛苦的2件事,在vue中js的加载时机 和 迁移静态资源public/assets。</font>
下载代码
本次改造的项目代码,原模板下载https://www.mobanwang.com/mb/demo/22705/;
也可以下载其他网络上的优秀的企业站代码。
├── about.html
├── assets
│ ├── css
│ │ ├── bootstrap.min.css
│ │ ├── em-breadcrumb.css
│ │ ├── plugin_theme_css.css
│ │ └── responsive.css
│ ├── fonts
│ │ ├── Flaticon.woff
│ │ ├── Flaticon.woff2
│ │ ├── Sofia Pro Bold.ttf
│ │ ├── aprova0698.eot
│ │ ├── aprova0698.svg
│ │ ├── aprova0698.ttf
│ │ ├── aprova0698.woff
│ │ ├── fontawesome-webfont3295.ttf
│ │ ├── fontawesome-webfont3295.woff
│ │ ├── fontawesome-webfont3295.woff2
│ │ ├── icofont.eot
│ │ ├── icofont.svg
│ │ ├── icofont.ttf
│ │ ├── icofont.woff
│ │ ├── icofont.woff2
│ │ ├── themify.ttf
│ │ └── themify.woff
│ ├── images
│ │ ├── about-img-1.jpg
│ │ ├── b1.jpg
│ │ ├── b2.jpg
│ │ ├── b3.jpg
│ │ ├── b4.jpg
│ │ ├── b5.jpg
│ │ ├── b6.jpg
│ │ ├── b7.jpg
│ │ ├── b8.jpg
│ │ ├── blog-sidebar1.jpg
│ │ ├── blog-sidebar2.jpg
│ │ ├── blog-sidebar3.jpg
│ │ ├── br1.jpg
│ │ ├── br2.jpg
│ │ ├── br3.jpg
│ │ ├── br4.jpg
│ │ ├── br5.jpg
│ │ ├── contact-bg.jpg
│ │ ├── faq-img.png
│ │ ├── favicon.png
│ │ ├── fottor-bg.jpg
│ │ ├── logo1.png
│ │ ├── logo2.png
│ │ ├── service-bg-img.jpg
│ │ ├── service-img.png
│ │ ├── single-blog.jpg
│ │ ├── single-service.jpg
│ │ ├── skill-img.jpg
│ │ ├── slide-03.jpg
│ │ ├── slider1.jpg
│ │ ├── slider2.jpg
│ │ ├── tab-img.jpg
│ │ ├── tab-img2.jpg
│ │ ├── tab-img3.jpg
│ │ ├── team-bg.jpg
│ │ ├── team1.jpg
│ │ ├── team1.png
│ │ ├── team2.jpg
│ │ ├── team2.png
│ │ ├── team3.jpg
│ │ ├── team3.png
│ │ ├── team4.png
│ │ ├── test1.png
│ │ ├── test2.png
│ │ ├── test3.png
│ │ └── test4.png
│ ├── js
│ │ ├── BeerSlider.js
│ │ ├── ajax-mail.js
│ │ ├── bootstrap.min.js
│ │ ├── bootstrap.min.js.map
│ │ ├── customizer.js
│ │ ├── imagesloaded.pkgd.min.js
│ │ ├── isotope.pkgd.min.js
│ │ ├── jquery.appear.js
│ │ ├── jquery.knob.js
│ │ ├── jquery.meanmenu.js
│ │ ├── jquery.nivo.slider.pack.js
│ │ ├── jquery.waitforimages.js
│ │ ├── map.js
│ │ ├── modernizr.custom.79639.js
│ │ ├── owl.carousel.min.js
│ │ ├── slick.min.js
│ │ ├── swiper-bundle.min.js.map
│ │ ├── theme-pluginjs.js
│ │ ├── theme.js
│ │ └── vendor
│ │ ├── jquery-3.5.1.min.js
│ │ └── modernizr-2.8.3.min.js
│ └── webfonts
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
├── blog-left-sidebar.html
├── blog-right-sidebar.html
├── blog.html
├── contact.html
├── faq.html
├── home-video.html
├── index.html
├── landing-page.html
├── portfolio-3column.html
├── portfolio-4column.html
├── portfolio.html
├── pricing-table.html
├── service.html
├── single-blog.html
├── single-service.html
├── style.css
├── team.html
├── testimonial.html
└── venobox
├── close.gif
├── next.gif
├── preload-circle.png
├── preload-dots.png
├── preload-ios.png
├── preload-quads.png
├── preload.png
├── prev.gif
├── venobox.css
├── venobox.js
└── venobox.min.js
9 directories, 133 files
迁移静态资源
分为3中情况
- assets下的图片资源,统一存放到
public/assets
下,后边调整代码来获取该路径的资源 - 将assets下的js和css和font资源,放到
public/assets
下的js和css和font
将venobox和style.css文件也迁移到public/assets
下,style.css可以放到public/assets/css
的目录下,<font style=“color:#DF2A3F;”>注意这里需要将</font><font style="color:#DF2A3F;">style.css</font>
<font style=“color:#DF2A3F;”>的图片引用,修改为相对引用地址。</font>
- 将html结尾的文件,复制body部分的代码到vue文件的template中。
关于js脚本加载的问题
在bootstrap中,每个页面为独立html页面,打开都会加载js脚本,并且加载脚本的时间在dom结构渲染完成后进行加载。
那么在改写的vue中,就需要onMounted的生命周期中加载。
在改造过程中尝试了几种方案:
- 写到plugin中,通过
nuxtApp.hook('app:mounted', async () => {})
的生命周期时机进行加载,这种方法对index.vue
页面生效,但是只加载了一次,对其他页面会失效。 - 第二种还是想放到插件中,让每个页面的路由之后,加载js
if (process.client) {
const router = useRouter();
// 监听路由变化,模拟每个页面的 mounted
router.afterEach(async (to, from) => {
console.log('页面 mounted 模拟:', to.path);
// 在这里执行你的逻辑
// 加载脚本、埋点、初始化第三方库等
// const scripts = [
// '/js/vendor/modernizr-2.8.3.min.js',
// '/js/vendor/jquery-3.5.1.min.js',
// '/js/bootstrap.min.js',
// '/js/isotope.pkgd.min.js',
// '/js/owl.carousel.min.js',
// '/js/jquery.nivo.slider.pack.js',
// '/js/slick.min.js',
// '/venobox/venobox.min.js',
// '/js/imagesloaded.pkgd.min.js',
// '/js/jquery.appear.js',
// '/js/jquery.knob.js',
// '/js/BeerSlider.js',
// '/js/theme-pluginjs.js',
// '/js/jquery.meanmenu.js',
// '/js/ajax-mail.js',
// '/js/theme.js',
// ];
// for (const src of scripts) {
// try {
// await loadScript(src);
// console.log('脚本加载成功:', src);
// } catch (err) {
// console.error(err);
// }
// }
});
}
这种方案不能使用<nuxt-link>
标签,使用此标签跳转的页面,还是无法正常加载和显示页面。使用<a>
时可以生效,但是会刷新页面。
也放弃了这个方案
- 使用
composables
下写一个公用的加载js的函数方法,在每个页面的onMounted
周期中调用一下,这算是最好的解决办法。
// 缓存已加载的脚本
const loadedScripts = new Set<string>();
const loadScript = (src: string) => {
return new Promise((resolve, reject) => {
if (loadedScripts.has(src)) {
resolve(true);
return;
}
const script = document.createElement('script');
script.src = src;
script.defer = true;
script.onload = () => {
loadedScripts.add(src);
resolve(true);
};
script.onerror = () => {
reject(new Error(`Failed to load script: ${src}`));
};
document.body.appendChild(script);
});
};
export const loadScriptClient = async () => {
const script1 = document.createElement('script');
script1.src = '/js/vendor/modernizr-2.8.3.min.js';
document.body.appendChild(script1);
const script2 = document.createElement('script');
script2.src = '/js/vendor/jquery-3.5.1.min.js';
document.body.appendChild(script2);
const script3 = document.createElement('script');
script3.src = '/js/bootstrap.min.js';
document.body.appendChild(script3);
const script4 = document.createElement('script');
script4.src = '/js/isotope.pkgd.min.js';
document.body.appendChild(script4);
const script5 = document.createElement('script');
script5.src = '/js/owl.carousel.min.js';
document.body.appendChild(script5);
const script6 = document.createElement('script');
script6.src = '/js/jquery.nivo.slider.pack.js';
document.body.appendChild(script6);
const script7 = document.createElement('script');
script7.src = '/js/slick.min.js';
document.body.appendChild(script7);
const script18 = document.createElement('script');
script18.src = '/venobox/venobox.min.js';
document.body.appendChild(script18);
const script8 = document.createElement('script');
script8.src = '/js/imagesloaded.pkgd.min.js';
document.body.appendChild(script8);
const script9 = document.createElement('script');
script9.src = '/js/jquery.appear.js';
document.body.appendChild(script9);
const script10 = document.createElement('script');
script10.src = '/js/jquery.knob.js';
document.body.appendChild(script10);
const script11 = document.createElement('script');
script11.src = '/js/BeerSlider.js';
document.body.appendChild(script11);
const script12 = document.createElement('script');
script12.src = '/js/theme-pluginjs.js';
document.body.appendChild(script12);
const script13 = document.createElement('script');
script13.src = '/js/jquery.meanmenu.js';
document.body.appendChild(script13);
const script14 = document.createElement('script');
script14.src = '/js/ajax-mail.js';
document.body.appendChild(script14);
const script15 = document.createElement('script');
script15.src = '/js/theme.js';
document.body.appendChild(script15);
};
在vue的页面中进行调用
// 初始化脚本
onMounted(() => {
loadScriptClient();
})
关于图片资源引用的问题
public/css内部应用的图片路径地址
public/assets/css内部应用的图片路径地址,是public/assets/images中的资源;
.consit_service_area2 {
background-image: url("../images/port-bg-img.jpg");
background-repeat: no-repeat;
background-size: cover;
padding: 120px 0px 110px;
}
vue文件的template的图片
template模版内的图片引入:
- 使用
"/assets/images/logo1.png"
的也是public/assets/images
目录的资源。 - 如果代码
"assets/images/logo1.png"
则是使用了assets/images
目录资源
<template>
<div class="mobile_menu_logo text-center">
<a href="index.html" title="consit">
<img src="/assets/images/logo1.png" alt="consit" />
</a>
</div>
</template>
vue文件的template的style中使用图片
在template中的style添加背景图片,这里如果正常使用/assets/images/logo1.png
,就会引用到/assets/images的资源,而不是public/assets/image的资源。
下面代码引用了 assets/image
的资源
这里不管有没有 /
路径,都是使用的 assets/image
<template>
<div
class="swiper-slide d1 t1 m1 witr_swiper_height"
style="background-image: url(/assets/images/slider1.jpg)"
>
1111
</div>
</template>
可以结合script,使用public的资源;
主要思路是通过动态导入图片资源,然后在绑定到style中
<template>
<div
class="swiper-slide d1 t1 m1 witr_swiper_height"
:style="{ backgroundImage: `url(${slider1})` }"
>
1111
</div>
</template>
<script setup>
// vue script内引入assets图片的方法
import slider1 from '/assets/images/slider1.jpg';
</script>
迁移完成后代码结构
./
├── README.md
├── app.vue
├── components
│ ├── navFooter.vue
│ └── navHeader.vue
├── composables
│ └── index.ts
│── nuxt.config.ts
├── package.json
├── pages
│ ├── about.vue
│ ├── blog.vue
│ ├── blogLeft.vue
│ ├── blogRight.vue
│ ├── contact.vue
│ ├── faq.vue
│ ├── homeVideo.vue
│ ├── index.vue
│ ├── landingPage.vue
│ ├── portfolio.vue
│ ├── portfolio3column.vue
│ ├── portfolio4column.vue
│ ├── pricingTable.vue
│ ├── service.vue
│ ├── serviceSingle.vue
│ ├── singleBlog.vue
│ ├── team.vue
│ └── testimonial.vue
├── plugins
│ └── load-script.client.ts
├── pnpm-lock.yaml
├── public
│ ├── assets
│ │ └── images
│ │ ├── about-img-1.jpg
│ │ ├── b1.jpg
│ │ ├── b2.jpg
│ │ ├── b3.jpg
│ │ ├── b4.jpg
│ │ ├── ...
│ │ ├── css
│ │ │ ├── bootstrap.min.css
│ │ │ ├── em-breadcrumb.css
│ │ │ ├── plugin_theme_css.css
│ │ │ ├── responsive.css
│ │ │ └── style.css
│ │ ├── fonts
│ │ │ ├── Flaticon.woff
│ │ │ ├── ...
│ │ ├── js
│ │ │ ├── BeerSlider.js
│ │ │ ├── ajax-mail.js
│ │ │ ├── ...
│ │ ├── venobox
│ │ │ ├── close.gif
│ │ │ ├── next.gif
│ │ │ ├── preload-circle.png
│ │ │ ├── preload-dots.png
│ │ │ ├── preload-ios.png
│ │ │ ├── preload-quads.png
│ │ │ ├── preload.png
│ │ │ ├── prev.gif
│ │ │ ├── venobox.css
│ │ │ ├── venobox.js
│ │ │ └── venobox.min.js
│ │ └── webfonts
│ │ ├── fa-brands-400.eot
│ │ ├── fa-brands-400.svg
│ │ ├── ...
│ ├── favicon.ico
│ ├── favicon.png
│ ├── robots.txt
└── tsconfig.json
29 directories, 146 files
以上是将bootstrap项目转为nuxt项目的代码结构。
关于接口调用和打包发布上线的操作
详细的操作和项目代码仓库,放置到个人网站中,如有需要请查看;