一:準(zhǔn)備工作
1、項(xiàng)目結(jié)構(gòu)
compnents文件夾 存放整個項(xiàng)目公共的組件
assets文件夾 存放樣式和字體圖標(biāo)
api文件夾 存放請求文件
pages文件夾存放項(xiàng)目頁面
pages文件夾中有conponents存放的是頁面級的公共組件
2鳖粟、搭建開發(fā)環(huán)境
- 初始化項(xiàng)目
npm init
2)安裝開發(fā)依賴
npm install --save-dev css-loader@4.2.1 style-loader@1.2.1 file-loader@6.0.0 url-loader@4.1.0
3)安裝生產(chǎn)依賴
npm install art-template@4.13.2 swiper@6.1.1
4)修改scripts屬性值
"start": "webpack-dev-server --open chrome"
3删铃、配置webpack.config.js文件
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 獲取絕對路徑
const resolve = dir => path.resolve(__dirname, dir);
module.exports = {
mode: 'development',
// Webpack 入口文件
entry: {
index: './src/pages/index',
destination: './src/pages/destination'
},
// Webpack 輸出路徑
output: {
// 輸出的目錄
path: resolve('dist'),
// 輸出的文件名
filename: 'js/[name].js'
},
// source-map踱蠢,調(diào)試用的,出錯的時候,將直接定位到原始代碼阵谚,而不是轉(zhuǎn)換后的代碼
devtool: 'cheap-module-eval-source-map',
resolve: {
// 自動補(bǔ)全(可以省略)的擴(kuò)展名
extensions: ['.js'],
// 路徑別名
alias: {
api: resolve('src/api'),
icons: resolve('src/assets/icons'),
styles: resolve('src/assets/styles'),
components: resolve('src/components'),
pages: resolve('src/pages'),
utils: resolve('src/utils')
}
},
// 不同類型模塊的處理規(guī)則
module: {
rules: [
// css
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 模板文件
{
test: /\.art$/,
loader: 'art-template-loader'
},
// 圖片
{
test: /\.(png|jpe?g|gif|svg)$/,
loader: 'url-loader',
options: {
// 小于 10K 的圖片轉(zhuǎn)成 base64 編碼的 dataURL 字符串寫到代碼中
limit: 10000,
// 其他的圖片轉(zhuǎn)移到
name: 'images/[name].[ext]',
esModule: false
}
},
// 字體文件
{
test: /\.(woff2?|eot|ttf|otf)$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'fonts/[name].[ext]'
}
}
]
},
plugins: [
// 自動將依賴注入 html 模板钞翔,并輸出最終的 html 文件到目標(biāo)文件夾
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/pages/index/index.art',
chunks: ['index']
}),
new HtmlWebpackPlugin({
filename: 'destination.html',
template: './src/pages/destination/destination.art',
chunks: ['destination']
})
]
};
二严卖、首頁開發(fā)
1、頭部組件布轿,下方代碼是components/header/index.js
import './header.css';
// 需要添加的類名
const CHANGED_CLASS_NAME = 'header-transition';
// 初始狀態(tài)哮笆,主要是為了防止多次觸發(fā)的問題
const INIT_STATE = 'init';
// 改變狀態(tài),主要是為了防止多次觸發(fā)的問題
const CHANGED_STATE = 'changed';
// 添加Header類
class Header {
// 需要傳遞四個參數(shù)
// 1:元素汰扭,2稠肘、距離,3萝毛、滾動條所在的元素项阴,4、綁定事件的元素
constructor(el, critical_point, scrollContainer, eventEl = scrollContainer) {
this.el = el;
this.critical_point = critical_point;
// 滾動條所在的容器
this.scrollContainer = scrollContainer;
// 監(jiān)聽滾動事件的元素
this.eventEl = eventEl;
// 調(diào)整狀態(tài)
this.setState(INIT_STATE);
// 綁定事件
this.bindEvent();
}
// 設(shè)置狀態(tài)
setState(state) {
this.state = state;
}
// 綁定事件
bindEvent() {
this.eventEl.addEventListener(
'scroll',
() => {
if (this.needChange()) {
this.setState(CHANGED_STATE);
this.change();
} else if (this.needReset()) {
this.setState(INIT_STATE);
this.reset();
}
},
false
);
}
// 重置笆包,去掉類名
reset() {
this.el.classList.remove(CHANGED_CLASS_NAME);
}
// 不是初始的狀態(tài)环揽,并且滾動的距離大于等于設(shè)定的距離
needReset() {
return (
this.state !== INIT_STATE &&
this.scrollContainer.scrollTop <= this.critical_point
);
}
// 變化,添加類名
change() {
this.el.classList.add(CHANGED_CLASS_NAME);
}
// 需要變化庵佣,不是已改變的狀態(tài)歉胶,并且滾動的距離小于設(shè)定的距離
needChange() {
return (
this.state !== CHANGED_STATE &&
this.scrollContainer.scrollTop > this.critical_point
);
}
}
// 導(dǎo)出頂部
export default Header;
使用Header類,下方代碼是pages/index/components/header/index.js
import Header from 'components/header';
const scrollContainer = document.getElementById('index-page');
const headerEl = scrollContainer.querySelector('.header');
new Header(headerEl, 0, scrollContainer);
2、幻燈片組件
下方代碼是:pages/index/components/slider/config.js
// Swiper 配置
export default {
// 循環(huán)模式選項(xiàng)
loop: true,
// 是否需要分頁器
pagination: {
el: '.swiper-pagination'
}
// 是否需要前進(jìn)后退按鈕
// navigation: {
// nextEl: '.swiper-button-next',
// prevEl: '.swiper-button-prev'
// },
// 是否需要滾動條
// scrollbar: {
// el: '.swiper-scrollbar'
// }
};
export const SWIPER_CONTAINER_CLASS = '.swiper-container';
使用幻燈片巴粪,下方代碼是:pages/index/components/slider/index.js
// 引入css
import 'swiper/swiper-bundle.min.css';
import './slider.css';
// 引入js
import Swiper from 'swiper/swiper-bundle.min';
// 引入配置文件
import config, { SWIPER_CONTAINER_CLASS } from './config';
// https://www.swiper.com.cn/api/index.html
// 實(shí)例化
new Swiper(SWIPER_CONTAINER_CLASS, config);
3通今、導(dǎo)航組件
下方代碼是:pages/index/components/nav/config.js
export const URL = 'https://www.imooc.com/api/mall-wepApp/index/nav';
export const LAYOUT_ID = 'index-nav';
下方代碼是:pages/index/components/nav/index.js
import './nav.css';
// 引入模板
import render from './nav.art';
// ajax請求
import { getData, getDelayedData } from 'api/getData';
// 請求地址和盛放結(jié)構(gòu)的元素
import { URL, LAYOUT_ID } from './config';
// https://www.imooc.com/api/mall-wepApp/index/nav
getData(URL).then(data => {
document.getElementById(LAYOUT_ID).innerHTML = render({
items: data
});
});
4、返回頂部
Backtop 組件肛根,下方代碼是:下方代碼是components/backtop/index.js
import './backtop.css';
import 'icons/iconfont.css';
const CHANGED_CLASS_NAME = 'backtop-hidden';
const INIT_STATE = 'init';
const CHANGED_STATE = 'changed';
class Backtop {
constructor(el, critical_point, scrollContainer, eventEl = scrollContainer) {
this.el = el;
this.critical_point = critical_point;
// 滾動條所在的容器
this.scrollContainer = scrollContainer;
// 監(jiān)聽滾動事件的元素
this.eventEl = eventEl;
this.setState(INIT_STATE);
this.bindEvent();
}
// 設(shè)置狀態(tài)
setState(state) {
this.state = state;
}
// 綁定事件
bindEvent() {
this.eventEl.addEventListener(
'scroll',
() => {
if (this.needChange()) {
this.setState(CHANGED_STATE);
this.change();
} else if (this.needReset()) {
this.setState(INIT_STATE);
this.reset();
}
},
false
);
this.el.addEventListener(
'click',
() => {
this.scrollTo();
},
false
);
}
scrollTo(top = 0, left = 0) {
this.scrollContainer.scrollTo({
top,
left,
behavior: 'smooth'
});
}
reset() {
this.el.classList.add(CHANGED_CLASS_NAME);
}
needReset() {
return (
this.state !== INIT_STATE &&
this.scrollContainer.scrollTop <= this.critical_point
);
}
// 變化
change() {
this.el.classList.remove(CHANGED_CLASS_NAME);
}
// 需要變化
needChange() {
return (
this.state !== CHANGED_STATE &&
this.scrollContainer.scrollTop > this.critical_point
);
}
}
export default Backtop;
使用返回頂部組件,下方代碼是:pages/index/components/backtop/index.js
import Backtop from 'components/backtop';
const scrollContainer = document.getElementById('index-page');
const backtopEl = scrollContainer.querySelector('.backtop');
new Backtop(backtopEl, window.innerHeight, scrollContainer);