為了響應快速開發企業網站,並且能夠適配移動端,完整的使用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項目的代碼結構。
關於接口調用和打包發佈上線的操作
詳細的操作和項目代碼倉庫,放置到個人網站中,如有需要請查看;
- 文章地址:https://shenshuai89.github.io/pages/3926f2/
- 線上預覽地址:https://www.shenshuai.site/nuxtapp202504114/