简介
vue是指一个用于创建用户界面的渐进式框架,旨在更好地组织与简化Web开发;Vue的核心库只关注视图层,并且非常容易学习,也非常容易与其他库或已有项目整合。
vue框架介绍
Vue.js(读音/vju:/,发音类似于view)是一套构建用户界面的渐进式框架。与其他重量级框架不同的是,Vue 采用自底向上增量开发的设计。
Vue 的核心库只关注视图层,并且非常容易学习,也非常容易与其他库或已有项目整合。Vue 完全有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用。
Vue.js 还提供了 MVVM 数据绑定和一个可组合的组件系统,具有简单、灵活的 API,其目标是通过尽可能简单的 API 实现响应式的数据绑定和可组合的视图组件。
我们也可以说 Vue.js 是一套响应式系统(Reactivity System)。数据模型层(Model)只是普通 JavaScript 对象,如下图所示,{ }代表一个 JavaScript 对象,修改它则更新相应的 HTML 片段(DOM),这些 HTML 片段也称为“视图(view)”。这会让状态管理变得非常简单且直观,可实现数据的双向绑定,所以我们也称之为响应式系统。
作为前端开发人员的首选入门框架,Vue 有很多优势:
-
Vue.js 可以进行组件化开发,使代码编写量大大减少,读者更加易于理解。
-
Vue.js 最突出的优势在于可以对数据进行双向绑定(在之后的编写中我们会明显地感觉到这个特点的便捷)。
-
使用 Vue.js 编写出来的界面效果本身就是响应式的,这使网页在各种设备上都能显示出非常好看的效果。
-
相比传统的页面通过超链接实现页面的切换和跳转,Vue 使用路由不会刷新页面
案例体验
计数器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button @click="num++">{{num}}</button>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.js"></script>
<script>
const {createApp,reactive,toRefs} = Vue
createApp({
setup(){
const data =reactive({
num:1
})
return{...toRefs(data)}
}
}).mount('#app')
</script>
列表展示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script type="text/javascript" src="js/vue.global.js"></script>
<body>
<div id="app">
<p v-for="b in booklist">{{b}}</p>
</div>
</body>
</html>
<script>
const {createApp,reactive,toRefs} = Vue
createApp({
setup(){
const data =reactive({
booklist:['宿舍','钉钉','嗯嗯']
})
return{...toRefs(data)}
}
}).mount('#app')
</script>
输入框
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<script type="text/javascript" src="js/vue.global.js"></script>
<body>
<div id="app"><button @click="addName">增加</button>
{{name}}
<input type="text" v-model="name">
</div>
</body>
</html>
<script>
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data =reactive({
name:'呜呜呜呜呜呜'
})
const addName=()=>{
data.name+="huhuhuhuhu";
}
return{...toRefs(data),addName}
}
}).mount('#app');
</script>
MvvM模式
MVVM是Model-View-ViewModel的简写。它本质上就是MVC的改进版。MVVM模式有助于将应用程序的业务和表示逻辑与用户界面 (UI) 清晰分离。 保持应用程序逻辑和UI之间的清晰分离有助于解决许多开发问题,并使应用程序更易于测试、维护和演变。 它还可以显著提高代码重用机会,并允许开发人员和UI设计人员在开发应用各自的部分时更轻松地进行协作
MVVM是ModelView-ViewModel的简写。它本质上就是MVC (ModelView- Controller) 的改进版,即模型-视图-视图模型。
模型:指的是后端传递的数据,data....
英,
视图: 指的是所看到的页面。
视图模型: mvvm模式的核心,"它是连接view和model的桥梁。
它有两个方向:
一是将[模型] 转化成[视图],即将后端传递的数据转化成所看到的页面。实现的方式是: 数据绑定。二是将[视图] 转化成[模型],即将所看到的页面转化成后端的数据。实现的方式是: DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
总结:在MWM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,
然后通知数据做改动,这实际上就实现了数据的双向绑定。并目MVVM中的View 和 ViewModel可以互相通信。
特点
MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model),有几大优点
1. 低耦合。视图(View)可以独立于Model变化和修改,一个ViewModel可以绑定到不同的"View"上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变。
2. 可重用性。可以把一些视图逻辑放在一个ViewModel里面,让很多view重用这段视图逻辑。
3. 独立开发。开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计,使用Expression Blend可以很容易设计界面并生成xaml代码。
4. 可测试。界面素来是比较难于测试的,测试可以针对ViewModel来写。
使用MVVM来开发用户控件。由于用户控件在大部分情况下不涉及到数据的持久化,所以如果将M纯粹理解为DomainModel的话,使用MVVM模式来进行自定义控件开发实际上可以省略掉M,变成了VVM。
理论基础
MVVM旨在利用WPF中的数据绑定函数,通过从视图层中几乎删除所有GUI代码(代码隐藏),更好地促进视图层开发与模式其余部分的分离。不需要用户体验(UX)开发人员编写GUI代码,他们可以使用框架标记语言(如XAML),并创建到应用程序开发人员编写和维护的视图模型的数据绑定。角色的分离使得交互设计师可以专注于用户体验需求,而不是对业务逻辑进行编程。这样,应用程序的层次可以在多个工作流中进行开发以提高生产力。即使一个开发人员在整个代码库上工作,视图与模型的适当分离也会更加高效,因为基于最终用户反馈,用户界面通常在开发周期中经常发生变化,而且处于开发周期后期。
MVVM模式试图获得MVC提供的功能性开发分离的两个优点,同时利用数据绑定的优势和通过绑定数据的框架尽可能接近纯应用程序模型。它使用绑定器、视图模型和任何业务层的数据检查功能来验证传入的数据。结果是模型和框架驱动尽可能多的操作,消除或最小化直接操纵视图的应用程序逻辑(如代码隐藏)。
vue语法
mustache语法
Mustache 是一款的前端模板引擎,它原本是基于 javascript 实现的,但是因为轻量易用,所以经过拓展目前支持更多的平台,如java,PHP,C++等、Mustache 主要用于在表现和数据相分离的前端技术架构中,根据数据生成特定的动态内容,实际作用和E1表达式一样为了接收渲染数据,但是比EL更加强大。
首先展示整体的代码案列:
<body>
<div id="app"></div>
<template id="my-app">
<!-- 1 mustache的基本应用 -->
<h2>{{ message }} - {{ message }}</h2>
<!-- 2 这是一个表达式 -->
{{message * 10}}
{{message.split(" ").reverse().join(" ")}}
<!-- 3 可以调用函数 -->
<!-- 可以使用computed(计算属性) -->
<h2>{{getReverseMessage()}}</h2>
<!-- 4 三元计算 -->
<h2>{{isShow ? "小老虎" : ""}}</h2>
<button @click="toggle">切换</button>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
message: "Hello Word",
counter: 100,
isShow: true
}
},
methods: {
getReverseMessage() {
// split 分割; reverse 反转;join 连接
return this.message.split(" ").reverse().join(" ");
},
toggle() {
this.isShow = !this.isShow;
}
}
}
Vue.createApp(App).mount('#app');
</script>
</body>
语法规则:
{{ data中的对象变量名/表达式的计算/方法名/三元计算 }}
作用:
(1)直接数据展示
{{ message }}
2)表达式的计算
{{message * 10}}
{{message.split(" ").reverse().join(" ")}} <!-- 分割反转连接-->
(3)调用函数、计算属性
{{ getReverseMessage() }}
(4)三元计算
{{isShow ? "小老虎" : ""}}
为什么在data定义好数据后,可以直接使用mustache语法进行数据的展示?
因为当我们创建了data后,vue就会将data存放于响应模板中,类似于java中的spring容器,之后在使用的过程中直接拿取便可
v-once指令
v-once用于指定元素或者组件只渲染一次。当数据发生变化时,元素或者组件以及其所有的子元素将视为静态内容并且跳过
<body>
<div id="app"></div>
<template id="my-app">
<h2>{{counter}}</h2>
<!-- 使用了 v-once 后 点击加一,下面的counter数字不会发生变化,默认只渲染一次 -->
<div v-once>
<h2>{{counter}}</h2>
<h2>{{message}}</h2>
</div>
<button @click="increment">+1</button>
</template>
<script src="../js/vue.js"></script>
<script>
const App = {
template: '#my-app',
data() {
return {
counter: 100,
message: "abc"
}
},
methods: {
increment() {
this.counter++;
}
}
}
Vue.createApp(App).mount('#app');
</script>
</body>
v-text
作用和{{}}类似,但是书写不一致。开发中用{{}}较多
v-html
默认情况下,如果我们展示的内容本身是 html 的,那么vue并不会对其进行特殊的解析。如果我们希望这个内容被Vue可以解析出来,那么可以使用 v-html 来展示。
v-pre
v-pre用于跳过元素和它的子元素的编译过程,显示原始的Mustache标签。就是页面中 所见即所得
v-cloak
这个指令保持在元素上直到关联组件实例结束编译。有的时候浏览器加载完毕,但是{{}}展示的内容还没有编译完毕,在页面上可能会出现短暂的展示 {{变量}} ,之后再显示最终的结果值,为了避免这中现象,先设置其样式不展示,直到全部编译完成后再进行展示。
v-bind
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.t{
border-radius: 100px;
}
</style>
</head>
<body>
<div id="app">
<div :class="div_class" v-bind:style="div_style">wwwwwwwwwwwwwwww</div>
<br>
<input type="text" :value="input_value"> <br>
<a :href="a_href"></a> <br>
<button :type="button_type">点我</button> <br>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
div_style: 'width: 200px;height: 200px;background-color: red',
div_class: 't',
input_value: '今天是个快乐的日子',
a_href: 'www.baidu.com',
button_type: 'submit'
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
语法糖 语法糖就是vue提供的简化写法,对于v-bind可以直接:属性即可
<a :href="link" target="_blank">大力出奇迹</a>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
.cr{
border-radius: 25px;
background-color: darkcyan;
cursor: pointer;
}
</style>
</head>
<body>
<div id="app">
<!--<div class="cr" :style="{width:w+'px',height:h+'px'}" v-on:click="checkDiv"></div>-->
<div class="cr" :style="getStyle()" v-on:click="checkDiv()"></div>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
w:50,
h:50
})
//方法
const checkDiv = () => {
data.w += 10
data.h += 10
}
const getStyle = () => {
return {width:data.w+'px',height:data.h+'px'}
}
return {...toRefs(data),checkDiv,getStyle}
}
}).mount('#app')
</script>
计算属性
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{computedChineseName}} 5000QPS
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs,computed} = Vue
const app = createApp({
setup(){
const data = reactive({
chineseName: ["萨姆1","小乖"]
})
//方法
const isChinese = () => {
return data.chineseName.length > 0 ? '有中文':'没有中文'
}
//计算属性
const computedChineseName = computed(() => data.chineseName.length > 0 ? '有中文':'没有中文')
return {...toRefs(data),isChinese,computedChineseName}
}
}).mount('#app')
</script>
普通方法和计算属性的区别: 我们可以看到两种方式在结果上确实是完全相同的,然而,不同之处在于计算属性值会基于其响应式依赖被缓存。 一个计算属性仅会在其响应式依赖更新时才重新计算。这意味着只要 chineseName不改变,无论多少次访问 c都 会立即返回先前的计算结果,而不用重复执行 getter 函数
v-on
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<button type="button" @click="ww(1,2,$event)">点我有惊喜</button>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
})
const ww = (x,y,e) => {
console.log("===================="+ x + y)
console.log(e.type)
}
return {...toRefs(data),ww}
}
}).mount('#app')
</script>
v-if
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--<input type="text" v-if="false">-->
<div>
<span v-if="score >= 90">奖励兰博基尼一辆</span>
<span v-if="score >= 80 && score < 90">奖励苹果一个</span>
<span v-if="score >= 60 && score < 80">男子单打</span>
<span v-if="score < 60">男女混合双打</span>
</div>
<span v-if="score > 80">合格</span>
<span v-else-if="score > 60 && score < 80">中等</span>
<span v-else>不合格</span>
<span v-show="score > 80">哈哈哈哈</span>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
score:77
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
v-show
v-show 也同样具有判断的功能,只不过 v-if属于真正意义的判断,如果条件失败,在渲染的时候不显示标签,vshow判断是通过样式来决定是否显示,如果判断失败,会在标签上添加css display:none
<h2 v-show="score>=80">{{message}}</h2>
v-for
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{student.name}} , {{studentNames[1]}}
<br>
<span v-for="(item,index) in student">{{index}} - {{item}}</span>
<br>
<span v-for="(item,index) in studentNames">{{index}} - {{item}} </span>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
student:{
name: '张三',
age: 12,
hobbies:'唱跳rap'
},
studentNames:['jack','ck','李四']
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
购物车案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style>
table{
width: 500px;
border: 1px solid #000;
border-collapse: collapse;
text-align: center;
}
th,tr,td{
border: 1px solid #000;
}
</style>
</head>
<body>
<div id="app">
<div v-if="books.length > 0">
<table>
<tr>
<th>序号</th>
<th>书名</th>
<th>出版日期</th>
<th>价钱</th>
<th>数量</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in books">
<td>{{index + 1}}</td>
<td>{{item.name}}</td>
<td>{{item.date}}</td>
<td>{{item.price}}</td>
<td>
<button :disabled="item.count <= 1" @click="item.count--">-</button>
{{item.count}}
<button @click="item.count++">+</button>
</td>
<td>
<button @click="del(index)">删除</button>
</td>
</tr>
</table>
总价钱为: {{total}}
</div>
<div v-if="books.length == 0">购物车为空</div>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs,computed} = Vue
const app = createApp({
setup(){
const data = reactive({
books:[
{name:'平凡的世界',date:'2010-12',price:50,count:1},
{name:'红楼梦',date:'2010-12',price:20.5,count:1},
{name:'水浒传',date:'2010-12',price:100,count:1},
{name:'三国演绎',date:'2010-12',price:150,count:1},
]
})
const del = (index) => {
data.books.splice(index,1)
}
//方法 - 计算方法
const total = computed(() => {
let count = 0;
for (const b of data.books) {
count += b.price * b.count
}
return count;
})
return {...toRefs(data),total,del}
}
}).mount('#app')
</script>
v-model
v-model表单双向绑定,是vue中非常重要的一个指令,双向指表单元素和数据的双向绑定,也是vue最有魅力的点 之一。
MVVM分为三个部分: 分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制 器) 1、 M:模型层,主要负责业务数据相关; 2、 V:视图层,顾名思义,负责视图相关,细分下来就是html+css 层; 3、 VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点; MVVM支持双向绑定,意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之 修改V层则会通知M层数据进行修改,以此也实现了视图与模型层的相互解耦;
双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="awd"> <br>
<input type="text" v-bind:value="ww" @input="ss($event)">
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
awd: '张三',
ww: '123'
})
const ss = (e) => {
data.ww = e.target.value
}
return {...toRefs(data),ss}
}
}).mount('#app')
</script>
.v-model+radio
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--男<input name="sex" type="radio" value="男" :checked="sex=='男'">
女<input name="sex" type="radio" value="女" :checked="sex=='女'">-->
<!--男<input name="sex" type="radio" value="男" v-model="sex">
女<input name="sex" type="radio" value="女" v-model="sex">-->
男<input name="sex" type="radio" value="0" v-model="sex">
女<input name="sex" type="radio" value="1" v-model="sex">
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
sex: 0
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
v-model+checkbox
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!--单选框 -->
<label for="agree">
<input type="checkbox" id="agree" v-model="isAgree">同意协议
</label>
<button :disabled="!isAgree">下一步</button>
<hr>
<!--复选框 -->
<input name="hobbies" type="checkbox" value="抽烟" v-model="hobbies">抽烟
<input name="hobbies" type="checkbox" value="喝酒" v-model="hobbies">喝酒
<input name="hobbies" type="checkbox" value="烫头" v-model="hobbies">烫头
<br>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
isAgree: false,
hobbies:['喝酒','抽烟']
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
v-model+select
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<select name="f" v-model="fruit" multiple="multiple">
<option value="苹果" >苹果</option>
<option value="香蕉" >香蕉</option>
<option value="橘子" >橘子</option>
<option value="榴莲" >榴莲</option>
</select>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
fruit:['橘子']
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
v-model值绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<span v-for="(item,index) in allFruits">
{{item}}<input type="checkbox" :value="item" v-model="selectFruit">
</span>
<input type="text" v-model.trim="name">
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data = reactive({
allFruits:['香蕉','榴莲','苹果','鸭梨','荔枝','芒果'],
selectFruit:['榴莲','苹果','荔枝'],
name:' asd '
})
return {...toRefs(data)}
}
}).mount('#app')
</script>
v-model修饰符
<!-- 1.lazy修饰符 声明当前延迟赋值 -->
<input type="text" v-model.lazy="message">
<h2>{{message}}</h2>
<!-- 2.number修饰符 声明当前绑定类型为数字 -->
<input type="number" v-model.number="message">
<h2>{{message}}{{typeof message}}</h2>
<!-- 2.trim修饰符 截取空格 -->
<input type="text" v-model.trim="name">
<h2>{{name}}</h2>
组合式api
Vue3 组合式 API(Composition API) 主要用于在大型组件中提高代码逻辑的可复用性。 传统的组件随着业务复杂度越来越高,代码量会不断的加大,整个代码逻辑都不易阅读和理解。
Vue3 使用组合式 API 的地方为 setup。 在 setup 中,我们可以按逻辑关注点对部分代码进行分组,然后提取逻辑片段并与其他组件共享代码。因此,组合 式 API(Composition API) 允许我们编写更有条理的代码
setup 函数
setup函数启动页面后自动执行的一个函数,项目中所有定义的变量、方法都需要写在setup函数中,需要注意的 是,所有setup函数中定义的变量和方法最后都需要return出去,否则无法在视图中使用。
ref函数
当ref里的值发生改变的时候,视图层也会跟随更新(响应式数据) ref可以操作基本数据类型,也可以操作复杂数据类型:对象 数组。 建议:使用ref操作基本数据类型:数字和字符串
reactive函数
reactive同样也是为我们创建一个响应式的引用,不同的是reactive不能用作到基本数据类型上。 reactive主要是作 用在复杂的引用数据结构数据上,例如多维数组及对象,reactive可以响应深层次数据,reactive返回一个proxy代 理对象,使用上和ref稍有区别。
toRef函数
toRef是函数,转换响应式对象中某个属性为单独响应式数据,并且值是关联的。
toRefs函数
场景: 经过reactive函数处理之后返回的对象,如果给这个对象解构或者展开,会让数据丢失响应式的能力,为了解 决这个问题需要引入toRefs函数,使用 toRefs函数 可以保证该对象展开的每个属性都是响应式的。也叫扩展运算 符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>{{tree}}</div>
<div v-for="i in arr">{{i}}</div>
<div v-for="i in person">{{i}}</div>
=====================
<div>{{mark}}</div>
<div>{{mark}}</div>
<div>{{mark}}</div>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,reactive,toRefs,ref,toRef} = Vue
const app = createApp({
setup(){
let tree = ref('小树苗');
const arr = ref(['苹果','香蕉','橘子'])
const person = ref({
name:'张三',
age : 50,
mark: '法外狂徒123123'
})
const data = reactive({
person:{
name:'张三',
age : 50,
mark: '法外狂徒123123'
}
})
let mark = toRef(data.person,'mark')
return {tree,arr,person,mark,...toRefs(data)}
}
}).mount('#app')
</script>
vue生命周期
vue2和vue3区别
生命周期案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<input type="text" v-model="name">
<a href="双向绑定.html">1111111111111111111</a>
</div>
</body>
</html>
<script type="text/javascript" src="js/vue.global.prod.js"></script>
<script type="text/javascript">
const {createApp,
reactive,
toRefs,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted} = Vue
const app = createApp({
setup(){
console.log("========setup========")
const data = reactive({
name:'zhangsan'
})
onBeforeMount(() => {
console.log("========onBeforeMount========")
})
onMounted(() => {
console.log("========onMounted========")
}),
onBeforeUpdate(() => {
console.log("========onBeforeUpdate========")
}),
onUpdated(() => {
console.log("========onUpdated========")
}),
onBeforeUnmount(() => {
console.log("========onBeforeUnmount========")
}),
onUnmounted(() => {
console.log("========onUnmount========")
})
return {...toRefs(data)}
},
}).mount('#app')
</script>
axios
ajax原理: 由客户端请求ajax引擎,再由ajax引擎请求服务器,服务器作出一系列响应之后返回给ajax引擎,由ajax引擎决定 将这个结果写入到客户端的什么位置。实现页面无刷新更新数据。 核心对象 XMLHttpReques
ajax优点: 1、无刷新更新数据 2、异步与服务器通信 3、前端和后端负载平衡 4、基于标准被广泛支持 5、界面与应用分离
ajax缺点: 1、ajax不能使用Back和history功能,即对浏览器机制的破坏。 2、安全问题 ajax暴露了与服务器交互的细节 3、对收索引擎的支持比较弱 4、破坏程序的异常处理机制 5、违背URL和资源定位的初衷 6、ajax不能很好的支持移动设备
Axios是一个基于promise的HTTP库,类似于jQuery的ajax,用于http请求。可以应用于浏览器端和node.js,既可以用于客户端,也可以用于node.js编写的服务端
Axios特性
-
(1)支持Promise API
-
(2)拦截请求与响应,比如:在请求前添加授权和响应前做一些事情。
-
(3)转换请求数据和响应数据,比如:进行请求加密或者响应数据加密。
-
(4)取消请求
-
(5)自动转换JSON数据
-
(6)客户端支持防御XSRF
目前解决跨域的问题常见的三种方式: 1. 客户端解决 2. 服务器解决 3. nginx反向代理
package edu.xja;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@SpringBootApplication
public class Day05Application {
public static void main(String[] args) {
SpringApplication.run(Day05Application.class, args);
}
/**
* 跨域过滤器
*
* @return
*/
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", buildConfig());
return new CorsFilter(source);
}
private CorsConfiguration buildConfig() {
CorsConfiguration corsConfiguration = new CorsConfiguration();
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
return corsConfiguration;
}
}
sprinboot+axios单表示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<table>
<tr>
<th>序号</th>
<th>用户名</th>
<th>昵称</th>
<th>账号状态</th>
<th>邮箱</th>
<th>手机号</th>
<th>用户性别</th>
<th>头像</th>
<th>用户类型</th>
<th>创建时间</th>
<th>更新时间</th>
<th>操作</th>
</tr>
<tr v-for="(item,index) in userList">
<td>{{index+1}}</td>
<td>{{item.userName}}</td>
<td>{{item.nickName}}</td>
<td>{{item.status==0?'正常':'禁用'}}</td>
<td>{{item.email}}</td>
<td>{{item.phonenumber}}</td>
<td>{{item.status==0? '男':'女'}}</td>
<td>{{item.avatar}}</td>
<td>{{item.userType == 0 ? '管理员':'普通用户'}}</td>
<td>{{item.createTime}}</td>
<td>{{item.updateTime}}</td>
<td> <button @click="update(item.id)">修改</button>
<button @click="del(item.id)">删除</button></td>
</tr>
</table>
</div>
</body>
</html>
<script type="text/javascript" src="js/axios.min.js"></script>
<script type="text/javascript" src="js/vue.global.js"></script>
<script>
const {createApp, reactive, toRefs} = Vue
const app = createApp({
setup() {
const data = reactive({
userList: []
})
const load = () => {
axios.get('http://localhost:8080/user', {
params: {}
}).then(res => {
data.userList=res.data
console.log(res)
})
}
load()
const del =(id)=>{
axios.delete('http://localhost:8080/user/'+id, {
params: {}
}).then(res => {
data.userList=res.data
console.log(res)
load()
})
}
const update = (id) => {
location = "updateUser.html?id="+id
}
return {...toRefs(data),del,update}
}
}).mount('#app')
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>
用户名:<input type="text" id="userName" v-model="userList.userName"><br>
昵称:<input type="text" id="nickName" v-model="userList.nickName"><br>
<span>账号状态</span>
<input type="text" id="status" v-model="userList.status"><br>
<span>邮箱</span><input type="text" id="email" v-model="userList.email"><br>
<span>手机号</span><input type="text" id="phonenumber" v-model="userList.phonenumber"><br>
<span>用户性别</span><input type="text" v-model="userList.status"><br>
<span>头像</span><input type="text" id="avatar" v-model="userList.avatar"><br>
<span>用户类型</span><input type="text" id="userType" v-model="userList.userType"><br>
<span>创建时间</span><input type="text" id="createTime" v-model="userList.createTime"><br>
<span>更新时间</span><input type="text" id="updateTime" v-model="userList.updateTime"><br>
<button type="button" @click="update">修改</button>
</div>
</div>
</body>
</html>
<script type="text/javascript" src="js/axios.min.js"></script>
<script type="text/javascript" src="js/vue.global.js"></script>
<script>
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data =reactive({
userList:{}
})
let searchURL = window.location.search;
searchURL = searchURL.substring(1, searchURL.length);
let id = searchURL.split("&")[0].split("=")[1];
data.userList.id=id
axios.get('http://localhost:8080/user/'+data.userList.id, {
params: {}
}).then(res => {
data.userList=res.data
console.log(res)
})
const update=()=>{
axios.put('http://localhost:8080/user',data.userList).then(res => {
console.log(res)
if(res){
location = "sysUser.html"
}
})
}
return{...toRefs(data),update}
}
}).mount('#app')
</script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div>
用户名:<input type="text" id="userName" v-model="userList.userName"><br>
昵称:<input type="text" id="nickName" v-model="userList.nickName"><br>
<span>账号状态</span><input type="text" id="status" v-model="userList.status"><br>
<span>邮箱</span><input type="text" id="email" v-model="userList.email"><br>
<span>手机号</span><input type="text" id="phonenumber" v-model="userList.phonenumber"><br>
<span>用户性别</span><input type="text" v-model="userList.status"><br>
<span>头像</span><input type="text" id="avatar" v-model="userList.avatar"><br>
<span>用户类型</span><input type="text" id="userType" v-model="userList.userType"><br>
<span>创建时间</span><input type="text" id="createTime" v-model="userList.createTime"><br>
<span>更新时间</span><input type="text" id="updateTime" v-model="userList.updateTime"><br>
<button type="button" @click="add">增加</button>
</div>
</div>
</body>
</html>
<script type="text/javascript" src="js/axios.min.js"></script>
<script type="text/javascript" src="js/vue.global.js"></script>
<script>
const {createApp,reactive,toRefs} = Vue
const app = createApp({
setup(){
const data =reactive({
userList:{}
})
const add=()=>{
axios.post('http://localhost:8080/user',data.userList).then(res => {
console.log(res)
if(res){
location = "sysUser.html"
}
})
}
return{...toRefs(data),add}
}
}).mount('#app')
</script>
vue脚手架
下载安装node.js
cmd查看版本node -v
webpack下载npm install webpack@5.73.0 -g
webpack -v
npm install -g @vue/cli
elemen-plus
下载node
然后下载webpack:npm install webpack@5.73.0 -g
下载npm install -g @vue/cli
配置端口号
使用包管理器#
我们建议您使用包管理器(如 NPM、Yarn 或 pnpm)安装 Element Plus,然后您就可以使用打包工具,例如 Vite 或 webpack。
# 选择一个你喜欢的包管理器
# NPM
$ npm install element-plus --save
# Yarn
$ yarn add element-plus
# pnpm
$ pnpm install element-plus
main.js
路由 vue-router
路由就是通过互联的网络把信息从源地址传输到目的地址的活动。
专业术语
前端渲染: 指页面加载和渲染过程中只需要浏览器就能够做到,例如HTML网页
后端染: 加载和渲染网页需要借助后端才能将网页展现出来,例如JSP -- HTML部分是response.write()
前端路由:在新的开发模式下,我们希望网页跳转的过程中不在直接重新刷新页面,而是通过一些特定处理之后
只要给定URL地址就直接将网页渲染到指定位置,而配置方式就需要使用到前端路由用来指定URL后端路由: 后端路由其实我们一直都在用,例如: servlet中配置了urL-pattern(地址跳转) SpringMVC中也一样给定不同的地址,映射到不同的controtler
路由应用
index.js
// 配置路由相关的信息
import VueRouter from 'vue-router'
import Vue from 'vue'
import Home from '../components/Home'
import About from '../components/About'
// 1.通过Vue.use(插件), 安装插件
Vue.use(VueRouter)
// 2.创建VueRouter对象
const routes = [
{
path: '',
// redirect重定向
redirect: '/home'
},
{
path: '/home',
component: Home
},
{
path: '/about',
component: About
}
]
const router = new VueRouter({
// 配置路由和组件之间的应用关系
routes,
mode: 'history',
linkActiveClass: 'active'
})
// 3.将router对象传入到Vue实例
export default router
vue-router动态路由的使用
在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望路径中存在用户id,这种path和Component相互匹配的关系,我们称之为动态路由,也是路由传递数据的一种方式。
路由懒加载
当打包构建应用时,JavaScript包会变得非常大,影响页面加载。
如果我们能吧不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了。
结合Vue的异步组件和Webpack的代码分析
const Home = resolve => { require.ensure(['../components/Home.vue'],
() => { resolve(require('../components/Home.vue')) })};
index.js
// import Home from '../components/Home'
// import About from '../components/About'
// import User from '../components/User'
// 懒加载方式
const Home = () => import('../components/Home')
const About = () => import('../components/About')
const User = () => import('../components/User')
路由嵌套
1、嵌套路由是一个很常见的功能
比如在home页面中,我们希望通过/home/news和/home/message访问一些内容;
一个路径映射一个组件,访问这两个路径也分别渲染这两个组件;
2、实现嵌套路由的两个步骤
创建对应的子组件,并且在路由映射中配置对应的子路由;
在组件内部使用<router-view>标签;
相当于父子路由
{
path: '/layout',
component: Layout,
children:[
{
path:'',
component: Welcome
},
{
path: 'user',
component: () => import('@/views/User')
}
]
}
路由模式
hash模式
1、vue-router默认是hash模式
2、url中有“#”号
3、hash值(“#”后的值)不会被包含在http请求中,改变hash值不会引起页面的重新加载。
4、hash改变会触发hashChange事件,会被浏览器记录下来,可以使用浏览器的前进和后退。
5、hash兼容到IE8以上
6、 会创建hashHistory对象,在访问不同的路由的时候,会发⽣两件事:
HashHistory.push()将新的路由添加到浏览器访问的历史的栈顶
HasHistory.replace()替换到当前栈
history模式
1、url不带参数
2、history 兼容 IE10 以上
3、history 模式需要后端配合将所有访问都指向 index.html,否则用户刷新页面,会导致 404 错误
4、在HTML4中常用的方法:
history.forward():在历史记录中前进一步
history.back():在历史记录中后退一步
history.go(n):在历史记录中跳转n步骤,n=0为刷新本页,n=-1为后退一页。
5、HTML5中新增了
history.pushState(data[,title][,url]):向历史记录中追加一条记录
history.replaceState(data[,title][,url]):替换当前页在历史记录中的信息
history.state:是一个属性,可以得到当前页的state信息。
window.onpopstate:是一个事件,在点击浏览器后退按钮或js调用forward()、back()、go()时触发。监听函数中可传入一个event对象,event.state即为通过pushState()或replaceState()方法传入的data参数
//有实力的背下来
相同点:
1. 都是VueRouter的模式配置选项。
2. 都可以用作SPA(单页面应用)的实现,实现前端路由,不向服务器发起请求,动态渲染页面。
不同点:
1. Hash模式需要#xxx(哈希值),History模式书写更简约。
2. Hash模式是通过window对象监听hashchange事件,根据hash值的变化来动态渲染页面的;History模式是通过window对象监听popstate事件,当浏览器前进和后退时,获取当前history对象状态即history.state来动态渲染组件。
3. Hash模式创建history对象是依赖HashHistory构造函数;History模式创建history对象是依赖HTML5History构造函数。
Hash模式利用HashHistory.push()和HashHistory.replace()可以将hash变化的URL都被记录在浏览器历史访问栈,实现页面内容和URL一一对应,从而可以使用浏览器的前进和后退功能。
History模式利用HTML5History.pushState()和HTML5History.replaceState()修改页面的url地址,修改history对象的状态,而不刷新页面。
4. Hash模式通过携带在url中传递参数;History模式既可以通过携带在url中传递参数,也可以将数据存放在一个特定的对象中。
5. Hash模式只有hash值设置为不同于上次时,才会被添加进历史记录栈;History模式可以记录相同的url。
6. Hash模式只能修改#之后的部分;History模式的pushState设置的新的url可以是于当前url同源的任意url。