vue2学习
vue2学习
基础
模板语法
Vue模板语法有2大类:
1.插值语法:
功能:用于解析标签体内容。
写法:{{xxx}},xxx是js表达式,且可以直接读取到data中的所有属性。
2.指令语法:
功能:用于解析标签(包括:标签属性、标签体内容、绑定事件…)。
举例:v-bind:href=“xxx” 或 简写为 :href=“xxx”,xxx同样要写js表达式,
且可以直接读取到data中的所有属性。
备注:Vue中有很多的指令,且形式都是:v-???,此处我们只是拿v-bind举个例子。
数据绑定
Vue中有2种数据绑定的方式:
1.单向绑定(v-bind):数据只能从data流向页面。
2.双向绑定(v-model):数据不仅能从data流向页面,还可以从页面流向data。
备注:
1.双向绑定一般都应用在表单类元素上(如:input、select等)
2.v-model:value 可以简写为 v-model,因为v-model默认收集的就是value值。
el与data
data与el的2种写法
1.el有2种写法
(1).new Vue时候配置el属性。
(2).先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
2.data有2种写法
(1).对象式
(2).函数式
如何选择:目前哪种写法都可以,以后学习到组件时,data必须使用函数式,否则会报错。
3.一个重要的原则:
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
-->
<!-- 准备好一个容器-->
mvvm
MVVM模型
1. M:模型(Model) :data中的数据
2. V:视图(View) :模板代码
3. VM:视图模型(ViewModel):Vue实例
观察发现:
1.data中所有的属性,最后都出现在了vm身上。
2.vm身上所有的属性 及 Vue原型上所有属性,在Vue模板中都可以直接使用。
数据代理
1.Vue中的数据代理:
通过vm对象来代理data对象中属性的操作(读/写)
2.Vue中数据代理的好处:
更加方便的操作data中的数据
3.基本原理:
通过Object.defineProperty()把data对象中所有属性添加到vm上。
为每一个添加到vm上的属性,都指定一个getter/setter。
在getter/setter内部去操作(读/写)data中对应的属性。
事件处理
基本使用
事件的基本使用:
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
4.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
5.@click=“demo” 和 @click=“demo($event)” 效果一致,但后者可以传参;
事件修饰符
Vue中的事件修饰符:
1.prevent:阻止默认事件(常用);
2.stop:阻止事件冒泡(常用);
3.once:事件只触发一次(常用);
4.capture:使用事件的捕获模式;
5.self:只有event.target是当前操作的元素时才触发事件;
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕;
键盘事件
1.Vue中常用的按键别名:
回车 => enter
删除 => delete (捕获“删除”和“退格”键)
退出 => esc
空格 => space
换行 => tab (特殊,必须配合keydown去使用)
上 => up
下 => down
左 => left
右 => right
2.Vue未提供别名的按键,可以使用按键原始的key值去绑定,但注意要转为kebab-case(短横线命名)
3.系统修饰键(用法特殊):ctrl、alt、shift、meta
(1).配合keyup使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发。
(2).配合keydown使用:正常触发事件。
4.也可以使用keyCode去指定具体的按键(不推荐)
5.Vue.config.keyCodes.自定义键名 = 键码,可以去定制按键别名
计算属性
计算属性:
1.定义:要用的属性不存在,要通过已有属性计算得来。
2.原理:底层借助了Objcet.defineproperty方法提供的getter和setter。
3.get函数什么时候执行?
(1).初次读取时会执行一次。
(2).当依赖的数据发生改变时会被再次调用。
4.优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
5.备注:
1.计算属性最终会出现在vm上,直接读取使用即可。
2.如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
//get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
//get什么时候调用?1.初次读取fullName时。2.所依赖的数据发生变化时。
get(){
console.log('get被调用了')
// console.log(this) //此处的this是vm
return this.firstName + '-' + this.lastName
},
//需要get只是计算出来的 如果需要修改就需要set 反之则不需要
//set什么时候调用? 当fullName被修改时 value就是修改的值
set(value){
console.log('set',value)
const arr = value.split('-')
this.firstName = arr[0]
this.lastName = arr[1]
}
//简写 没有set
fullName(){
console.log('get被调用了')
return this.firstName + '-' + this.lastName
}
监听属性
监视属性watch:
1.当被监视的属性变化时, 回调函数自动调用, 进行相关操作
2.监视的属性必须存在,才能进行监视!!
3.监视的两种写法:
(1).new Vue时传入watch配置
(2).通过vm.$watch监视
//isHot就是监视的属性
vm.$watch('isHot',{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
})
//配置
watch:{
isHot:{
immediate:true, //初始化时让handler调用一下
//handler什么时候调用?当isHot发生改变时。
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
}
}
深度监视
深度监视:
(1).Vue中的watch默认不监测对象内部值的改变(一层)。
(2).配置deep:true可以监测对象内部值改变(多层)。
备注:
(1).Vue自身可以监测对象内部值的改变,但Vue提供的watch默认不可以!
(2).使用watch时根据数据的具体结构,决定是否采用深度监视。
watch:{
//正常写法
isHot:{
immediate:true, //初始化时让handler调用一下
deep:true,//深度监视
handler(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue)
}
},
//简写
isHot(newValue,oldValue){
console.log('isHot被修改了',newValue,oldValue,this)
}
}
计算属性与监听属性
computed和watch之间的区别:
1.computed能完成的功能,watch都可以完成。
2.watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
两个重要的小原则:
1.所被Vue管理的函数,最好写成普通函数,这样this的指向才是vm 或 组件实例对象。
2.所有不被Vue所管理的函数(定时器的回调函数、ajax的回调函数等、Promise的回调函数),最好写成箭头函数,
这样this的指向才是vm 或 组件实例对象。
//监听属性
watch:{
firstName(val){
setTimeout(()=>{
console.log(this)
this.fullName = val + '-' + this.lastName
},1000);
},
lastName(val){
this.fullName = this.firstName + '-' + val
}
}
//计算属性
fullName(){
console.log('get被调用了')
setTimeout(()=>{
return this.firstName + '-' + this.lastName //由于计算属性由return控制返回值 所以当代码执行到return时
},1000); //就结束了 将结果返回给了setTimeout(异步函数) 所以计算属性
} // 不能使用异步操作
样式绑定
绑定样式:
1. class样式
写法:class=“xxx” xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
2. style样式
:style="{fontSize: xxx}“其中xxx是动态值。
:style=”[a,b]"其中a、b是样式对象。
条件渲染
1.v-if
写法:
(1).v-if=“表达式”
(2).v-else-if=“表达式”
(3).v-else=“表达式”
适用于:切换频率较低的场景。
特点:不展示的DOM元素直接被移除。
注意:v-if可以和:v-else-if、v-else一起使用,但要求结构不能被“打断”。
2.v-show
写法:v-show=“表达式”
适用于:切换频率较高的场景。
特点:不展示的DOM元素未被移除,仅仅是使用样式隐藏掉
3.备注:使用v-if的时,元素可能无法获取到,而使用v-show一定可以获取到。
列表渲染
内置指令
我们学过的指令:
v-bind : 单向绑定解析表达式, 可简写为 :xxx
v-model : 双向数据绑定
v-for : 遍历数组/对象/字符串
v-on : 绑定事件监听, 可简写为@
v-if : 条件渲染(动态控制节点是否存存在)
v-else : 条件渲染(动态控制节点是否存存在)
v-show : 条件渲染 (动态控制节点是否展示)
v-text指令:
1.作用:向其所在的节点中渲染文本内容。
2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
v-html指令:
1.作用:向指定节点中渲染包含html结构的内容。
2.与插值语法的区别:
(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2).v-html可以识别html结构。
3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
v-cloak指令(没有值):
1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
v-once指令:
1.v-once所在节点在初次动态渲染后,就视为静态内容了。
2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
v-pre指令:
1.跳过其所在节点的编译过程。
2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
数据监视
Vue监视数据的原理:
1. vue会监视data中所有层次的数据。
2. 如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1).对象中后追加的属性,Vue 默认不做响应式处理
(2).如需给后添加的属性做响应式,请使用如下API:
添加位置 添加的key 添加的值
Vue.set(target,propertyName/index,value) 或
vm.$set(target,propertyName/index,value)
3. 如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1).调用原生对应的方法对数组进行更新。
(2).重新解析模板,进而更新页面。
4.在Vue修改数组中的某个元素一定要用如下方法:
1.使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
2.Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!
收集表单数据
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值。
若:,则v-model收集的是value值,且要给标签配置value值。
若:
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
lazy:失去焦点再收集数据
number:输入字符串转为有效的数字
trim:输入首尾空格过滤
过滤器
过滤器:
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = “xxx | 过滤器名”
备注:
1.过滤器也可以接收额外参数、多个过滤器也可以串联
2.并没有改变原本的数据, 是产生新的对应的数据
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//局部过滤器 配置在methods中
filters:{
timeFormater(value,str='YYYY年MM月DD日 HH:mm:ss'){
// console.log('@',value)
return dayjs(value).format(str)
}
自定义指令
需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。
自定义指令总结:
一、定义语法:
(1).局部指令:
new Vue({ new Vue({
directives:{指令名:配置对象} 或 directives{指令名:回调函数}
}) })
directives:{
//big函数何时会被调用?1.指令与元素成功绑定时(一上来)。2.指令所在的模板被重新解析时。
真实Dom 和前面的进行绑定
'big-number'(element,binding){
// console.log('big')
element.innerText = binding.value * 10
},
big(element,binding){
console.log('big',this) //注意此处的this是window
// console.log('big')
element.innerText = binding.value * 10
},
fbind:{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}
}
(2).全局指令:
Vue.directive(指令名,配置对象) 或 Vue.directive(指令名,回调函数)
//定义全局指令
/* Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
}) */
二、配置对象中常用的3个回调:
(1).bind:指令与元素成功绑定时调用。
(2).inserted:指令所在元素被插入页面时调用。
(3).update:指令所在模板结构被重新解析时调用。
三、备注:
1.指令定义时不加v-,但使用时要加v-;
2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
ref
ref属性
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
- 使用方式:
- 打标识:
<h1 ref="xxx">.....</h1>
或<School ref="xxx"></School>
- 获取:
this.$refs.xxx
- 打标识:
- 通过ref标记的标签或组件会被保存在vm身上的**$refs**属性上
props
-
功能:让组件接收外部传过来的数据
-
传递数据:
<Demo name="xxx"/>
-
接收数据:
-
第一种方式(只接收):
props:['name']
-
第二种方式(限制类型):
props:{name:String}
-
第三种方式(限制类型、限制必要性、指定默认值):
props:{ name:{ type:String, //类型 required:true, //必要性 default:'老王' //默认值 } }
备注:props是只读的,Vue底层会监测你对props的修改,如果进行了修改,就会发出警告,若业务需求确实需要修改,那么请复制props的内容到data中一份,然后去修改data中的数据。
-
<Student name="李四" sex="女" :age="18"/>
这两个绑定方式差不多 加:“”里面就是js表达式的结果 所以类型就是number 不加就是string
修改数据使用data对props需要修改的东西进行接收 修改data中的值
//修改age 通过data中的myage进行接收 不能直接修改age 去修改myage
data() {
console.log(this)
return {
msg:'我是一个尚硅谷的学生',
myAge:this.age
}
},
methods: {
updateAge(){
this.myAge++
}
}
扩展
- $data 对应的是实例身上的data _data是数据代理 提供get set
- 其他的都是差不多的类型
- props接收的参数存放在$props 通过_props进行代理到实例身上
mixin(混入)
-
功能:可以把多个组件共用的配置提取成一个混入对象
-
使用方式:
第一步定义混合:
-
创建一个mixin.js文件
-
分别暴露 export const hunhe = { methods: { showName(){ alert(this.name) } }, mounted() { console.log('你好啊!') }, } export const hunhe2 = { data() { return { x:100, y:200 } }, }
{ data(){....}, methods:{....} .... }
第二步使用混入:
全局混入:
Vue.mixin(xxx)
在main.js里使用
局部混入:mixins:['xxx']
局部引入 mixins接收 类似props -
自定义插件
-
功能:用于增强Vue
-
本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
-
定义插件:
对象.install = function (Vue, options) { // 1. 添加全局过滤器 Vue.filter(....) // 2. 添加全局指令 Vue.directive(....) // 3. 配置全局混入(合) Vue.mixin(....) // 4. 添加实例方法 Vue.prototype.$myMethod = function () {...} Vue.prototype.$myProperty = xxxx }
-
使用插件:
Vue.use()
main.js中导入插件 并通过Vue.use使用挂载插件
组件自定义事件
-
一种组件间通信的方式,适用于:子组件 ===> 父组件
-
使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
-
绑定自定义事件:
-
第一种方式,在父组件中:
<Demo @atguigu="test"/>
或<Demo v-on:atguigu="test"/>
-
触发自定义事件:
this.$emit('atguigu',数据)
-
test(name,...params){ console.log('App收到了学生名:',name,params) this.studentName = name }, this.$emit('atguigu',this.name,666,888,900)
-
-
解绑自定义事件
this.$off('atguigu')
-
若想让自定义事件只能触发一次,可以使用
once
修饰符,或$once
方法。-
this.$off('atguigu') //解绑一个自定义事件 this.$off(['atguigu','demo']) //解绑多个自定义事件 this.$off() //解绑所有的自定义事件
-
-
第二种方式,在父组件中:
- 这个方式要当组件挂载完毕之后才可以去获取 灵活性强可以对绑定事件前进行异步操作
-
<Demo ref="demo"/> ...... mounted(){ this.$refs.demo.$on('atguigu',回调) }
-
三 通过props
-
<School :getSchoolName="getSchoolName"/> props:['getSchoolName'],
-
-
组件上也可以绑定原生DOM事件,需要使用
native
修饰符。-
直接给Student绑定一个原生的点击事件
-
<Student ref="student" @click.native="show"/>
-
-
注意:通过
this.$refs.xxx.$on('atguigu',回调)
绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!
-
全局事件总线
-
一种组件间通信的方式,适用于任意组件间通信。
-
安装全局事件总线:
new Vue({ ...... beforeCreate() { Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm }, ...... })
-
使用事件总线:
-
接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。
mounted() { this.$bus.$on('hello',(data)=>{ console.log('我是School组件,收到了数据',data) })
-
提供数据:
this.$bus.$emit('xxxx',传递数据)
data() { return { name:'张三', sex:'男', } }, methods: { sendStudentName(){ this.$bus.$emit('hello',this.name) }
-
-
最好在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件。
消息订阅与发布
-
一种组件间通信的方式,适用于任意组件间通信。
-
使用步骤:
-
安装pubsub:
npm i pubsub-js
-
引入:
import pubsub from 'pubsub-js'
-
接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。
this.pubId = pubsub.subscribe('hello',(msgName,data)=>{ console.log(this) // console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data) }) }, beforeDestroy() { // this.$bus.$off('hello') pubsub.unsubscribe(this.pubId) //取消订阅 },
-
提供数据:
pubsub.publish('xxx',数据)
sendStudentName(){ // 类似 this.$bus.$emit('hello',this.name) pubsub.publish('hello',666) //发布消息 }
- 最好在beforeDestroy钩子中,用
PubSub.unsubscribe(pid)
去取消订阅。
-
nextTick
- 语法:
this.$nextTick(回调函数)
- 作用:在下一次 DOM 更新结束后执行其指定的回调。
- 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。
插槽
-
作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件 。
-
分类:默认插槽、具名插槽、作用域插槽
-
默认插槽:
父组件中: <Category> <div>html结构1</div> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot>插槽默认内容...</slot> </div> </template>
- 当父组件使用子组件里有多个根节点时,会把所有根节点当做一个节点插入,要实现指定插入使用具名插槽,就只是多指定一个name属性
-
具名插槽:
父组件中: <Category> <template slot="center"> <div>html结构1</div> //单个结构可以不使用template 直接使用<div slot='center'></div> </template> <template v-slot:footer> //v-slot与slot 只是方法的新与旧 都可以使用 <div>html结构2</div> </template> </Category> 子组件中: <template> <div> <!-- 定义插槽 --> <slot name="center">插槽默认内容...</slot> <slot name="footer">插槽默认内容...</slot> </div> </template>
-
-
作用域插槽:
-
理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)
-
使用 绑定自身的数据 在使用方可以通过
-
获取
这两个也是方法新旧的 都可以使用
-
必须使用template进行接收 接收的是一个对象需要scopeData.games获取数据
-
-
具体编码:
父组件中: <Category> <template scope="scopeData"> <!-- 生成的是ul列表 --> <ul> <li v-for="g in scopeData.games" :key="g">{{g}}</li> </ul> </template> </Category> <Category> <template slot-scope="scopeData"> <!-- 生成的是h4标题 --> <h4 v-for="g in scopeData.games" :key="g">{{g}}</h4> </template> </Category> 子组件中: <template> <div> <slot :games="games"></slot> </div> </template> <script> export default { name:'Category', props:['title'], //数据在子组件自身 data() { return { games:['红色警戒','穿越火线','劲舞团','超级玛丽'] } }, } </script>
-
动画
- 过度类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hht8RLnp-1660566003942)(C:\Users\sxf\AppData\Roaming\Typora\typora-user-images\image-20220529143047254.png)]
transition组件
-
使用此组件包裹需要实现动画效果的东西 只能包裹一个组件
-
两个属性 name(可省略) appear(默认false)
-
指定name属性 则为自定义类名(优先级高)
- 指定name属性后过度类型则变为name-enter
- appear开启初始渲染动画 也可单独添加渲染效果设置
- appear-class(初始的class样式)
- appear-active-class(整个过程的样式)
- appear-to-class (结束的样式)
-
<transition name="hello" appear> <h1 v-show="isShow">你好啊!</h1> </transition>
-
方式一 借助keyframse动画实现 /* 初始状态 */ h1{ background-color: orange; } /* 开始样式 */ .hello-enter-active{ animation: atguigu 0.5s linear; } /* 结束样式 */ .hello-leave-active{ animation: atguigu 0.5s linear reverse; } /* 动画效果 */ @keyframes atguigu { from{ transform: translateX(-100%); } to{ transform: translateX(0px); } } 方式二 过渡 h1{ background-color: orange; } /* 进入的起点、离开的终点 */ .hello-enter,.hello-leave-to{ transform: translateX(-100%); } /* 动画过程 */ .hello-enter-active,.hello-leave-active{ transition: 0.5s linear; } /* 进入的终点、离开的起点 */ .hello-enter-to,.hello-leave{ transform: translateX(0); }
transition-group组件
- 可以包裹多组件 使用方法与上一致
- 需要指定key值
animate.css
-
动画库
-
<transition-group appear //配置动画库 name="animate__animated animate__bounce" //开始动画 enter-active-class="animate__swing" //结束动画 leave-active-class="animate__backOutUp" > <h1 v-show="!isShow" key="1">你好啊!</h1> <h1 v-show="isShow" key="2">尚硅谷!</h1> </transition-group>
css3动画
配置代理
原因:违背了同源策列
-
代理服务器的端口和本身是一样的
-
在发请求时 请求是转发给代理服务器 首先会先判断自身有没有 如果有就不会发给代理服务器了
-
代理服务器配置接收到请求转发的地址 可配置请求前缀开启多个代理
-
axios.get('http://localhost:8080/students').then( response => { console.log('请求成功了',response.data) }, error => { console.log('请求失败了',error.message) }
-
//开启代理服务器(方式一) module.exports = { devServer: { proxy: 'http://localhost:5000' } } 缺点:不能配置多个代理
-
axios.get('http://localhost:8080/demo/students').then( response => { console.log('请求成功了',response.data) }, error => { console.log('请求失败了',error.message) } //开启代理服务器(方式二) devServer: { proxy: { '/atguigu': { target: 'http://localhost:5000', pathRewrite:{'^/atguigu':''}, //重写路径 去除前缀在发过去 // ws: true, //用于支持websocket // changeOrigin: true //用于控制请求头中的host值 }, '/demo': { target: 'http://localhost:5001', pathRewrite:{'^/demo':''}, // ws: true, //用于支持websocket // changeOrigin: true //用于控制请求头中的host值 } } }
- changeOrigin
- 默认true 用于代理服务器如实告诉接收请求方自己请求的地址
- 就是骗不骗人 true骗 收到的请求是和自己一样的
- false 就如实显示发请求的地址
- changeOrigin
-
-
路由router
编程式导航
基本使用
-
使用
<router-view>
进行占位 -
<router-link to="">
链接跳转 -
配置路由
const routes = [ { path:'/', redirect:'/Nav' 重定向 当访问/或初次加载时访问 }, { path:'/Gengduo', component:Gengduo } { path:'/Nav', component:Nav, children:[ 子路由 { path:'/', redirect:'Home' }, { path:'Mine', component:Mine } ] } ]
$route
params :id
动态路由就是增加了一个传参
this当前组件实例 存在许多方法 可自行查看
<router-link to="/ss/1" > 传参
{
path:"/ss:id" 通过冒号id进行设置
}
this.$route.params.id 通过这个进行获取
也可以为跳转链接 添加props=true吗 也可以在路由规则里添加 开启props传参
获取时就直接通过props获取
路由的props配置
作用:让路由组件更方便的收到参数
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件 处理query参数
props(route){ 可以使用解构或者连续解构
return {
id:route.query.id,
title:route.query.title
}
}
}
声明式导航
$router
-
通过触发事件来进行跳转 参数可以通过加号来连接
this.$router.push('/movie'+id)
在路由规则里为相应的路由设置name属性
导航守卫
在路由js文件中设置
vuex
state
-
提供唯一的公共数据源,所有的共享数据统一放在Store的State进行存储
-
两种访问方式
1.this.$Store.state.全局数据名称 2.从vuex中导入mapState函数 import {mapState} from 'vuex' 在将全局属性映射为当前组件的计算机属性 //...为展开运算符 computed:{ ...mapState(['数据名']) 或者 } //借助mapState生成计算属性,从state中读取数据。(对象写法) // ...mapState({he:'sum',xuexiao:'school',xueke:'subject'}), //借助mapState生成计算属性,从state中读取数据。(数组写法) ...mapState(['sum','school','subject']),
Mutation
- 用于变更Store中的数据 只能通过Mtation进行变更 不能直接操作Store
- 不要在mutation中执行异步操作
state 为vuex的Store实例 第二个参数为模块调用该方法时传入的参数
mutation:{
addN(state,step){} 定义方法来进行变更
}
-
两种触发方式
1.this.$store.commit('调用的方法',传入参数) 2.从vuex导入mapMutation import {mapMutation} from 'vuex' 将需要的mutations函数映射为当前组件的methedss方法 metheds:{ ...mapMutation(['方法1','方法2']) }
Action
- 用于执行异步操作 要通过Mutation的方式更变数据
actions:{
addNas('context',参数){}
}
// 第一个参数必定为context 他拥有和Store相同的属性和方法
-
两种触发方式
1.this.$store.dispath('addNas',参数) 2.导入mapAction import {mapAction} from 'vuex' 将指定的action方法映射为当前组件方法 methods:{ ...mapAtion(['方法','方法']) }
-
与Mutation结合使用
在actions中使用context调用commit方法与Mutation结合
Getter
-
用于对Store中的数据进行加工处理形成新的数据,不会改变原数据,只起到一个包装的作用,类似于vue的计算属性
这个参数state就是vuex的state ss为state的数据 gets1为包装后的*新数据* getters:{ gets1:state=>{ return '当前最新数据是【'+state.ss+'】' } }
- 两种调用方式
1.this.$store.getter.名称 2.导入mapGetter import {mapGetter} from 'vuex' 将要用到的属性映射为当前组件的计算机属性 computed:{ ...mapGtter(['属性名','属性名']) }
mudules
- 可以让每一个模块拥有自己的store(state、mutation、action、getter),使结构清晰,方便管理
- 如果所有的状态管理都写在同一个store,会非常臃肿
//一个模板store
const moduleA = {
state:{
name:"Rick"
},
mutations:{
moduleAupdname(state){
state.name = "Liu"
}
},
getters:{
},
actions:{
}
}
//vuex主store 在modules进行注册命名
const store = new Vuex.Store({
state:{
},
mutations:{
},
getters:{
},
actions:{
},
modules:{
a:moduleA 《================
}
})
在调用时方法一样的
this.$store.a.state.属性 这里的a是选择模板的命名 指定去寻找相应的模板的属性 a也可以省略 省略后 后先去寻找主模板 找不到就按去寻找子模板
namespaced命名空间
-
开启命名空间后,组件中读取state数据:
//方式一:自己直接读取 this.$store.state.personAbout.list //方式二:借助mapState读取: ...mapState('countAbout',['sum','school','subject']),
-
开启命名空间后,组件中读取getters数据:
//方式一:自己直接读取 this.$store.getters['personAbout/firstPersonName'] //方式二:借助mapGetters读取: ...mapGetters('countAbout',['bigSum'])
-
开启命名空间后,组件中调用dispatch
//方式一:自己直接dispatch this.$store.dispatch('personAbout/addPersonWang',person) //方式二:借助mapActions: ...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})
-
开启命名空间后,组件中调用commit
//方式一:自己直接commit this.$store.commit('personAbout/ADD_PERSON',person) //方式二:借助mapMutations: ...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),
总结
Promise
概念
Promise是异步编程的一种解决方案,其实是一个构造函数,自己身上有all reject resolve 几个方法,原型上有then catch等
几个特点
//Promise的两个参数
new Promise(function(resolve,reject){
resolve('要返回的数据可以是任何数据 例如接口数据') 成功调用方法
reject('数组不够') 失败调用回方法
}).then(成功时回调function(data){},失败时回调function(){}) data成功接受的数值
.catch((reason)=>{
console.log(reason) reason失败原因
})
Promise.all([f,f]).then(成功回调function(results){
console.log(results)
})
all接受一个数组为所有需要异步的Promise的对象 (创建几个加几个所以成功才会回调)
results all会把所以成功的回调传给then 通过then的成功回调将所有结果进行打包成一个数组
Promise.race([f,f]).then(成功失败回调()=>{}) 赛跑 谁先执行完就谁用回调 其余不行 也可以让所有f进行异步
- 对象状态不受外界影响,Promise对象代表一个异步操作,有三个状态
- pending (进行中)
- fulfilled (已成功)
- rejected (已失败)
- 只有异步操作的结果决定这三个状态 任何其他操作都无法改变
- 一旦状态改变,就不会在变,任何时候都可以得到这个结果 Promise对象状态改变只有两种可能
- pending 到 fulfilled
- pending 到 rejected
- 只要发生一种 状态就不会改变 这个时候称之为resolved(已定型)
- 我们new一个Promise对象 没有调用他 当我们传进去函数就已经执行了 在使用时一般包在一个函数里 等待函数调用触发
- 传入的函数会返回一个Promise对象
then
- then() 和我们使用的回调函数差不多 他可以接受一个参数 是接受resolve(或reject返回的错误原因)返回的数据这时就返回了‘要返回的数据可以是任何数据 例如接口数据’
- 可以连续.then() (链式编程) 因为Promise每次都会返回一个新的Promise对象
catch
与try catch类似 用来捕获异常
all()
他提供了异步操作的能力,Promise方法(Promise.all()执行) 通过调用他将所以操作进行异步 在所有都成功时才回调
all接受一个数组为所有需要异步的Promise的对象 (创建几个加几个所以成功才会回调)
results all会把所以成功的回调传给then 通过then的成功回调将所有结果进行打包成一个数组
rece
这个是 谁先执行完就执行then 类似与赛跑机制 不管是成功回调还是失败回调 其余的都不会在进入race任何回调 会进行异步执行 执行自己的方法进行返回
Axios
简介
axios框架全称 (Ajax I/O system)
- 基于promise用于浏览器和node.js的http客户端,因此可以使用PromiseAPI
请求方式
- get 获取数据,请求指定信息,返回实体对象
- post 向指定资源提交数据
- put 更新数据,从客户端向服务器传送数据取代指定的文档的内容
- path 更新数据,是对put方法的补充,用来对已知资源进行局部更新
- delete 请求服务器删除指定数据
get
方法一
this.$axios.get('/goods.json',{
parms:{
id:1 parms 为请求的地址后的参数 也可要直接写在url中 /goods.json?id=1
}
}).then(res=>{
console.log(res.data)
},err=>{
console.log(err)
})
方法二
this.$axios({
method:'get',
url:'/goods.json',
parms:{
id:1
}
}).then()
post
- post请求分为两种类型
- form-data 表单提交,图片上传,文件上传,用这个比较多
- application/json 一般用于Ajax异步请求
- params是添加到url的请求字符串中的,用于get请求。
data是添加到请求体(body)中的, 用于post请求。
application/json 请求
方法一
this.$axios.post('/url',{
id:1
}).then(res=>{
console.log(res.data)
},err=>{})
方法二
this.$axios({
method:'post',
url:'/url',
data:{
id:1 请求的参数 get是带在url上是请求路径 post是请求体 url不带参数 用data
}
}).then()
form-data 请求 提交表单数据
let data = {
请求参数
}
let formdata = new FormData();
for(let key in data){
fromdata.append(key,data[key])
}
this.$axios.post('/good.json',fordata).then() 将上传数据封装到formdata中 进行请求提交
put path
put请求
this.$axios.put('/url',{
id:1
}).then()
path请求
this.$axios.path('/url',{
id:1
}).then()
delete
参数以明文形式提交
this.$axios.delete('/url',{
params:{
id:1
}
}).then
参数以封装对象形式提交
this.$axios.delete('/url',{
data:{
id:1
}
}).then()
方法二
axios({
method:'delete',
url:'/url',
params:{ 明文形式提交
id:1
},
data:{
id:1 封装对象形式提交
}
}).then()
all
-
并发请求
-
同时进行多个请求,并统一处理返回值
-
发送多个请求(并发请求),类似于promise.all,若一个请求出错,那就会停止请求
this.$axios.all([---------------------------------------------
this.$axios.get(/g1.json),
this.$axios.get(/g2.json)
]).then(-------------------------------------------------------
this.$axios.spread((g1,g2)=>{ spread 成功时的处理 失败会停止请求
console.log(g1.data)
console.log(g2.data)
})
)
axios实例
创建axios实例
通过create创建axios实例 并取名字
- baseURL 请求的域名,基本地址,类型:String
- timeout 请求超时时长,单位ms,类型:Number
- url 请求路径,类型:String
- method 请求方法,类型:String
- headers 设置请求头,类型:Object
- params 请求参数,将参数拼接在URL上,类型:Object
- data 请求参数,将参数放到请求体中,类型:Object
let instance = this.$axios.create({
baseURL: 'http://localhost:9090',
timeout: 2000
})
instance.get('/goods.json').then(res=>{
console.log(res.data);
})
————————————————
版权声明:本文为CSDN博主「柠檬树上柠檬果柠檬树下你和我」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_39765048/article/details/117688019
axios全局配置
示例代码
//配置全局的超时时长
this.$axios.defaults.timeout = 2000; default设置默认属性
//配置全局的基本URL
this.$axios.defaults.baseURL = 'http://localhost:8080';
axios实例配置
示例代码
let instance = this.$axios.create();
instance.defaults.timeout = 3000;
axios请求配置
this.$axios.get('/goods.json',{
timeout: 3000
}).then()
以上配置的优先级为:请求配置 > 实例配置 > 全局配置
拦截器
拦截器:在请求或响应被处理前拦截它们
1、请求拦截器
this.$axios.interceptors.request.use(config=>{
// 发生请求前的处理
return config
},err=>{
// 请求错误处理
return Promise.reject(err);
})
//或者用axios实例创建拦截器
let instance = $axios.create();
instance.interceptors.request.use(config=>{
return config
})
2、响应拦截器
示例代码
this.$axios.interceptors.response.use(res=>{
//请求成功对响应数据做处理
return res //该返回对象会传到请求方法的响应对象中
},err=>{
// 响应错误处理
return Promise.reject(err);
})
3、取消拦截
let instance = this.$axios.interceptors.request.use(config=>{
config.headers = {
token: ''
}
return config
})
//取消拦截
this.$axios.interceptors.request.eject(instance);
4、错误处理
示例代码
this.$axios.get('/url').then(res=>{
}).catch(err=>{
//请求拦截器和响应拦截器抛出错误时,返回的err对象会传给当前函数的err对象
console.log(err);
})
5、取消请求
let source = this.$axios.CancelToken.source();
this.$axios.get('/goods.json',{
cancelToken: source
}).then(res=>{
console.log(res)
}).catch(err=>{
//取消请求后会执行该方法
console.log(err)
})
//取消请求,参数可选,该参数信息会发送到请求的catch中
source.cancel('取消后的信息');
原型与原型链
图解
原型概念
新对象在原型的基础之上建立起来 同时也会继承原型的相应属性和方法
prototype
-
原型的意思 通过函数的方式创建obj对象 此函数可以调用proto来获取对象的原型
-
对象obj没有这个 属性
_proto_
- 每个对象都会有这个属性 用来指向该对象的原型
construction
- 每一个原型都有construction属性 用来指向关联的构造函数
- 同时对象继承原型,也会拥有这个方法 指向构造函数
总结 实例与原型
当读取实例对象的属性时,如果没有找到则会找他的原型,还没有,就原型的原型,一直到最顶层
通过这样的一层层关系 组成了原型链
更多推荐
所有评论(0)