{
{
}
-S 是 --save的简写
-D 是 --save-dev的简写
development 表示在开发阶段
production表示要上线的项目
none 表示‘无’
执行dev脚本后会在根目录下生成一个dist文件夹,里面包含了生成的main.js文件
,main.js文件大小取决于exports的参数
开发的是有一定要用development,因为最求的是打包的速度,而不是体积
上线的时候一定要用production,因为上线最求得是体积,而不是速度快
在webpack 4.X和5.X的版本中,有如下默认约定:
1.默认的打包入口为src -> index.js
2.默认的输出文件路径为 dist -> main.js
ps:可以在webpack.config.js中修改打包的默认约定
const path = require('path')
module.exports = {
mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目
//entry: //指定要处理那个文件
// __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
entry: path.join(__dirname,'./src/index1.js'),
// 指定生成的文件要放到哪里
output: {
//存放的目录
path: path.join(__dirname,'dist'),
// 生成的文件名
filename: 'bundle.js'
}
}
在开发中使用插件自动打包
npm install [email protected] -D
"scripts": {
//添加serve参数
"dev": "webpack serve"
},
「wds」: Project is running at http://localhost:8080/
表示项目运行的地址
「wds」: webpack output is served from /
生成的js在根目录,但是不会在硬盘中显示,而是生成在内存中,因为内存比硬盘快,所以应当把index.html里的js引用为内存生成的js
/**index.html中**/
<script src="../main.js"></script>
在实际运行中需要进入http://localhost:8080/src/这个路径里面,可以使用html-webpack-plugin插件把src/index.html页面复制到项目根目录里面
npm install [email protected] -D
const path = require('path')
//导入html-webpack-plugin这个插件,得到插件构造函数
const HtmlPlugin = require('html-webpack-plugin')
//new 构造函数,创建插件的实例对象
const htmlPlugin = new HtmlPlugin({
//指定要复制哪个页面
template: './src/index.html',
//复制出来的路径以及存放路径
filename: './index.html'
})
module.exports = {
mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目
//entry: //指定要处理那个文件
// __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
entry: path.join(__dirname,'./src/index.js'),
plugins: [htmlPlugin],
//通过plugin节点,使htmlplugin插件生效
// 指定生成的文件要放到哪里
output: {
//存放的目录
path: path.join(__dirname,'dist'),
// 生成的文件名
filename: 'main.js',
}
}
表示将复制的页面放到主目录里面(内存)
如11所讲
devServer
module.exports = {
mode : 'none', //mode 来指定构建模式 develoment 开发模式 production表示要上线的项目
//entry: //指定要处理那个文件
// __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
entry: path.join(__dirname,'./src/index.js'),
plugins: [htmlPlugin],
//通过plugin节点,使htmlplugin插件生效
// 指定生成的文件要放到哪里
output: {
//存放的目录
path: path.join(__dirname,'dist'),
// 生成的文件名
filename: 'main.js',
},
// devServer
devServer: {
open: true,//初次打包,自动打开浏览器
port:80,//指定端口
host: '127.0.0.2' //指定打开的地址
}
}
在http协议中,端口号80表示默认端口,则端口号在浏览器省略不显示
loader(加载器)
在实际开发过程中,webpack处理不了后缀不是.js结尾的模块,webpack默认是处理不了的,需要调用loader加载器才能正常的打包,否则会报错!
用vue往html页面填充数据
一套现成的解决方案,要遵守框架的规范
vue会监听数据的变化,从而重新渲染页面的结构DOM
OK:数据发生变化,页面重新渲染!
Note:数据驱动是 单向的数据绑定 \color{red}{单向的数据绑定} 单向的数据绑定
在网页中form负责采集数据,Ajax负责 “提交数据”
MVVM 是 数据驱动视图 \color{red}{数据驱动视图} 数据驱动视图和 双向数据 \color{red}{双向数据} 双向数据绑定的核心原理,MVVM是值指的Model、View和View Model它把一个页面拆分成三部分
这里我自己按照视频上面的代码识别不了Vue对象,下面代码贴的开发文档的
<div id="app">{{ message }}div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js">script>
<script>
//这里使用的vue开发文档来创建https://cn.vuejs.org/guide/quick-start.html#using-vue-from-cdn
const { createApp } = Vue
createApp({
data() {
return {
message: 'Hello Vue!'
}
}
}).mount('#app')
script>
Null
指令(Directives)是vue为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。
vue中的指令按照不同的用途可以分为如下6大类:
① 内容渲染 \color{red}{内容渲染} 内容渲染指令
② 属性绑定 \color{red}{属性绑定} 属性绑定指令
③ 事件绑定 \color{red}{事件绑定} 事件绑定指令
④ 双向绑定 \color{red}{双向绑定} 双向绑定指令
⑤ 条件渲染 \color{red}{条件渲染} 条件渲染指令
⑥ 列表渲染 \color{red}{列表渲染} 列表渲染指令
v − t e x t \color{pink}{v-text} v−text
缺点:会覆盖元素内部原有的内容
<p v-text="username">p>
{ { } } 插值表达式 \color{pink}{\{\{\}\}插值表达式} {{}}插值表达式
用来解决覆盖原有内容的问题,实际开发中用的最多
但插值表达式只能用于内容节点,不能用于属性节点
v − h t m l \color{pink}{v-html} v−html
可以渲染标签
v − o n c e \color{pink}{v-once} v−once
可以通过这个指令来一次性的插值,数据改变的时候,这个值不会更新
v − b i n d \color{pink}{v-bind} v−bind
vue规定可以将v-bind:简写为":"(冒号)
在vue中绑定内容可以动态拼接
<div :title="'box'+index">这是一个div</div>
v − o n \color{pink}{v-on} v−on
语法格式为 v-on :事件名称=“事件处理函数名称”
由于v-on在开发中频率很高,简写为 @ \color{red}{@} @
<div id="app">
<p>count的值是{{ count }}</p>
<!-- 语法格式为 v-on :事件名称="事件处理函数名称" -->
<button v-on:click="addCount">+1</button>
</div>
<script src="./vue.global.js"></script>
<script>
const { createApp } = Vue
createApp({
data() {
return {
count:0,
}
},
// methods的作用就是定义事件的处理函数
methods:{
addCount: function(){
//在实际开发中建议使用简写 addCount(){
count++
}
}
}).mount('#app')
</script>
由于业务逻辑代码只有一行所以也可以简写为
<button @click="message++">+1button>
<button @click="message--">-1button>
可以使用一个形参来接收
add(e){
const nowBgc = e.target.style.background;
e.target.style.background = nowBgc ==='red' ? '' : 'red'
this.resu=nowBgc
console.log(nowBgc);
}
$event
e v e n t 是 v u e 提供的特殊变量,表示原生事件参数对象 e v e n t 。 event是vue提供的特殊变量,表示原生事件参数对象event。 event是vue提供的特殊变量,表示原生事件参数对象event。event可以解决事件对象event被覆盖的问题
.prevent 阻止默认行为
----> 阻止a连接的跳转,阻止表单的提交
.stop 阻止事件冒泡
----> 内部盒子点击不会触发外层盒子
.capture
---->从外部开始向内部触发
.once
---->只触发一次
.self
---->如果通过冒泡,则不触发
表按下了enter键则执行submit方法 && 按下了esc键则执行clearInput方法
<input type="text"@keyup.enter="submit"@keyup.esc="clearInput">
v-model数据绑定指令
可以帮助辅助开发者不操作DOM的前提下,快速获取表单的数据
<p>用户名{{username}}p>
<input type="text"@keyup.enter="submit"@keyup.esc="clearInput" v-model="username">
<p>选中的省份是:{{province}}p>
<select v-model="province">
<option value="">请选择option>
<option value="1">重庆option>
<option value="2">广东option>
<option value="3">北京option>
<option value="4">上海option>
select>
注意:v-model指令只能配合表单元素一起使用,不能和p标签a标签不能输入的标签所使用
为了方便对用户内容的输入处理,v-model提供了三个修饰符
v − i f \color{pink}{v-if} v−if
v − s h o w \color{pink}{v-show} v−show
实现的效果
v-if会动态创建和移除DOM元素,从而控制元素在页面上的显示与隐藏
它有更高的性能消耗
v-show指令会动态的为元素添加或移除style="display:none"样式,来控制显示与隐藏
他会有更高的出事消耗开销
频繁的切换,使用v-show更好
反之,使用v-if更好
随机生成0.01~1的数
num:Math.random(),
相当于if–else
<p v-if="num>0.5">大于0.5p>
<p v-else>小于0.5p>
v-else-if相当于switch case语句
v − f o r \color{pink}{v-for} v−for
语法格式:(item,index)in items
item和index都是形参,可更改
<li v-for="(user,i) in list">索引:{{i}}姓名是:{{user.name}}li>
问题:
当列表的数据变化时,默认情况下,vue会尽可能的复用已存在的DOM元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
解决方案:给每一项给一个唯一的key 属性
key所绑定的值,只能是数字型或字符串型
<li v-for="(user,i) in list" :key="list.id">
过滤器(Filter)常用于文本的格式化
“|”被称为管道符
在属性中添加|可以使用过滤器
<p>{{province | capitalize}}p>
过滤器可以用在插值表达式和v-bind属性绑定
过滤器得通过与el节点平齐的filters节点来描述
filters: {
capitalize(str){
return str.charAt(0).toUpperCase()+str.slice(1)
}
}
私有过滤在不被控制的区域不会起作用
可以用下面的例子来声明全局过滤器
<script>
Vue.filter('capitalize',(str)=>{//str是形参
return str.charAt(0).toUpperCase()+str.slice(1)
})
</script>
其中,私有过滤器优先级高于全局过滤器
可以调用多个过滤器
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
<link rel="stylesheet" href="./lib/bootstrap.css" />
<style>
:root {
font-size: 13px;
}
body {
padding: 8px;
}
style>
head>
<body>
<div id="app">
<div class="card">
<h5 class="card-header">添加品牌h5>
<div class="card-body">
<form class="form-inline" @submit.prevent>
<div class="input-group mb-2 mr-sm-2">
<div class="input-group-prepend">
<div class="input-group-text">品牌名称div>
div>
<input type="text" class="form-control" v-model.trim="brandname" @keyup.esc="brandname=''"/>
div>
<button type="submit" class="btn btn-primary mb-2" @click="addNewBrand">添加品牌button>
form>
div>
div>
<table class="table table-bordered table-striped mt-2">
<thead>
<tr>
<th>#switchesth>
<th>品牌名称th>
<th>状态th>
<th>创建时间th>
<th>操作th>
tr>
thead>
<tbody>
<tr v-for="(item,index) in brandlist" :key="item.id">
<td>{{item.id}}td>
<td>{{item.brandname}}td>
<td>
<div class="custom-control custom-switch">
<input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.state">
<label class="custom-control-label" :for="item.id" v-if="item.state">已开启label>
<label class="custom-control-label" :for="item.id" v-else>已禁用label>
div>
td>
<td>{{item.addtime | dateFormat}}td>
<td>
<a href="#" @click.prevent="removeBrand(item.id)">删除a>
td>
tr>
tbody>
table>
div>
<script src="../../vue-2.6.14/dist/vue.js">script>
<script>
//创建全局的过滤器
Vue.filter('dateFormat', (dateStr)=>{
return dateStr
})
const vm = new Vue({
el: '#app',
data: {
brandname:'',
nextId:'5',
brandlist:[
{ id: 1,brandname: '宝马', state: true, addtime:new Date() },
{ id: 2,brandname: '奥迪', state: true, addtime:new Date() },
{ id: 3,brandname: '奔驰', state: true, addtime:new Date() },
{ id: 4,brandname: '山崎', state: true, addtime:new Date() },
]
},
methods: {
// 添加新的品牌数据
addNewBrand(){
if(!this.brandname)
return alert("品牌名不能为空!");
// 添加操作
this.brandlist.push({
id:this.nextId,
brandname:this.brandname,
state:true,
addtime:new Date()
})
this.nextId++,
this.brandname = ''
},
// 根据id删除对应的数据
removeBrand(id){
// 过滤旧数组,形成新数组
this.brandlist=this.brandlist.filter(x => x.id !==id )
}
},
})
script>
body>
html>
是指一个web网站中只有唯一一个html页面,所有的功能和交互都在这一个页面完成
单页面应用程序将所有的功能局限于一个web页面中,仅在该web页面初始化时加载相应的资源(HTML、Javascript和CSS)。
一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转。而是利用JavaScript动态地变换HTML的内容,从而实现页面与用户的交互
node_modules 目录用来存放第三方依赖包
public 是公共的静态资源目录
srC是项目的源代码目录(程序员写的所有代码都要放在此目录下)
.gitignore是Git的忽略文件
index.html是SPA单页面应用程序中唯一的HTML页面
package.json 是项目的包管理配置文件
}
assets目录用来存放项目中所有的静态资源文件(css、fonts等)
components目录用来存放项目中所有的自定义组件
App.vue是项目的根组件
index.css是项目的全局样式表文件
main.js是整个项目的打包入口文件
}
App.vue用来编写待渲染的模板结构
index.html中需要预留一个el区域
main.js把App.vue 渲染到了index.html所预留的区域中
根据封装的思想,把页面上可重用的部分封装为组件,从而方便项目的开发和维护。
例如:Ibootstrap就契合了组件化开发的思想。用户可以通过拖拽组件的方式,快速生成一个页面的布局结构。
Vue是完全支持组件化,开发的,其中后缀名为 . v u e \color{red}{.vue} .vue的文件为组件
template组件模板结构
script组件的javascript行为
css 组件的样式
template不会被渲染成DOM元素,只会起到包裹的作用
在vue3版本中支持多个根节点
可以使用export default导出一个组件
可以通过name指定名称
<script>
export default{
name: 'MyApp1',
}
</script>
指定组件的数据
<template>
<div>
<h1>这是一个vue组件</h1>
<h3>MyName:{{username}}</h3>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default{
name: 'MyApp1',
data(){
return {
username:'晓刘'
}
}
}
</script>
methods方法节点,与data同级
<template>
<div>
<h1>这是一个vue组件</h1>
<h3>MyName:{{username}}</h3>
<p>count的值是:{{count}}</p>
<button @click="add">+1</button>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default{
name: 'MyApp1',
data(){
return {
username:'晓刘',
count:0
}
},
methods: {
add(){
this.count++
}
},
}
</script>
style节点与script节点同级
......
<script>
......
script>
<style>
h1{
color:red;
}
style>
①运行npm install less -D命令安装依赖包,从而提供less 语法的编译支持
②在