本文共 16163 字,大约阅读时间需要 53 分钟。
能够说出什么是前端工程化 | 能够说出 webpack 的作用 | 能够掌握 webpack 的基本使用 | 了解常用 plugin 的基本使用 | 了解常用 loader 的基本使用 | 能够说出 Source Map 的作用 |
---|---|---|---|---|---|
采用工程化的方式来开发前端项目。区别于传统开发,工程化开发会有源文件和目标的概念,在开发阶段写源文件,在发布阶段时,用webpack进行打包,发布。 | 模块打包器。对模块进行打包。 | 1. 先要有一个项目(npm init)。2. 本地安装webpack。3. 根据webpack配置文件要求,去写各类配置:mode, entry, output, devtool, plugin, loader… 最终完成打包功能。 | 1. 安装2.wepback.config.js中去配置plugins. 3.每一个plugin都有自己的操作细节,要单独去学习使用(查官网)。 3. 常用的有:(1)清空打包目录(2)压缩 (3)抽取css到独立文件 (4)复制index.html到目录文件夹 | 1. 作用:去帮助webpack去加载非.js模块。 一个文件类型对应一个Loader。2.使用步骤:(1)下载安装(2)配置module,rules 3.每个Loader的使用细节都不一样。4. 常用的:css-loader, style-loader, less-loader, postcss-loader, file-loader,babel-loader,url-loader | 帮助我们去调试代码。因为源文件打包成目标代码之后(多个文件混成了一个),不方便调试代码。可以用souce-map来对源代码和目标文件之间生成映射关系 |
综合应用: vue, 组件,路由,webpack
功能介绍:
回顾为什么要讲webpack?
用webpack搭建一个支持单文件组件(一个组件就放在一个文件中)的开发环境。
目录结构
建立文件夹,名为heros
,在文件夹下,做npm init --yes
安装需要用到的各种包。
### 开发依赖npm i html-webpack-plugin vue-loader vue-style-loader vue-template-compiler webpack@4.44.2 webpack-cli@3.3.12 webpack-dev-server -D### 生产依赖npm i vue
在根目录下,创建一个名为webpack.config.js的文件,内容如下:
const path = require('path')const VueLoaderPlugin = require('vue-loader/lib/plugin')const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = { // 配置 webpack-dev-server的选项 devServer: { host: '127.0.0.1', // 配置启动ip地址 port: 10088, // 配置端口 open: true // 配置是否自动打开浏览器 }, output: { // 拼接一个绝对路由 path: path.join(__dirname, './dist'), filename: 'bundle.js' }, entry: './src/main.js', // 入口 // 插件来于拓展webpack功能 module: { rules: [ { test: /\.vue$/, use: 'vue-loader' } ] }, plugins:[ new HtmlWebpackPlugin({ minify: { // 压缩HTML文件 removeComments: true, // 移除HTML中的注释 collapseWhitespace: true, // 删除空白符与换行符 minifyCSS: true// 压缩内联css }, filename: 'index.html', // path.resolve()就是转成绝对路径 template: path.resolve('./public/index.html') // 指定模板的位置 }), new VueLoaderPlugin() ]}
在根目录下,创建public/index.html
,内容如下:
Document
在html-webpack-plugin工作时,把它拷贝到指定的出口文件夹下。
在根目录下,创建: src/main.js 。内容如下:
// 入口文件// import es6的模块化, 用来导入另一个模块// 引入根组件import app from './app.vue'// console.log(app)import Vue from 'vue'new Vue({ // 这是Vue的配置项,名是render,值是一个函数。 // 功能: 把app这个组件手挂载到vue实例 ------ vue实例中就只一个根组件 render: function (h) { return h(app) }}).$mount('#app')// #app: 就是public/index.html中的div
在src下面创建app.vue文件, src/app.vue
它的后缀名是.vue,需要在vscode中安装插件(vetur)才可以正确显示出来代码高亮效果。
内容如下:
这是一个vue的组件!!!!!
下面是建议安装vscode拓展:
运行 npm run dev。 这里的dev就是上面在package.json中指定的属性名,当然,你也可以换成其它的名字。
single file component
用一个.vue为后缀的文件来声明一个组件,在webpack的加持下解析这个文件。
// 全局注册组件Vue.component('com-a',{ // 组件配置对象 template: '组件结构'})new Vue({ // 局部注册组件 components: { 'com-b': { // 组件配置对象 template: '组件结构' } }})
无论是何种注册方式,每个组件必须有一个组件配置化对象。
在vue-loader 配合webpack中
.vue文件的格式:
// 相对于组件配置对象中 template 选项,声明组件结构。必须有一个root(根)标签 { {msg}}// 如果有其他的配置选项,需要默认导出一个对象,在对象中声明其他配置选项// 当前组件需要样式
用这种方式定义组件,结构 逻辑 样式 分工明确,非常清晰,便于维护。
单文组件必须要有配置的环境来支持,在浏览器直接使用是不行的。
es6的模块 — 与vue无关
webpack与vue无关
不要认为 学习了es6的模块化,webpack只能在vue中使用!
目标:让一个.js文件(A.js)中可以引用另一个.js文件(B.js)中的代码
模块: 就是一个文件。
模块化的规范:
在nodejs中,模块化规范:CommonJS
module.exports = '导出的内容'
exports.xxx = '导出的内容'
const path = require('path')
nodejs中的模块化与es6中的模块化是不同的。
ES6也提供了模块化规范:ES6模块
export default 导出内容
import 变量名 from 'js模块路径'
export const 成员变量名1 = '导出内容1'
export const 成员变量名2 = '导出内容2'
import {成员变量名1} from 'js模块路径'
(1) 先导出
(2) 再导入
定义模块: src/es6module/a.js
// 创建一个模块// 如何把es6module/a.js中的fn这个函数给main.js中去使用?const a = 100function fn(x,y) { return x + y}
导出模块
// 创建一个模块// 如何把es6module/a.js中的fn这个函数给main.js中去使用?// const a = 100function fn(x,y) { return x + y}// 导出模块中的fnexport { fn }
导入模块
main.js
import { fn } from './es6module/a.js'console.log(fn(100,200)) // 300
module-a.js
// 模块a 默认导出// 可以导出任何格式的内容:字符串 数字 函数 对象 数组 ...export default { name: '模块A', attr: '属性'}
main.js
import obj from './module-a'console.log(obj) // {name: "模块A", attr: "属性"}
module-b.js
// 模块B 按需导出export function fn(x,y) { return x + y}export function fn1(x,y,z) { return x + y +z}export const a = 314
另一种写法:
function fn(x,y) { return x + y}function fn1(x,y,z) { return x + y +z}const a = 314export { fn, fn1, a}
main.js
// 按需导入import { a,b} from './module-b'console.log(a,b)
你要提前知道在导出时,它们是不是叫a,b。
// 按需导入(全部成员导入)import * as all from './module-b'console.log(all) // 收集了所有成员的变量(对象)
module-c.js
// 混合导入// 同时有默认导出和 按需导出const fn = function(x,y) { return x + y}const a = 100const fn1 = function(x,y,z) { return x + y+z}// 按需导出export { a, fn1}// 默认导出export default { fn}
main.js
// 有混合导入import obj, { fn1} from './es6module/c.js'// 有混合导入, 也可以拆开写// import obj from './es6module/c.js'// import {fn1} from './es6module/c.js'console.log(obj,fn1)
一个名字在a.js中导出也是这个名字;
在main.js中也有一个名字与之重复了,此时就要改名字,有两个地方可改名字:
export { xxx as 新名字}# 导入重命名import { xxx as 新名字}
// tool.jsconst fn = function(x,y) { return x + y}// 导出重命名export { fn as f2}// index.jsimport { f2 as f1} from "./tool.js"
直接在public/index.html
中引入bootstrap的样式即可
Document
从示例代码中把基本的html结构复制过来。
container,col-md-2,col-md-10 都是在boostarp.css中要用到的class。
分析布局:
src/components/header.vue
按boostrap样式要求,完成dom
对于.vue而来,如果不写script项,则相当于一个默认导出。
步骤:
侧边栏 col-md-2 bootstrap中的栅格系统路由容器
src/components/sideBar.vue
按boostrap样式要求,完成dom
步骤:
引入vue-router
配置路由规则
在根组件中添加router-view
给左侧添加声明式路由导航
安装vue-router
vue-router是vue的插件,我们通过npm包的方式来加载(在.html中,是通过srcript 的src属性来加载的)
npm i vue-router
导入并注册插件
main.js
import VueRouter from 'vue-router'Vue.use(VueRouter) //注册插件(**重要**)
在src下创建pages文件夹,并在下面放置三个组件,分别表示路由切换时的三个页面:
src/pages/index.vuesrc/pages/add.vuesrc/pages/edit.vue
每个页面组件中,都只需要维持基本内容即可。
导入组件,初始化路由插件,路由规则配置
main.js中
// 提前定义好三个组件,以备在路由中使用import Index from './pages/index.vue'import Add from './pages/add.vue'import Edit from './pages/add.vue'// 创建路由实例,定义路由规则const router = new VueRouter( { routes: [ { path: '/', component: Index }, { path: '/add', component: Add } ]})
new Vue({ render: h => h(App), router: router}).$mount('#app')
App.vue
7.直接在地址栏中进行测试
http://127.0.0.1:10088/#/
http://127.0.0.1:10088/#/add
在components/MyAside.vue中,使用router-link替换之前的a。
英雄列表 装备列表 技能列表
再次点击测试。
1.当前激活的路由导航链接会多出一个特殊的类名:router-link-exact-active
。根据它来设置高亮效果。
对应修改路由配置
// 入口文件// import es6的模块化, 用来导入另一个模块// 引入根组件import app from './app.vue'import Vue from 'vue'import Index from './pages/index.vue'import Add from './pages/add.vue'import Assets from './pages/assets.vue'import Skills from './pages/skills.vue'// 1.导入包import VueRouter from 'vue-router'// 以vue插件的方式去引入vueRouter到vue中// 2. 使用插件Vue.use(VueRouter)// 3.创建路由对象const router = new VueRouter({ routes: [ // 重定向 { path: '/', redirect: '/hero' }, { path: '/hero', component: Index }, { path: '/add', component: Add }, // 装备管理 { path: '/assets', component: Assets }, // 技能管理 { path: '/skills', component: Skills } ]}) // 4. 在vue实例中使用new Vue({ router: router, // 这是Vue的配置项,名是render,值是一个函数。 // 功能: 把app这个组件手挂载到vue实例 ------ vue实例中就只一个根组件 render: function (h) { return h(app) }}).$mount('#app')// #app: 就是public/index.html中的div
分析:
在main.js中涉及路由代码太多,有必须提练一下。
思路:
把与路由相关的代码,提取出来,写在src/router/index.js中;
在main.js中引入它
操作:
(1)新建 src/router/index.js,写入代码如下:
import Vue from 'vue'// 引入路由import VueRouter from 'vue-router'// 注册插件// Vue.use(插件) : 把这个插件的功能集成到vueVue.use(VueRouter)import Index from '../pages/index.vue'import Add from '../pages/add.vue'import Assets from '../pages/assets.vue'import Skills from '../pages/skills.vue'const router = new VueRouter({ routes: [ { path: '/', component: Index }, { path: '/add', component: Add }, { path: '/assets', component: Assets }, { path: '/skills', component: Skills } ]})export default router
注意一下:组件文件的路径关系。
(2) 在main.js中引入
// 入口文件// import es6的模块化, 用来导入另一个模块// 默认导入,引入根组件import app from './app.vue'// console.log(app)// "vue"是我们之前npm i vue时下载的,它相当于是第三个模块,所以不需要加相对路径// 其实,这里的vue来自:node_modules\vue\dist\vue.runtime.common.jsimport Vue from 'vue'import router from './router/index.js'const vm = new Vue({ // render:这是Vue的配置项(el, data,computed....),名是render,值是一个函数。 // 功能: 把app这个组件手挂载到vue实例 ------ vue实例中就只一个根组件 render: function(h) { return h(app) }, router: router})vm.$mount('#app')
json-server 是一个全局安装的工具,用来把.json快速生成RESTful风格的接口。
在前面的学习中,已经全局安装过。
建立目录mockdata,在下面放置一个db.json文件,内容如下:
|-src|-src\mockdata\db.json
内容:
{ "heroes":[ { "id":10000, "heroName": "安妮", "gender": "女", "cTime": "2010-10-10 10:10:10" }, { "id":10001, "heroName": "德玛西亚", "gender": "男", "cTime": "2014-10-10 10:10:10" }, { "id":10002, "heroName": "刘三姐", "gender": "女", "cTime": "Fri Apr 17 2020 16:24:42 GMT+0800 (中国标准时间)" }, { "id":10003, "heroName": "超人", "gender": "男", "cTime": "2020/10/10 10:10:10" } ]}
在 db.json 的位置启动数据接口服务器:json-server db.json
验证一下:
在项目运行过程,不能关闭这个服务。
在项目中通过npm i axios
安装axios,方便我们来获取json-server接口服务器中数据。
之前是<script src='axios的地址'>
来使用axios的,现在要通过第三方包的方式来下载使用。
项目目录下运行如下命令:
npm i axios
结果:
+ axios@0.21.1added 4 packages from 7 contributors in 26.593s
在src/pages/hero/index.vue中,测试axios的使用
通过click事件来测试使用。
在浏览器的network面板观察请求是否发出。
补充一个方法loadHeros用来发ajax请求,获取数据,并保存到数据项中。
在钩子函数 created中调用它
显示数据
文件:src/pages/index.vue
根据数据进行渲染
注意:
实现大致步骤:
src/page/index.vue
补充一个做删除的方法:
hDelete (id) { const res = window.confirm('你确定要删除吗?') if(!res) { return } // json-server时,它会自动会生成restful风格的接口 // 它用来作删除的接口就是这样要求的 axios({ method: 'DELETE', url: 'http://localhost:3000/heroes/' + id }).then(res => { console.log(res) this.loadData() }) },
由于这个添加功能比较复杂,不方便与列表页做在一起,这里单独来设置一个页面组件来实现添加功能。
实现大致步骤:
/add
路由地址。新增文件:src/pages/add.vue
pages/index.vue
添加英雄 或者:添加英雄
heroAdd.vue
实现大致步骤:
/hero/edit/:id
。新增:src/pages/edit.vue
router/index.js
+ import Edit from './pages/edit.vue'const router = new VueRouter({ routes: [ // ...+ { path: '/edit', component: Edit }, ]})
落地项目代码:
src/pages/index.vue
思路:
1.发一次请求,根据id获取这个英雄的详情并显示出来
2.用户在此基础上进行修改,并提交数据。
思路:
发一次请求,根据id获取这个英雄的详情并显示出来
要点:
data () { return { hero: { gender: '', heroName: '' } } },created () { this.loadDetail() }, methods: { loadDetail() { axios({ method: 'GET', url: 'http://localhost:3000/heroes/' + this.$route.query.id }).then(res => { console.log(res) // 保存到数据项中 this.hero.gender = res.data.gender this.hero.heroName = res.data.heroName }) } }
视图
用户在页面上进行修改,点击保存,把改动通过axios调用接口,实现保存。
hModify () { // 收集表单的信息 const { heroName, gender} = this.hero // 检验有效性 if (heroName === '') { alert('名字不能为空') return false } // ajax提交 axios({ method: 'PUT', url: 'http://localhost:3000/heroes/' + this.$route.query.id, data: { heroName, gender, cTime: Date.now() // 获取当前的时间戳 } }).then(res => { // 跳回主页 // console.log(res) this.$router.push('/') }).catch(err => { alert('添加失败') console.log(err) }) }
如有不足,请多指教,
未完待续,持续更新! 大家一起进步!转载地址:http://rcku.baihongyu.com/