前端工程化:
一.ES6
变量与模版字符串
let 和var的差别:
<script>
//1. let只有在当前代码块有效代码块. 代码块、函数、全局
{
let a = 1
var b = 2
}
console.log(a); // a is not defined 花括号外面无法访问
console.log(b); // 可以正常输出
//2. 不能重复声明
let name = '天真'
let name = '无邪'
//3. 不存在变量提升(先声明,在使用)
console.log(test) //可以 但是值为undefined
var test = 'test'
console.log(test1) //不可以 let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
let test1 = 'test1'
//4、不会成为window的属性
var a = 100
console.log(window.a) //100
let b = 200
console.log(window.b) //undefined
</script>
-
const和var的差异
1、新增const和let类似,只是const定义的变量不能修改
2、并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
模板字符串(template string)是增强版的字符串,用反引号(`)标识
1、字符串中可以出现换行符
2、可以使用 ${xxx} 形式输出变量和拼接变量
解构表达式:解构赋值的语法使用花括号 {}
表示对象,方括号 []
表示数组
let [a, b, c] = [1, 2, 3]; //新增变量名任意合法即可,本质是按照顺序进行初始化变量的值
let {a, b} = {a: 1, b: 2};
//新增变量名必须和属性名相同,本质是初始化变量的值为对象中同名属性的值
//等价于 let a = 对象.a let b = 对象.b
//使用 : 操作符指定新的变量名
let {a: x, b: y} = {a: 1, b: 2};
//函数参数解构赋值
function add([x, y]) {
return x + y;
}
add([1, 2]); // 3
箭头函数(类似Java中的Lambda表达式 )
//ES6 允许使用“箭头”(=>)定义函数。
//1. 函数声明
let fn1 = function(){}
let fn2 = ()=>{} //箭头函数,此处不需要书写function关键字
let fn3 = x =>{} //单参数可以省略(),多参数无参数不可以!
let fn4 = x => console.log(x) //只有一行方法体可以省略{};
let fun5 = x => x + 1 //当函数体只有一句返回值时,可以省略花括号和 return 语句
//2. 使用特点 箭头函数this关键字
// 在 JavaScript 中,this 关键字通常用来引用函数所在的对象,
// 或者在函数本身作为构造函数时,来引用新对象的实例。
// 但是在箭头函数中,this 的含义与常规函数定义中的含义不同,
// 并且是由箭头函数定义时的上下文来决定的,而不是由函数调用时的上下文来决定的。
// 箭头函数没有自己的this,this指向的是外层上下文环境的this
let person ={
name:"张三",
showName:function (){
console.log(this) // 这里的this是person
},
viewName: () =>{
console.log(this) // 这里的this是window
}
}
rest参数,在形参上使用 和JAVA中的可变参数几乎一样 :let fun = function (...args){...}}
spread参数,在实参上使用rest:fun1(...arr)
应用:
//应用场景1 合并数组
let arr=[1,2,3]
let arr2=[4,5,6]
let arr3=[...arr,...arr2]
//应用场景2 合并对象属性
let p1={name:"张三"}
let p2={age:10}
let p3={gender:"boy"}
let person ={...p1,...p2,...p3}
对象的创建与拷贝(支持了class extends constructor等关键字 )
浅拷贝:let person2 = person;--指向统一内存
深拷贝:let person2 = JSON.parse(JSON.stringify(person));--通过JSON和字符串的转换形成一个新的对象
模块化处理:分别导出,统一导出,默认导出
分别导出-模块想对外导出,添加export关键字即可(导入-import * as m1 from './module.js';*代表module.js中的所有成员,m1代表所有成员所属的对象)
导入JS文件 添加type='module' 属性,否则不支持ES6的模块化
<script src="./app.js" type="module" />
统一导出
// 统一对外导出(暴露)
export {
PI,
sum,
Person
}
导入:
/*
{}中导入要使用的来自于module.js中的成员
{}中导入的名称要和module.js中导出的一致,也可以在此处起别名
{}中如果定义了别名,那么在当前模块中就只能使用别名
{}中导入成员的顺序可以不是暴露的顺序
一个模块中可以同时有多个import
多个import可以导入多个不同的模块,也可以是同一个模块
*/
import {PI ,Person ,sum,PI as pi,Person as People,sum as add} from './module.js'
默认导出:export default sum
导入:import {default as add} from './module.js'
npm常用命令:
1.项目初始化
-
npm init
-
生成一个package.json 文件
-
-
npm init -y
-
所有信息使用当前文件夹的默认值!
-
2.安装依赖 npm | Home
-
npm install 包名 或者 npm install 包名@版本号
-
安装包或者指定版本的依赖包(安装到当前项目中)
-
-
npm install -g 包名
-
安装全局依赖包
-
-
npm install
-
安装package.json中的所有记录的依赖
-
3.升级依赖
-
npm update 包名
-
将依赖升级到最新版
-
4.卸载依赖
-
npm uninstall 包名
5.查看依赖
-
npm ls
-
查看项目依赖
-
-
npm list -g
-
查看全局依赖
-
6.运行命令
-
npm run 命令是在执行 npm 脚本时使用的命令。npm 脚本是一组在 package.json 文件中定义的可执行命令。npm 脚本可用于启动应用程序,运行测试,生成文档等,还可以自定义命令以及配置需要运行的脚本。
-
在 package.json 文件中,scripts 字段是一个对象,其中包含一组键值对,键是要运行的脚本的名称,值是要执行的命令。
"scripts": { "start": "node index.js", "test": "jest", "build": "webpack" },
-
scripts 对象包含 start、test 和 build 三个脚本。当您运行 npm run start 时,将运行 node index.js,并启动应用程序。同样,运行 npm run test 时,将运行 Jest 测试套件,而 npm run build 将运行 webpack 命令以生成最终的构v建输出。
二.VUE3:
-
声明式渲染:Vue 基于标准 HTML 拓展了一套模板语法,使得我们可以声明式地描述最终输出的 HTML 和 JavaScript 状态之间的关系。
-
响应性:Vue 会自动跟踪 JavaScript 状态并在其发生变化时响应式地更新 DOM
Vite创建Vue3工程化项目(vscode)
- 创建工程:npm create vite@latest; 选择vue+JavaScript选项
- 安装依赖:npm i(安装package.json 中的依赖)
- 启动项目-研发模式:npm run dev
- 停止项目:ctrl+c
Vite+Vue3项目的目录结构:
Vite 项目的入口为 src/main.js 文件,这是 Vue.js 应用程序的启动文件,也是整个前端应用程序的入口文件。在该文件中,通常会引入 Vue.js 及其相关插件和组件,同时会创建 Vue 实例,挂载到 HTML 页面上指定的 DOM 元素中。
SFC:.vue文件对js/css/html统一封装, 该文件由三个部分组成 <script> <template> <style>
-
template标签 代表组件的html部分代码 代替传统的.html文件
-
script标签 代表组件的js代码 代替传统的.js文件
-
style标签 代表组件的css样式代码 代替传统的.css文件(存储的是css代码! <style scoped> 是 Vue.js 单文件组件中用于设置组件样式的一种方式,它的含义是将样式局限在当前组件中,不对全局样式造成影响。)
工程组织:
-
index.html是项目的入口,其中
<div id ='app'></div>
是用于挂载所有组建的元素 -
index.html中的script标签引入了一个main.js文件,具体的挂载过程在main.js中执行
-
main.js是vue工程中非常重要的文件,他决定这项目使用哪些依赖,导入的第一个组件
-
App.vue是vue中的核心组件,所有的其他组件都要通过该组件进行导入,该组件通过路由可以控制页面的切换
Vite+Vue3响应式和setup函数:
响应数据:
<script type="module">
//存储vue页面逻辑js代码
import {ref} from 'vue'
export default{
setup(){
//非响应式数据: 修改后VUE不会更新DOM
//响应式数据: 修改后VUE会更新DOM
//VUE2中数据默认是响应式的
//VUE3中数据要经过ref或者reactive处理后才是响应式的
//ref是VUE3框架提供的一个函数,需要导入
//let counter = 1
//ref处理的响应式数据在js编码修改的时候需要通过.value操作
//ref响应式数据在绑定到html上时不需要.value
let counter = ref(1)
function increase(){
// 通过.value修改响应式数据
counter.value++
}
function decrease(){
counter.value--
}
return {
counter,
increase,
decrease
}
}
}
</script>
<template>
<div>
<button @click="decrease()">-</button>
{{ counter }}
<button @click="increase()">+</button>
</div>
</template>
通过setup函数来省略语句:
<script type="module" setup>
/* <script type="module" setup> 通过setup关键字
可以省略 export default {setup(){ return{}}}这些冗余的语法结构 */
import {ref} from 'vue'
// 定义响应式数据
let counter = ref(1)
// 定义函数
function increase(){
counter.value++
}
function decrease(){
counter.value--
}
</script>
样式导入方式:
-
全局引入main.js
import './style/reset.css'
-
vue文件script代码引入
import './style/reset.css'
-
Vue文件style代码引入
@import './style/reset.css'
Vue3视图渲染技术:
插值表达式:双大括号{{}}和文本表达式:v-xxxx
-
插值表达式是将数据渲染到元素的指定位置的手段之一
-
插值表达式不绝对依赖标签,其位置相对自由
-
插值表达式中支持javascript的运算表达式
-
插值表达式中也支持函数的调用
-
v-*** 这种写法的方式使用的是vue的命令
-
v-***的命令必须依赖元素,并且要写在元素的开始标签中
-
v-***指令支持ES6中的字符串模板:``
-
插值表达式中支持javascript的运算表达式
-
插值表达式中也支持函数的调用
-
v-text可以将数据渲染成双标签中间的文本,但是不识别html元素结构的文本
-
v-html可以将数据渲染成双标签中间的文本,识别html元素结构的文本
属性渲染:渲染元素的属性使用v-bind;语法为 v-bind:属性名='数据名'
事件绑定:v-on
来监听 DOM 事件,并在事件触发时执行对应的 Vue的JavaScript代码
-
用法:
v-on:click="handler"
或简写为@click="handler"
-
vue中的事件名=原生事件名去掉
on
前缀 如:onClick --> click
-
handler的值可以是方法事件处理器,也可以是内联事件处理器(直接对数据进行修改)
-
<!-- 方法事件处理器 --> <button v-on:click="addCount()">addCount</button> <br> <!-- 内联事件处理器 --> <button @click="count++">incrCount</button> <br>
-
绑定事件时,可以通过一些绑定的修饰符,常见的事件修饰符如下
-
.once:只触发一次事件。[重点]
-
.prevent:阻止默认事件。[重点]
-
响应式数据:
ref
可以将一个基本类型的数据(如字符串,数字等)转换为一个响应式对象。 ref
只能包裹单一元素; reactive() 函数创建一个响应式对象或数组(toRef基于reactive响应式对象上的一个属性,创建一个对应的 ref响应式数据。这样创建的 ref 与其源属性保持同步:改变源属性的值将更新 ref 的值,反之亦然。toRefs将一个响应式对象多个属性转换为一个多个ref数据,这个普通对象的每个属性都是指向源对象相应属性的 ref。 )
条件渲染与列表渲染
-
v-if='表达式'
只会在指令的表达式返回真值时才被渲染 -
也可以使用
v-else
为v-if
添加一个“else 区块”。 -
一个
v-else
元素必须跟在一个v-if
元素后面,否则它将不会被识别。 -
v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为display
的 CSS 属性。 -
使用
v-for
指令基于一个数组来渲染一个列表 -
使用
item in items
形式的特殊语法,其中items
是源数据的数组,而item
是迭代项的别名 -
可选的第二个参数表示当前项的位置索引 v-for="(item, index) in items"
计算属性computed
// 一个计算属性 ref
const publishedBooksMessage = computed(() => {
return author.books.length > 0 ? 'Yes' : 'No'
})
数据监听器watch(watcheffect)
-
当数据发生变化时需要执行相应的操作
-
监听数据变化,当满足一定条件时触发相应操作
-
在异步操作前或操作后需要执行相应的操作
<script type="module" setup>
//引入模块
import { ref,reactive,watch} from 'vue'
let firstname=ref('')
let lastname=reactive({name:''})
let fullname=ref('')
//监听一个ref响应式数据
watch(firstname,(newValue,oldValue)=>{
console.log(`${oldValue}变为${newValue}`)
fullname.value=firstname.value+lastname.name
})
//监听reactive响应式数据的指定属性
watch(()=>lastname.name,(newValue,oldValue)=>{
console.log(`${oldValue}变为${newValue}`)
fullname.value=firstname.value+lastname.name
})
//监听reactive响应式数据的所有属性(深度监视,一般不推荐)
//deep:true 深度监视
//immediate:true 深度监视在进入页面时立即执行一次
watch(()=>lastname,(newValue,oldValue)=>{
// 此时的newValue和oldValue一样,都是lastname
console.log(newValue)
console.log(oldValue)
fullname.value=firstname.value+lastname.name
},{deep:true,immediate:false})
//监听所有响应式数据
watchEffect(()=>{
//直接在内部使用监听属性即可!不用外部声明
//也不需要,即时回调设置!默认初始化就加载!
console.log(firstname.value)
console.log(lastname.name)
fullname.value=`${firstname.value}${lastname.name}`
})
</script>
vue生命周期-Vue 组件实例在创建时都需要经历一系列的初始化步骤,比如设置好数据侦听,编译模板,挂载实例到 DOM,以及在数据改变时更新 DOM。在此过程中,它也会运行生命周期钩子的函数
-
onMounted() 注册一个回调函数,在组件挂载完成后执行。
-
onUpdated() 注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用。
-
onUnmounted() 注册一个回调函数,在组件实例被卸载之后调用。
-
onBeforeMount() 注册一个钩子,在组件被挂载之前被调用。
-
onBeforeUpdate() 注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。
-
onBeforeUnmount() 注册一个钩子,在组件实例被卸载之前调用。
组件之间传递数据:
父传子:
//父
<!-- 使用子组件,并且传递数据!通过设置属性传递数据 -->
<Son :message="message" :title="title"></Son>
//子
import {defineProps} from 'vue'
//声明父组件传递属性值,属性值要一致
defineProps({
message: String ,
title: Number
})
子传父:
//子
import {defineEmits} from 'vue'
//1.定义要发送给父组件的方法,可以1或者多个
let emites = defineEmits(['add','sub']);
let data = ref(1);
function sendMsgToParent(){
//2.发父组件对应的方法,调用defineEmites对应的属性
emites('add','add data!'+data.value)
emites('sub','sub data!'+data. Value)
}
<button @click="sendMsgToParent">发送消息给父组件</button>
//父
//自定义接收,子组件传递数据方法! 参数为数据!
const psub = (data) => {
pdata.value = data;
}
<!-- 声明@事件名应该等于子模块对应事件名!调用方法可以是当前自定义!-->
<Son @add="padd" @sub="psub"></Son>
兄弟间传参:子传父-父传子
Vue3路由机制router-资源
promise-异步编程技术
(1)Promise对象代表一个异步操作,有三种状态:`Pending`(进行中)、`Resolved`(已完成,又称 Fulfilled)和`Rejected`(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从`Pending`变为`Resolved`和从`Pending`变为`Rejected`。
1.实例化promise对象,并且执行(类似Java创建线程对象,并且start)
参数: resolve,reject随意命名,但是一般这么叫!
参数: resolve,reject分别处理成功和失败的两个函数! 成功resolve(结果) 失败reject(结果)
参数: 在function中调用这里两个方法,那么promise会处于两个不同的状态
状态: promise有三个状态
pending 正在运行
resolved 内部调用了resolve方法
rejected 内部调用了reject方法
参数: 在第二步回调函数中就可以获取对应的结果
*/
let promise =new Promise(function(resolve,reject){
//resolve("promise success")
//reject("promise fail")
// throw new Error("error message")
})
//2.获取回调函数结果 then在这里会等待promise中的运行结果,但是不会阻塞代码继续运行
promise.then(
function(value){console.log(`promise中执行了resolve:${value}`)},
).catch(
function(error){console.log(error)}
)
async 标识异步函数
-
async标识函数后,async函数的返回值会变成一个promise对象
-
如果函数内部返回的数据是一个非promise对象,async函数的结果会返回一个成功状态 promise对象
-
如果函数内部返回的是一个promise对象,则async函数返回的状态与结果由该对象决定
-
如果函数内部抛出的是一个异常,则async函数返回的是一个失败的promise对象
async function fun1(){
...
}
let promise =fun1()
promise.then(
function(value){
console.log("success:"+value)
}
).catch(
function(value){
console.log("fail:"+value)
}
)
await-
-
await右侧的表达式一般为一个promise对象,但是也可以是一个其他值
-
如果表达式是promise对象,await返回的是promise成功的值
-
await会等右边的promise对象执行结束,然后再获取结果,后续代码也会等待await的执行
-
如果表达式是其他值,则直接返回该值
-
await必须在async函数中
-
如果await右边的promise失败了,就会抛出异常,需要通过 try ... catch捕获处理
axios-资源
三.后端过滤器中设置跨域处理
@WebFilter("/*")
public class CrosFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
System.out.println(request.getMethod());
HttpServletResponse response = (HttpServletResponse) servletResponse;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT,OPTIONS, DELETE, HEAD");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
// 如果是跨域预检请求,则直接在此响应200业务码
if(request.getMethod().equalsIgnoreCase("OPTIONS")){
WebUtil.writeJson(response, Result.ok(null));
}else{
// 非预检请求,放行即可
filterChain.doFilter(servletRequest, servletResponse);
}
}
}
通过pinia状态管理定义共享数据:
import {defineStore } from 'pinia'
//定义数据并且对外暴露
// store就是定义共享状态的包装对象
// 内部包含四个属性: id 唯一标识 state 完整类型推理,推荐使用箭头函数 存放的数据 getters 类似属性计算,存储放对数据
// 操作的方法 actions 存储数据的复杂业务逻辑方法
// 理解: store类似Java中的实体类, id就是类名, state 就是装数据值的属性 getters就是get方法,actions就是对数据操作的其他方法
export const definedPerson = defineStore(
{
id: 'personPinia', //必须唯一
state:()=>{ // state中用于定义数据
return {
username:'张三',
age:0,
hobbies:['唱歌','跳舞']
}
},
getters:{// 用于定义一些通过数据计算而得到结果的一些方法 一般在此处不做对数据的修改操作
// getters中的方法可以当做属性值方式使用
getHobbiesCount(){
return this.hobbies.length
},
getAge(){
return this.age
}
},
actions:{ // 用于定义一些对数据修改的方法
doubleAge(){
this.age=this.age*2
}
}
}
)
----------------------------------------------------------------------
import { createApp } from 'vue'
import App from './App.vue'
import router from './routers/router.js'
// 导pinia
import { createPinia } from 'pinia'
// 创建pinia对象
let pinia= createPinia()
let app =createApp(App)
app.use(router)
// app中使用pinia功能
app.use(pinia)
app.mount('#app')
------------------------------------------------------------------------
import { ref} from 'vue';
import { definedPerson} from '../store/store';
// 读取存储的数据
let person= definedPerson()