前端工程化:
一.ES6
变量与模版字符串
let 和var的差别:
<script>//1. let只有在当前代码块有效代码块. 代码块、函数、全局{let a = 1var b = 2} console.log(a); // a is not defined 花括号外面无法访问console.log(b); // 可以正常输出//2. 不能重复声明let name = '天真'let name = '无邪'//3. 不存在变量提升(先声明,在使用)console.log(test) //可以 但是值为undefinedvar test = 'test'console.log(test1) //不可以 let命令改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。let test1 = 'test1' //4、不会成为window的属性 var a = 100console.log(window.a) //100let b = 200console.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指向的是外层上下文环境的thislet 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上时不需要.valuelet 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
// 一个计算属性 refconst 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一样,都是lastnameconsole.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 {@Overridepublic 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()