VUE笔记
VUE
00.学习vue的大致思路:
1.学习本阶段的作用
能够熟练使用 vue.js技术栈开发前端项目
2.vue.js技术栈
- vue.js
- vue-router
- webpack
- axios
- vue-cli3
- vuex
- vue组件库(element-UI…)
学习目标
- 掌握vue.js基础语法⭐
- 掌握vue组件
- 掌握vue路由⭐
- 掌握axios⭐
- 理解webpack⭐
- 掌握vue-cli3和Element-UI的使用⭐
- 掌握vuex⭐
- 能够熟练使用vue技术栈开发前端项目
⭐:重难点
4.本阶段包含案例项目展示
- 电商后台管理系统
5.阶段模块和学习方法建议
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SMcmveAN-1649165714784)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330154633003.png)]
01.常用特性概述与表单效果概览
input 单行文本
textarea 多行文本
select 下拉多选
radio 单选框
checkbox 多选框
02.侦听器基本用法
应用场景:数据变化时执行异步或者开销较大的操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xjRFLq08-1649165714785)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220328090839031.png)]
属性的名称和里面方法的名称要相同,这样才可以绑定数据的变化
03.MVVM设计思想分析
- M(model) 模型:提供数据的
- V(view) 视图:提供页面展示效果
- VM(View-Model) 实现控制逻辑,把两者结合在一起
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-owoWFX9s-1649165714785)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220328091740343.png)]
设计思想:分治
把视图层和数据层分开 他们两个通过vue来连接起来
从视图通过事件监听到数据
从数据通过数据绑定到视图层
04.双向数据绑定和v-model指令用法
数据与页面的交互是双向数据绑定
页面变化会引起数据发生改变
数据也可以填充到页面中影响页面布局
v-model = ‘data中的数据’
双向数据绑定主要体现在表单输入域中
05.v-model底层原理分析
属性绑定+事件绑定
//$event是一个标准的事件对象
…
methods:{
handle:function(event){
//使用输入域中最新的数据覆盖原来的数据
this.msg = event.target.value //target就是input本身
}
}
v-bind:value 数据绑定
v-on:input 事件绑定
06.数据响应式概念和v-once用法
如何理解响应式?
- html5中的响应式:屏幕尺寸的变化导致样式的变化
- 数据的响应式(数据的变化导致页面内容的变化)
什么是数据绑定?
- 数据绑定:将数据填充到标签中
v-once只编译一次
- 显示内容之后不再具有响应式功能
- v-once的应用场景:如果显示的信息后续不需要再修改
我们可以使用v-once,这样可以提高性能
07.过滤器
过滤器的作用是什么?
格式化数据(处理数据),比如将字符串格式化为首字母大写,将日期格式化为指定的格式等
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TUnDvAJU-1649165714786)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220328154821821.png)]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model = 'msg'>
<div>{{msg | upper }}</div>
</div>
<script>
//过滤器
Vue.filter('upper',function (val) {
return val.charAt(0).toUpperCase() val.slice(1); //这边要有返回值!!!
})
var vl = new Vue({
el:"#app",
data:{
msg:'hello'
}
})
</script>
</body>
</html>
2.自定义过滤器
Vue.filter('过滤器名称',function(value){
//过滤器业务逻辑
})
3.过滤器的使用
<div>{{msg | upper | lower}}</div> <--
叠加:即先大写在小写
-->
<div v-bind:id = 'id | formatId'></div>
//也可以属性绑定
4.局部过滤器
filters:{
capitalize:function(){}
} //写在new Vue里面
5.带参数的过滤器
Vue.filter('format',function(value,argu1){
//value是过滤器传递过来的参数,要调用参数从第二个开始
})
6.过滤器的使用
<div>{{date | format('yyyy-MM-dd')}}</div>
08.组件
定义:
组件是vue.js最强大的功能之一
组件可以扩展HTML元素,封装可重用的代码
组件系统可以让我们用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fkaSVyGT-1649165714786)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220328162624420.png)]
注册一个全局组件语法格式:
Vue.component(tagName,option)
//tagName为组件名,options为配置选项
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<runoob></runoob>
</div>
<script>
//定义全局组件
Vue.component('runoob',{
template:'<h1>自定义组件!!</h1>'
})
//创建根实例
var vl = new Vue({
el:"#app",
data:{}
})
</script>
</body>
</html>
在实例选项中注册一个局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<runoob></runoob>
</div>
<script>
//定义全局组件
var child = {
template:'<div>注册一个局部组件</div>'
}
//创建根实例
var vl = new Vue({
el:"#app",
data:{},
components:{
//<runoob>将只在父模板中可用
'runoob':child
}
})
</script>
</body>
</html>
Prop(父组件向子组件传值)
prop是子组件用来接受父组件传递过来的数据的一个自定义属性
父组件的数据需要通过props把数据传给子组件,子组件需要显式地用props选项声明“prop”:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child message = "hello!"></child>
</div>
<script>
//注册
Vue.component('child',{
//声明props
props:['message'],
//同样也可以在vm实例中像“this.message”这样使用
template:'<span>{{message}}</span>'
})
//创建根实例
new Vue({
el:'#app'
})
</script>
</body>
</html>
动态绑定:
类似于用v-bind绑定HTML特性到一个表达式,也可以用v-bind动态绑定props的值到父组件的数据中,每当父组件的数据变化时,改变话会传递到子组件中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<child message = "hello!"></child> //静态绑定
<child message = "hello!" :che = 'ch'></child> //同时也可以绑定多个,后面的是动态绑定
</div>
<script>
//注册
Vue.component('child',{
//声明props
props:['message','che'],
//同样也可以在vm实例中像“this.message”这样使用
template:'<span>{{message "------" che}}</span>'
})
//创建根实例
new Vue({
el:'#app',
data:{
ch:'6666'
}
})
</script>
</body>
</html>
注意:prop是单向绑定的:当父组件的属性变化时,将传递给子组件,但是不会反过来
prop命名规则:在prop中可以使用驼峰式命名
但是到HTML中必须使用短横线命名规则
prop支持不同类型字符串
在number中
HTML中: :pnum = “12” 则返回的一个数字,可以在template中支持运算
如果是pnum = “12”,则返回的是一个字符串
布尔值也是类似道理
注意点:凡是遇到v-for循环,都要加一个:key = ’index‘
如:
<li :key = 'index' v-for = '(item,index) in parr'>item</li>
子组件向父组件传递参数
子组件向父组件传递信息:
1.子组件通过自定义事件向父组件中传递信息
2.父组件监听子组件的事件
<button v-on:click = '$emit("enlarge-text")'>扩大字体</button> //第一步 其中$emit函数是固定的
<menu-item v-on:enlarge-text = "fontSize = 0.1"></menu-item> //第二步
携带参数:
3.子组件通过自定义事件向父组件传递信息
4.父组件监听子组件的事件
<button v-on:click = '$emit("enlarge-text",0.1)'>扩大字体</button> //第二个值就是子组件传递要携带的参数
<menu-item v-on:enlarge-text = "fontSize = $event"></menu-item> //父组件中通过$event来接受子组件传递过来的参数
或者在父组件中直接用handle($event),具体实现流程在下面methods中实现
兄弟组件之间数据交互
非父子之间传值
1.单独的事件中心管理组件间的通信
var eventHub = new Vue() //单独创建的vue实例对象就是事件中心管理组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xHorVae0-1649165714787)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330161749298.png)]
2.监听事件和销毁事件
eventHub.$on('add-todo',addTodo) //第一个参数是事件名称,第二个参数是事件函数
eventHub.$off('add-todo')
3.触发事件
eventHub.$emit('add-todo',id)
实例:
<div>
<button @click = 'handle'>销毁事件</button>
</div>
<test-tom></test-tom>
<test-jerry></test-jerry>
//定义事件中心
var hub = new Vue();
Vue.component('test-tom',{
data:function(){
return{
num:0
},
template:`
<div>
<div>TOM:{{num}}</div>
<div>
<button @click = "handle">点击</button>
</div>
</div>
`,methods:{
handle:function(){
//触发兄弟组件的事件
hub.$emit('jerry-event',1)
}
},
mounted:function(){
//在钩子函数中,代表页面已经加载完成,监听事件
hub.$on('tom-event',(val) => {
this.num =val
})
}
}
})
Vue.component('test-jerry',{
data:function(){
return{
num:0
},
template:`
<div>
<div>JERRY:{{num}}</div>
<div>
<button @click = "handle">点击</button>
</div>
</div>
`,
methods:{
handle:function(){
hub.$emit('tom-event',1)
}
},
mounted:function(){
//在钩子函数中,代表页面已经加载完成,监听事件
hub.$on('jerry-event',(val) => {
this.num =val
})
}
})
var vm = new Vue({
el:"#app",
data:{
},
methods:{
handle:function(){
hub.$off('tom-event')
hub.$off('jerry-event')
}
}
})
组件插槽的作用:
组附件向子组件传递内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yxJCeNyl-1649165714787)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330163945202.png)]
父组件中间有值
<div id="app">
<runoob>666</runoob>
</div>
//定义全局组件
Vue.component('runoob',{
template:`<h1>自定义组件!!</h1>
<div>
<slot></slot>
</div>
`
})
最终将组件插槽中的数据传给slot隐藏组件
最后结果就是 自定义组件!!666
如果slot和插槽中都有内容
则slot原先的内容被默认覆盖
具名插槽用法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qbtkcOFO-1649165714788)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330164550943.png)]
作用域插槽
应用场景:父组件对子组件的内容进行加工处理
- 插槽定义
<div id="app">
<fruit-list :list = 'list'>
//在组件中间提供内容,使用特殊标签temlpate,通过slot-scope获取子组件中的数据
<template slot-scope="slotProps"> //用于接受子组件的数据
<strong v-if = 'slotProps.info.id == 2' class="current">{{slotProps.info.name}}</strong> //代码高亮
//利用v-if父元素实现对子元素的加工处理
<span v-else>{{slotProps.info.name}}</span>
</template> //利用template将控制逻辑写在里面
</fruit-list>
</div>
//js:
//定义全局组件
Vue.component('fruit-list',{
props:['list'],
template:`
<div>
<li :key="item.id" v-for = "item in list">
<slot :info = 'item'>{{item.name}}</slot>
</li>
</div>
`
})
在父组件中可以获取到子组件中的数据并且对数据进行加工处理
得到的数据就是从子组件的slot中的info的值获取到,info是自定义的,用来传递给父组件
样式绑定
class样式处理
//对象语法 通过true flase来实现控制逻辑
<div v-bind:class = "{active: isactive}"></div>
//数组语法 通过直接赋值实现控制逻辑
<div v-bind:class = "{activeClass,errorClass}"></div>
//对象绑定和数组绑定结合使用
<div v-bind:class = "{activeClass,errorClass,{active: isactive}}"></div>
样式绑定相关语法细节:
1.对象绑定和数组绑定可以结合使用
2.class绑定的值可以简化操作
用数组或对象包含多个值
3.默认的class如何处理?
默认的class会保留
注意点:
v-bind绑定样式
v-on绑定事件
methods中调用属性记得加this.xxx
style样式处理:
//对象语法 直接写的css样式,不过css样式在data中定义
<div v-bind:style = "{color:activeColor,fontsize:fontSize}"></div>
//数组语法 放多个对象
<div v-bind:style = "{baseStyles,overStyles}"></div>
生命周期
主要阶段:
- 挂载(初始化相关属性) 如:methods watch
beforeCreate created beforeMount mounter
- 更新(dom元素或者组件的管更操作)
beforUpdate updated
- 销毁(销毁相关属性),释放资源
beforeDestroy destroyed
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WJfOH0uU-1649165714789)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329113214424.png)]
另外特别注意mounted 只有它加载完成之后才能调用后台接口往里面填入数据
vue路由
基本概念与原理:
本质:对应关系
1.后端路由:
概念:根据不同的用户的url请求,返回不同的内容
本质:url请求地址与服务器资源之间的对应关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ePNfaZey-1649165714789)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329142354123.png)]
2.SPA
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tLMIAaFN-1649165714789)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329142607552.png)]
2.前端路由
概念:根据不同的用户事件,显示不同的页面内容
本质:用户事件和事件处理函数之间的对应关系
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IQBLyJ44-1649165714790)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329142854878.png)]
3.实现简易的前端路由
基于url中的hash实现(点击菜单的时候改变url的hash,根据hash的变化控制组件的切换)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cLVWCr1s-1649165714790)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329143144280.png)]
//监听window的onhashchange事件,根据获取到的最新的hash值,切换要显示的组件的名称
window.onhashchange = function(){
//通过location.hash获取到最新的hash值
}
1.利用手动的方式完成一个简单的前端路由
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<!--被vue实例控制的div区域-->
<div id="app">
<!--切换组件的超链接-->
<a href="#/zhuye">主页</a>
<a href="#/keji">科技</a>
<a href="#/caijing">财经</a>
<a href="#/yule">娱乐</a>
<!--href里面的值就是hash值,即每个a链接的身份证-->
<!-- 根据 :is属性指定的组件名称,把对应的组件渲染到component 标签所在的位置-->
<!--可以把 component 标签当作是【组件的占位符】-->
<component :is = "comName"></component>
</div>
<script>
//实现动态切换,点击a链接切换信息
//#region定义需要被切换的4个组件
const zhuye = {
template:'<h1>主页信息</h1>'
}
const keji = {
template:'<h1>科技信息</h1>'
}
const caijing = {
template:'<h1>财经信息</h1>'
}
const yule = {
template:'<h1>娱乐信息</h1>'
}
</script>
<script>
const vm = new Vue({
el:'#app',
data:{
comName:zhuye
},
//注册私有组件
components:{
zhuye,
keji,
caijing,
yule
}
})
//监听 window的onhashchange 事件,根据获取到的最新的hash值,切换要显示的组件的名称
window.onhashchange = function () {
//通过 location.hash获取到最新的hash值
//console.log(location.hash.slice(1))
//slice(1)代表从索引为1的位置往后取,就没有#啦
//用case条件判断switch
switch (location.hash.slice(1)) {
case '/zhuye':
vm.comName = 'zhuye'
break
case '/keji':
vm.comName = 'keji'
break
case '/caijing':
vm.comName = 'caijing'
break
case '/yule':
vm.comName = 'yule'
break
}
}
</script>
</body>
</html>
vue router
vue router是vue.js官方的路由管理器
它和vue.js的核心深度集成,可以非常方便的用于SPA应用程序的开发
扩展:SPA:单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
vue router包含的功能有
- 支持HTML5历史模式或hash模式
- 支持嵌套路由
- 支持路由参数
- 支持编程式路由
- 支持命名路由
vue router的基本使用步骤
1.引入相关的库文件
先引入vue 在引入vue-router 因为后者依赖于前者
2.添加路由链接
router-link 是vue中提供的标签,默认会被渲染为a标签
to 属性默认会被渲染为 href标签
to 属性的值默认会被选认为 #开头的hash地址
<router-link to = "/user">User</router-link>
<router-link to = "/register">Register</router-link>
3.添加路由填充位
路由填充位也叫做路由占位符
将来通过路由规则匹配到的组件,都会被渲染到 router-view所在的位置
<router-view></router-view>
4.定义路由组件
var User = {
template:'<div>User</div>'
}
var Register = {
template:'<div>Register</div>'
}
5.配置路由规则并创建路由实例
//创建路由实例对象
var router = new VueRouter({
//routes 是路由规则数组
routes:[
//每个路由规则都是一个配置对象,其中至少包含path和component
//path表示当前路由规则匹配的hash地址
//component表示当前路由规则对应要展示的组件
{path:'/user',component:User},
{path:'/register',component:Register}
]
})
6.把路由挂载到Vue根实例中
new Vue({
el:'#app',
//为了能够让路由规则生效,必须把路由对象挂载到vue实例中
router
})
路由重定向
路由重定向指的是:用户在访问地址A的时候,强制用户跳转到地址C,从而展示特定的组件页面;通过路由规则的redirect属性,指定一个新的路由地址,可以很方便的设置路由的重定向
比如访问一个页面,直接跳转到展开内容的页面
var router = new VueRouter({
routes:{
//其中,path表示需要被重定向的原地址,redirect表示将要被重定向到的新地址
{path:'/',redirect:'/user'},
{path:'/user',compnent:User},
{path:'/register',component:Register}
}
})
嵌套路由
1.嵌套路由功能分析:
- 点击父级路由链接显示模板内容
- 模板内容中又有子级路由链接
- 点击子级路由链接显示子级模板内容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wxsXyE1A-1649165714790)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220329204931117.png)]
const User = {
template: '<h1>User</h1>'
}
const Register = {
//子级路由链接 和子级路由填充位放在register下面
//``是模板字符串
template: `<div>
<h1>Register</h1>
<hr/>
<router-link to = "/register/tab1">Tab1</router-link>
<router-link to = "/register/tab2">Tab2</router-link>
<rounter-view>
</div>`
}
//子路由占位符
const Tab1 = {
template:'<h3>tab1 子组件</h3>'
}
const Tab2 = {
template:'<h3>tab2 子组件</h3>'
}
//创建路由实例对象
const router = new VueRouter({
//routes 是路由规则数组
routes: [
//每个路由规则都是一个配置对象,其中至少包含path和component
//path表示当前路由规则匹配的hash地址
//component表示当前路由规则对应要展示的组件
{path: '/user', component: User}, //component只接受组件对象不接受字符串
{path: '/register',
component: Register,
//通过children属性,为/register 添加子路由规则
//children数组表示子路由规则
children:[
{path:'/resgister/tab1',component:Tab1},
{path:'/resgister/tab2',component:Tab2}
]
}
]
})
动态路由匹配
如果某部分路由规则他们的一部分是一样的,另一部分是变化的,我们可以把这变化的那一部分形成路由参数 ,路由参数就叫路由匹配
var router = new VueRouter({
routers:[
//动态数据参数,以冒号开头
{path:'/user/:id',component:User}
]
})
const User = {
//路由组件中通过$route.params获取路由参数
template:'<div>User {{$route.params.id}}</div>'
}
上面conponent中的值就是下面实现方法的名称
路由组件传递参数
$route与对应路由行成高度耦合,不够灵活,所以可以使用props将组件和路由解耦关联
1.props的值为布尔类型
const router = new VueRouter({
routes:[
//如果props被设置为true,route.params将会被设置为组件属性
{path:'/user/:id',component:User,props:true}
]
})
const User = {
props:['id'] //使用props接受路由参数 即id值
template:'<div>用户ID:{{ id }}</div>' //使用路由参数
}
2.props的值为对象类型
const router = new VueRouter({
routes:[
//如果props是一个对象,它会被按原样设置为组件属性
{path:'/user/:id',component:User,props:{uname:'zcr',age:18}}
]
})
const User = {
props:{'uname','age'},
template:'<div>用户信息:{{ uname '----' age}}</div>'
}
这里访问的是uname和age的值,id算是废了
那么如何既能访问到uname和age,又能访问到id的值呢?
第三种方法来袭:props的值为函数类型
const router = new VueRouter({
routes:[
//如果props是一个函数,则这个函数接受route对象对自己的形参
{
path:'/user/:id',
component:User,
props:route => ({
uname:'zcr',
age:18,
id:route.params.id
})
}
]
})
const User = {
props:['uname','age','id'],
template:'<div>用户信息:{{uname "----" age "-----" id}}</div>'
}
命名路由:
命名路由的配置原理:
为了更加方便地表示路由的路径,可以给路由规则起一个别名,即为“命名路由”
const router = new VueRouter({
routes:[
{
path:'/user/:id',
name:'user',
component:User
}
]
})
<router-link :to = "{name : 'user',params:{id:123}}">User</router-link>
//编程式导航
router.push({ name:'user' , params :{id : 123}})
不仅可以根据路径跳转,还可以根据name和id
编程式导航
页面导航的两种方式:
- 声明式导航:通过点击链接实现导航的方式,叫做声明式导航
例如:普通网页中的a链接或者vue中的rounter-link
- 编程式导航:通过调用JS形式的API实现导航的方式,叫做编程式导航
例如:普通网页中的location.href
基本用法:
常见的编程式导航API如下:
this.$router.push(‘hash地址’) 跳转到某个哈希地址
this.$router.go(n) 前进n或者后退n步
const User = {
template:'<div><button @click = "goRegister">跳转到注册页面</button></div>'
methods:{
goRegister:function(){
//用编程的方式控制路由跳转
this.$router.push('/register')
}
}
}
router.push()方法的参数规则
//字符串(路径名称)
router.push('/home')
//对象
router.push({path:'/home'})
//命名的路由(传递参数)
router.push({name:"/user",params:{userid:123}})
//带查询参数,变成/register?uname = lisi
router.push({path:'/register',query:{uname:'lisi'}})
异步vue
axios的基本特性:
axios是一个基于Promise用于浏览器和node.js的HTTP客户端
axios是一个专门用于调用后台接口的js库 需要引入
它具有以下特性:
- 支持浏览器和node.js
- 支持promise
- 能拦截请求和响应
- 自动转换json数据
axios.get('/adata') //发起请求
.then(ret=>{
// data属性名称是固定的,用于获取后台响应的数据
console.log(ret.data)
})
//后台接口
app.get('/adata',(req,res) => {
res.send('Hello axios!')
})
axios的常用API
1.GET传递参数
1)通过URL传递参数
//第一种
axios.get('http://localhost:3000/adata?id = 123')
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.get('/axios?id = 123',(req,res)=>{
res.send('axios get 传递参数' req.query.id)
})
//第二种
axios.get('http://localhost:3000/adata/123')
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.get('/axios/:id',(req,res)=>{
res.send('axios get (Restful) 传递参数' req.params.id)
})
2)通过params选项传递数据(传递多参数这个更方便)
axios.get('http://localhost:3000/adata',{
params:{
id:789
}
})
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.get('/axios/:id',(req,res)=>{
res.send('axios get (Restful) 传递参数' req.params.id)
})
2.delete传递参数
参数传递方式与get类似
只不过后台只用query 不用params了
//第一种
axios.delete('http://localhost:3000/adata',{
params:{
id:789
}
})
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.delete('/axios/:id',(req,res)=>{
res.send('axios DELETE (Restful) 传递参数' req.query.id)
})
//第二种
axios.delete('http://localhost:3000/adata?id = 123')
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.delete('/axios?id = 123',(req,res)=>{
res.send('axios DELETE 传递参数' req.query.id)
})
//第三种
axios.delete('http://localhost:3000/adata/123')
.then(ret=>{
console.log(ret.data)
})
//后台接口
app.delete('/axios/:id',(req,res)=>{
res.send('axios DELETE (Restful) 传递参数' req.query.id)
})
3.post传递参数
通过选项传递参数(默认传递的是json格式的数据)
axios.post('/adata',{
uname:'tom',
pwd:123
}).then(ret=>{
console.log(ret.data)
})
//后台接口
app.post('/axios',(req,res)=>{
res.send('axios post 传递参数' req.body.uname req.body.pwd)
})
通过URLSearchParams传递参数(表单传递)
//先准备一个实例对象,把数据填充到实例对象中
const params = new URLSearchParams();
params.append('uname','zcr');
params.append('pwd','123');
axios.post('http://loacahost:8000/axios',params).then(ret=>{
console.log(ret.data)
})
//后台接口
app.post('/axios',(req,res)=>{
res.send('axios post 传递参数' req.body.uname req.body.pwd)
})
4.put请求
参数传递方式和POST非常类似
axios.put('/adata/123',{ //做信息修改,加上id
uname:'zcr',
pwd:123
}).then(ret=>{
console.log(ret.data)
})
//后台接口
app.put('/axios/:id',(req,res)=>{
res.send('axops put 传递参数' req.params.id '--' req.body.uname '--' req.body.pwd)
})
JSON比起表单形式的传递参数方式更加方便
axios的响应结果
响应结果的主要属性:
- data:实际响应回来的数据
- headers:响应头信息
- status:响应状态码
- statusText:响应状态信息
axios的全局配置
配置请求的基准URL地址
axios.defaults.baseURL= "http://localhost:3000/"
axios.get('adata?id = 123')
.then(ret=>{
console.log(ret.data)
})
设置请求头,需要在后台设置允许传递
//后台 : 设置允许跨域访问该服务
app.all('*',function(req,res,next){
res.header('Access-Control-Allow-Headers','mytoken')
})
//前端
axios.defaults.headers['mytoken'] = 'dawfagaddafags' //某一个字符串
设置超出时间
axios.defaults.timeout = 3000 //超出时间
axios拦截器
在请求发出之前设置一些信息
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLPEZfx0-1649165714791)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330113221856.png)]
//添加一个请求拦截器
axios.interceptors.request.use(function(config)){
//在请求发出之前进行一些信息设置
return config;
},function(err){
//处理一些响应的错误信息
}
//axios实例
axios.intercepors.request.use(function(config){
console.log(config.url) //可以打印出当前访问的url
config.headers.mytoken = 'nihao';
return config
},function(err){
console.log(err)
})
axios.get("http://localhost:3000/adata").then(function(data){
console.log(data)
})
第一个函数进行信息配置,第二个函数做错误警告
响应拦截器
在获取数据之前对数据做一些加工处理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CKCfutuz-1649165714791)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330114028611.png)]
//添加一个响应拦截器
axios.interceptors.response.use(function(res){
//在这里对返回的数据进行处理.
return res;
},function(err){
//处理响应的错误信息
})
//实例:
axios.interceptors.response.use(function(res){
console.log(res) //此时打印出来的是对象
var data = res.data //对数据进行拦截处理
return data
},function(err){
console.log(err)
})
axios.get('http://localhost:3000/adata').then(function(data){
console.log(data) //此时打印出来的就是数据
})
)
async/await的基本用法
async/await是ES7引入的新语法,可以更加方便的进行异步操作
async 关键字用于函数上,(async函数的返回值是Promise实例对象)
await 关键字用于async函数当中(await可以得到异步的结果)
async function queryData(id){
const ret = await axios.get('/data');
//后面的ret就是promise实例对象
return ret;
}
queryData.then(ret=>{
console.log(ret)
})
//这样就不用then了
//实例:
axios.defaults.baseURL = "http:localhost:3000";
/*axios.get('adata').then(function(ret){
console.log(ret.data)
})*/
//第一种方法
async function queryData(){
var ret = await axios.get('adata');
console.log(ret.data)
}
queryData();
//第二种方法
async function queryData(){
var ret = await axios.get('adata');
//await后面要跟一个promise实例对象
//在promise中我们可以处理异步任务
//console.log(ret.data)
return ret.data;
}
queryData().then(function(data){
console.log(data)
});
//第三种方法
async function queryData(){
var ret = await new Promise(function(resolve,reject){
setTimeout(function(){
resolve('nihao')
},1000)
return ret;
})
//await后面要跟一个promise实例对象
//在promise中我们可以处理异步任务
//这里我们直接换成promise
}
queryData().then(function(data){
console.log(data)
});
async返回值是一个新的promise实例对象
可以直接用then调用promise实例对象
async/await 处理多个异步请求
多个异步请求的场景
在async中顺序的写请求
async function queryData(id){
const info = await axios.get('/async1')
const ret = await axios.get('async2?info = ' info.data)
return ret
}
queryData.then(ret=>{
console.log(ret)
})
//后台接口
app.get('/async1',(req,res) =>{
res.send('hello')
})
app.get('/async2',(req,res) =>{
if(req.query.info == 'hello'){
res.send('world')
}else{
res.send('error')
}
})
vuex
复习:
组件之间共享数据的方式
父向子传值:v-bind属性绑定
子向父传值:v-on事件绑定
兄弟组件之间共享数据:EventBus
- $on 接收数据的那个组件
- $emit 发送数据的那个组件
但上述方法都是小范围的进行数据共享
大范围的数据共享还得靠vuex
vuex是什么
vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RZf8go5i-1649165714792)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220330193906566.png)]
如果没有vuex,那么组件之间的数据是靠链条一层一层的进行共享,非常复杂,如果用vue,他会建立一个全局共享数据store,那么就可以直接从store中取数据,非常方便,不需要进行复杂的数据传递。
使用vuex统一管理状态的好处
- 能够在vuex中集中管理共享的数据,易于开发和后期维护
- 能够高效地实现组件之间的数据共享,提高开发效率
- 存储在vuex中的数据都是响应式的,能够实时保持数据和页面的同步
什么样的数据适合存储到vuex中
一般情况下,只有组件之间共享的数据,才有必要存储到vuex中
对于组件中的私有数据,依旧存储到组件自身的data中即可
vuex的基本使用
1.安装vuex依赖包
npm i vuex --save
2.导入vuex包
import Vuex from 'vuex'
Vue.use(Vuex)
3.创建store对象
const store = new Vuex.Store({
//state 中存放的就是全局共享的数据
state:{count:0}
})
4.将 store对象挂载到vue实例中
new Vue({
el:'#app',
render: h => h(app) //用render渲染vue实例
router,
//将创建的共享数据对象,挂载到Vue实例中
//所有的组件,就可以直接从store中获取到全局的数据了
store
})
vuex的核心概念
State
State提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行提供
//创建store数据源,提供唯一的公共数据
const store = new Vuex.Store({
state:{ count: 0 }
})
组件访问State中数据的第一种方式
this.$store.state.全局数据名称
在template中this可以省略
组件访问State中数据的第二种方式:
//1.从vuex中按需导入mapState 函数
import {mapState} from 'vuex'
通过刚才导入的mapState函数,按当前组件需要的全局数据,映射为当前组件的computed计算属性
//2.将全局数据,映射为当前组件的计算属性
computed:{
...mapState(['count'])
}
Mutation
Mutation用于变更Store中的数据
- 只能通过mutation变更Store数据,不可以直接操作Store中的数据
- 通过这种方式虽然从做起来稍微繁琐一些,但是可以集中监控所有数据的变化
//定义Mutation 在store.js中
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
add(state){
//变更状态
state.count
}
}
})
//在组件中触发mutation
methods:{
handle1(){
//触发mutations的第一种方式
this.$store.commit('add')
}
}
可以在触发Mutation时传递参数
//定义Mutation
const store = new Vuex.Store({
state:{
count:0
},
mutations:{
addN(state,srep){
//变更状态
state.count = step
}
}
})
//触发mutation
methods:{
handle2(){
//在调用commit函数
//触发mutations时携带参数
this.$store.commit('addN',3)
}
}
调用mutation的第二种方式:
this.$store.commit()是触发mutations的第一种方式,触发mutations的第二种方式:
//1.从vuex中按需导入mapMutations函数
import {mapMutations} from 'vuex'
通过刚才导入的mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法
//2.将指定的mutations函数,映射为当前组件的methods函数
methods:{
...mapMutations(['add','addN'])
}
不要在mutations函数中执行异步操作
Action
Action用于处理异步任务
如果通过异步操作变更数据,必须通过Action
而不能使用Mutation,但是在Action中还是要通过Mutation的方式间接变更数据
//定义Action
const store = new Vuex.Store({
// 省略其他代码
mutations:{
add(state){
state.count
}
},
actions:{
addAsync(context){
setTimeout(() =>{
context.commit('add')
},1000)
}
}
})
//触发Action
methods:{
handle(){
//触发actions的第一种方式
this.$store.dispatch('addAsync')
}
}
携带参数,和mutation类似
//定义action
const store = new Vuex.Store({
//其他代码
mutations:{
addN(state,step){
state.count = step
}
},
acrions:{
addNAsync(context,step){
setTimeout(()=>{
context.commit('addN',step)
},1000)
}
}
})
//触发action
methods:{
handle(){
//在调用dispatch
//触发actions时携带参数
this.$store.dispatch('addNAsync',5)
}
}
触发action的第二种方式
this.$store.dispatch()是触发actions的第一种方式
触发actions的;第二种方式
//1.从vuex中按需导入mapActions函数
import {mapActions} from 'vuex'
通过刚才导入的mapActions函数,将需要的actions函数,映射为当前组件的methods方法
//通过刚才导入的actions函数,映射为当前组件的methods函数
methods:{
...mapActions(['addASync','addNASync'])
}
Getter
Getter用于对store中的数据进行加工处理形成新的数据
- getter可以对store中已有的数据加工处理之后行成新的数据,类似vue的计算属性
- store中数据发生变化,getter的数据也会跟着变化
//定义Getter
const store = new Vue.Store({
state:{
count:0
},
getters:{
showNum:state =>{
return '当前最新的数量是[' state.count '']'
}
}
})
使用getters的第一种方式
this.$store.getters.名称
第二种方式
import {mapGetters} from 'vuex'
computed:{
...mapGetters(['showNum'])
}
电商后台管理项目
1.1电商项目基本业务概述
根据不同的应用场景,电商系统一般都提供了pc端、移动app端、微信小程序端、移动web等多种终端访问方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4GE2JesI-1649165714792)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220403101301741.png)]
1.2电商后台管理系统的功能
电商后台管理系统用于管理用户账号、商品分类、商品信息、订单、数据统计等业务功能
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TYKNw7TB-1649165714792)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220403101411659.png)]
1.3 电商后台管理系统的开发模式(前后端分离)
电商后台管理系统整体采用前后端分离的开发模式,其中前端项目是基于Vue技术栈的SPA项目
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6zPu09eR-1649165714793)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220403101707864.png)]
1.4电商后台管理系统的技术选型
1.前端项目技术栈
- Vue
- Vue-router
- Element-UI
- Axios
- Echarts
2.后端项目技术栈
- Node.js
- Express
- Jwt(状态保持的工具,模拟类似于session的功能)
- Mysql
- Sequelize
2.1前端项目初始化步骤
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WklZ9THu-1649165714793)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220403102032674.png)]
2.2后台项目的环境安装配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NaYLLZO6-1649165714793)(C:\Users\命与超然\AppData\Roaming\Typora\typora-user-images\image-20220403112206958.png)]
参数,和mutation类似
//定义action
const store = new Vuex.Store({
//其他代码
mutations:{
addN(state,step){
state.count = step
}
},
acrions:{
addNAsync(context,step){
setTimeout(()=>{
context.commit('addN',step)
},1000)
}
}
})
//触发action
methods:{
handle(){
//在调用dispatch
//触发actions时携带参数
this.$store.dispatch('addNAsync',5)
}
}
触发action的第二种方式
this.$store.dispatch()是触发actions的第一种方式
触发actions的;第二种方式
//1.从vuex中按需导入mapActions函数
import {mapActions} from 'vuex'
通过刚才导入的mapActions函数,将需要的actions函数,映射为当前组件的methods方法
//通过刚才导入的actions函数,映射为当前组件的methods函数
methods:{
...mapActions(['addASync','addNASync'])
}
Getter
Getter用于对store中的数据进行加工处理形成新的数据
- getter可以对store中已有的数据加工处理之后行成新的数据,类似vue的计算属性
- store中数据发生变化,getter的数据也会跟着变化
//定义Getter
const store = new Vue.Store({
state:{
count:0
},
getters:{
showNum:state =>{
return '当前最新的数量是[' state.count '']'
}
}
})
使用getters的第一种方式
this.$store.getters.名称
第二种方式
import {mapGetters} from 'vuex'
computed:{
...mapGetters(['showNum'])
}
电商后台管理项目
1.1电商项目基本业务概述
根据不同的应用场景,电商系统一般都提供了pc端、移动app端、微信小程序端、移动web等多种终端访问方式
[外链图片转存中…(img-4GE2JesI-1649165714792)]
1.2电商后台管理系统的功能
电商后台管理系统用于管理用户账号、商品分类、商品信息、订单、数据统计等业务功能
[外链图片转存中…(img-TYKNw7TB-1649165714792)]
1.3 电商后台管理系统的开发模式(前后端分离)
电商后台管理系统整体采用前后端分离的开发模式,其中前端项目是基于Vue技术栈的SPA项目
[外链图片转存中…(img-6zPu09eR-1649165714793)]
1.4电商后台管理系统的技术选型
1.前端项目技术栈
- Vue
- Vue-router
- Element-UI
- Axios
- Echarts
2.后端项目技术栈
- Node.js
- Express
- Jwt(状态保持的工具,模拟类似于session的功能)
- Mysql
- Sequelize
2.1前端项目初始化步骤
[外链图片转存中…(img-WklZ9THu-1649165714793)]
2.2后台项目的环境安装配置
[外链图片转存中…(img-NaYLLZO6-1649165714793)]
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhggcibc
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13