//環境:簡單webpack環境
webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin') // 引入這行
const webpack = require('webpack')
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin')
//將css樣式單獨抽離成一個文件
let MiniCssExtractPlugin = require('mini-css-extract-plugin');
//添加optimize-css-assets-webpack-plugin插件,與uglifyjs-webpack-plugin插件
let OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
let UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const isDev = process.env.NODE_ENV === 'development'
const config = {
mode: 'development',
entry: path.join(__dirname, './src/index.js'),
output: {
filename: 'bundle.js',
//路徑必須是一個絕對路徑
path: path.resolve(__dirname, 'dist')
},
optimization: { //優化項
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true
}),
new OptimizeCSSAssetsPlugin()
],
},
plugins: [
//process.env.NODE_ENV = development 爲一個變量報錯
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: isDev ? '"development"' : '"production"' //Or JSON.stringify('development')
}
}),
//js打包後自動插入模板
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, './src/index.html'),
minify: {
removeAttributeQuotes: true,
collapseWhitespace: true
},
hash: true
}),
new VueLoaderPlugin(),
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
})
],
module: {
//規則 css-loader 解析類似import這種語法的語句
//style-loader 把css插入到head標籤中
//loader的用法:字符串只用一個loader
//loader的特點:單一
//多個loader,需要[]
//loader順序,從右向左,從下到上執行
//loader還可以寫出對象方式
rules: [{
test: /\.vue$/,
loader: 'eslint-loader',
exclude: /node_modules/,
enforce: 'pre'
},
{
test: /\.vue$/i,
use: ['vue-loader']
},
{
test: /\.jsx$/,
loader: 'babel-loader'
},
{
test: /\.js$/,
loader: 'eslint-loader',
enforce: "pre",
include: [path.resolve(__dirname, 'src')], // 指定檢查的目錄
options: { // 這裏的配置項參數將會被傳遞到 eslint 的 CLIEngine
formatter: require('eslint-friendly-formatter') // 指定錯誤報告的格式規範
}
},
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: [
'@babel/preset-env'
],
plugins: [
//注意插件順序
["@babel/plugin-proposal-decorators", {
"legacy": true
}],
//https://www.npmjs.com/package/@babel/plugin-proposal-class-properties
["@babel/plugin-proposal-class-properties", {
"loose": true
}],
//https://babeljs.io/docs/en/babel-plugin-transform-runtime#docsNav
"@babel/plugin-transform-runtime",
],
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}
}
},
{
test: /\.css$/,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader', //給css樣式添加瀏覽器前綴 -moz- ...
]
},
{
test: /\.(jpg|jpeg|png|svg|gif)$/i,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 10 * 1024
}
}
},
{
test: /\.scss$/i,
use: [
// 'style-loader',
MiniCssExtractPlugin.loader,
{
loader:'css-loader',
options:{
importLoaders:1
}
},
// {
// loader: 'postcss-loader',
// options: {
// // nables source map support, postcss-loader will use the previous source map given by other loaders and update it accordingly,
// // if no previous loader is applied before postcss-loader, the loader will generate a source map for you.
// sourceMap: true
// }
// },
{
loader: "postcss-loader",
options: {
ident: 'postcss',
plugins: [
require('autoprefixer')({
'browsers': ['> 1%', 'last 2 versions']
}),
]
}
},
'sass-loader'
]
},
{
test: /\.art$/,
loader: 'art-template-loader'
}
]
}
}
if (isDev) {
config.module.rules.push({
test: /\.styl(us)?$/, //rules裏面修改下匹配styl的正則表達式,文件內寫的lang是等於"stylus"的
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
//nables source map support, postcss-loader will use the previous source map given by other loaders and update it accordingly,
//if no previous loader is applied before postcss-loader, the loader will generate a source map for you.
sourceMap: true
}
},
'stylus-loader'
]
})
config.devtool = '#cheap-nodule-eval-source-map' //webpack官方推薦
config.devServer = {
port: 8888,
contentBase: './build', //指定目錄
progress: true, //打包時顯示進度條
// open:true, //打包後自動打開瀏覽器
host: '0.0.0.0', //可localhost、可IP及手機連接wifi訪問等等
compress: true,
overlay: {
warnings: true,
errors: true
},
hot: true //熱替換
}
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
} else {
config.output.filename = '[name].[chunkhash:8].js' //開發環境會報錯
config.module.rules.push({
test: /\.styl(us)?$/,
use: ExtractTextWebpackPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
{
loader: 'postcss-loader',
options: {
//nables source map support, postcss-loader will use the previous source map given by other loaders and update it accordingly,
//if no previous loader is applied before postcss-loader, the loader will generate a source map for you.
sourceMap: true
}
},
'stylus-loader'
]
})
})
config.plugins.push(
new ExtractTextWebpackPlugin({
//因爲webpack4包含了contenthash這個關鍵字段,所以extarct-text-webpack-plugin中不能使用contenthash
//解決:使用md5:contenthash:hex:8替代
// filename:'styles.[contentHash:8].css'
filename: 'styles.[md5:contenthash:hex:8].css'
})
)
}
module.exports = config
// 構建分頁邏輯所需要的數據(代碼來自慕課網某課程)
// art-template的使用原則:不要在裏面拼接大段的HTML代碼。
// 類似本利中的分頁組件,最好是構造一份適合Handlebars的數據,然後傳給它,來生成html。
formatPag.js
const formatPag = function (pagData) {
var arr = []
var total = parseInt(pagData.totalCount)
var cur = parseInt(pagData.curPage)
// 處理首頁的邏輯:<<
var toLeft = {}
toLeft.index = 1 // index代表點擊按鈕的時候可以跳轉到的頁面
toLeft.text = '«' // text代表button的文本
if (cur !== 1) {
toLeft.clickable = true
}
arr.push(toLeft)
// 處理到上一頁的邏輯
var pre = {}
pre.index = cur - 1
pre.text = '‹'
if (cur !== 1) {
pre.clickable = true
}
arr.push(pre)
var pag
// 處理到cur頁前的邏輯
if (cur <= 5) {
for (var i = 1; i < cur; i++) {
pag = {}
pag.text = i
pag.index = i
pag.clickable = true
arr.push(pag)
}
} else {
// 如果cur>5,那麼cur前的頁要顯示爲...
pag = {}
pag.text = 1
pag.index = 1
pag.clickable = true
arr.push(pag)
pag.text = '...'
arr.push(pag)
// 當前頁前面2個頁數顯示出來
for (var j = cur - 2; j < cur; j++) {
pag = {}
pag.text = j
pag.index = j
pag.clickable = true
arr.push(pag)
}
}
// 處理當前頁
pag = {}
pag.text = cur
pag.index = cur
pag.cur = true
arr.push(pag)
// 處理cur頁後的邏輯
if (cur >= total - 4) {
for (var k = cur + 1; k <= total; k++) {
pag = {}
pag.text = k
pag.index = k
pag.clickable = true
arr.push(pag)
}
} else {
// 如果cur < total - 4, 那麼cur後的頁面顯示爲...
// 顯示以當前頁後面的2個頁數
for (var m = cur + 1; m <= cur + 2; m++) {
pag = {}
pag.text = m
pag.index = m
pag.clickable = true
arr.push(pag)
}
pag = {}
pag.text = '...'
arr.push(pag)
pag = {}
pag.text = total
pag.index = total
pag.clickable = true
arr.push(pag)
}
// 處理到下一頁的邏輯
var next = {}
next.index = cur + 1
next.text = '›'
if (cur !== total) {
next.clickable = true
}
arr.push(next)
// 處理到尾頁的邏輯
var toRight = {}
toRight.index = total // index代表點擊按鈕的時候可以跳轉到的頁面
toRight.text = '»' // text代表button的文本
if (cur !== total) {
toRight.clickable = true
}
arr.push(toRight)
return arr
}
export default formatPag
//page.art
<ul>
{{if data && data.length>0}}
{{each data}}
<li data-id={{$value.index}} {{if $value.cur}} class="cur" {{/if}} {{if $value.clickable}} class="clickable" {{/if}}>{{# $value.text}}</li>
{{/each}}
{{else }}
{{/if}}
</ul>
//page.js
const $ = require('jquery');
const page = require('./page.art');
$.getJSON('http://imoocnote.calfnote.com/inter/getClasses.php', {
curPage: 1
}, function (data) {
console.log(JSON.stringify(formatPag(data)));
var html = page({"data":formatPag(data)});
$("#page").html(html);
});
index.js
import Vue from 'vue'
import App from './app.vue'
// img.src = './meinv.png';就是一個普通字符串
import beauty from './images/profile.jpg'
// import axios from 'axios'
import formatPag from './formatPag.js'
require('@primer/css/buttons/index.scss')
require('@primer/css/utilities/index.scss')
require('./style/page.css')
const img = new Image()// 把圖片引入,返回一個新的圖片地址
img.src = beauty
const root = document.createElement('div')
document.body.appendChild(root)
document.body.appendChild(img)
const $ = require('jquery')
const page = require('./tpl/page.art')
console.log(formatPag)
$.getJSON('http://imoocnote.calfnote.com/inter/getClasses.php', {
curPage: 1
}, function (data) {
console.log(JSON.stringify(formatPag(data)))
var html = page({ data: formatPag(data) })
$('#pag').html(html)
})
new Vue({
// 通過h把App組件掛載到html裏面,這裏只是聲明瞭渲染的是組件App的內容,還需通過$mount掛載到html的一個節點上面
render: (h) => h(App)
}).$mount(root)