目录
案例
一Vue基础
什么是Vue?
vue 是一个mvvm 框架,Model-View-ViewModel,是一个MVC 的前端版本
补充:mvvm框架
mvvm的组成
ViewModel 是一个控制器的角色,在他里面实现逻辑运算等这样就可以把Model层和View层
高度分离。
View:视图,用于封装和展示数据以及效果,其实就是html结构。
Model:数据模型,用来封装数据以及数据运行的业务逻辑。
详解
MVVM的一个关键特征是数据绑定。在典型的MVVM框架中,视图和模型之间通过ViewModel实现双向数据绑定。当模型的数据发生变化时,ViewModel会负责更新视图,反之亦然。这降低了手动管理DOM的复杂性,提高了代码的可维护性。
一些流行的前端框架,如Vue.js和Angular,采用了MVVM的设计模式。这些框架通过提供响应式的数据绑定、组件化、以及其他功能,简化了前端应用的开发流程。
举例来说,使用Vue.js的MVVM框架的代码可能如下所示:
<template>
<div>
<h1>{{ message }}</h1>
<input v-model="message">
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello, MVVM!'
};
}
};
</script>
在这个例子中,{{ message }}
是Vue.js中的模板语法,它会自动将message
数据绑定到对应的DOM元素上。当用户在输入框中输入时,数据会自动更新,反之亦然。这种双向数据绑定的机制是MVVM框架的核心概念之一。
Vue的使用方法
使用vue的方法
1.通过script 引入vue文件
2.可以通过vue-cli 创建vue项目,进行开发
1.直接下载并引入
<script src="./js/vue.global.js"></script>
<script>
//解构出一个创建应用的方法
const {createApp} = Vue;
//创建应用
createApp({
//设置数据
data(){
return{
str:'wbg加油'
}
}
}).mount('#app');
</script>
2.通过 CDN 使用 Vue
在HTML文件中通过
<script>
标签引入Vue.js的CDN链接,如下所示:
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
3.通过npm安装
使用npm(Node Package Manager)可以将Vue.js安装为项目的依赖项。首先,在项目目录下运行以下命令安装Vue.js:
npm install vue
然后,在JavaScript文件中通过import
语句引入Vue:
import Vue from 'vue';
4.使用Vue CLI创建项目
Vue CLI(命令行界面)是一个官方提供的工具,用于快速搭建Vue项目。首先,全局安装Vue CLI:
npm install -g @vue/cli
然后,通过以下命令创建新项目:
vue create my-vue-project
进入项目目录,运行以下命令启动开发服务器:
cd my-vue-project
npm run serve
在这种方式下,Vue.js会被自动安装并作为项目的依赖项。
二插值表达式
什么是插值表达式?
{{ }} :插值表达式,在他的里面可以执行 vue的变量,表达式,也可以执行函数,插值表达式实际上是一个js的域,在插值表达式中可以执行简单的js语句,并且把执行结果返回到插值表达式所在的dom结构的位置上。
插值表达式的缺点
初次加载的时候文本闪烁
解决方法
解决方法
1.把vue文件引入到head中,不建议使用
2.使用指令 v-cloak 来隐藏数据没有加载完成的dom结构,这样可以解决页面开始时候的闪烁问题
该指令的运行方式是,首先隐藏没有编译成功的dom结构,等到dom编译成功之后,会自动把隐藏的方式去掉
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>插值表达式</title>
<style>
*{
margin: 0;
padding: 0;
}
/* //使用属性选择器,绑定v-cloak 属性的内容 */
[v-cloak]{
display: none;
}
</style>
</head>
<body>
<div id="app">
<p v-cloak>{{ str }}</p>
<p v-cloak>{{ 1+1 }}</p>
<p v-cloak>{{ 3>4?'wbg':'vue'}}</p>
<p v-text="str"></p>
<div v-html="str1"></div>
<p>{{obj.name+'演唱'+obj.song}}</p>
</div>
</body>
</html>
<script src="./js/vue.global.js"></script>
<script>
const {createApp}=Vue;
let app = createApp({
/*
data函数中存放当前页面中所有的数据,如果需要声明数据,必须声明在data中
data是一个方法,发的返回值是一个对象,data必须有返回值,否则报错
*/
data(){
return{
str:'伤不起,香水有毒',
str1:'<h2>老鼠爱大米</h2>',
obj:{
name:'伍佰',
song:'挪威的森林',
}
}
}
})
app.mount('#app')
</script>
三 属性绑定
在vue中,{{}}插值表达式不能直接绑定属性的值
可以使用 v-bind来绑定属性
语法是
v-bind:属性名 = '属性值/变量名'
简写方式 :属性名 = '属性名/变量名'
<body>
<!--
属性绑定
在vue中,{{}}插值表达式不能直接绑定属性的值
可以使用 v-bind来绑定属性
语法是
v-bind:属性名 = '属性值/变量名'
简写方式
:属性名 = '属性名/变量名'
-->
<div id="app">
<a v-bind:href="'http://jd.com'">微博</a>
<a v-bind:href="url">微博</a>
<a :href="url">微博简写</a>
</div>
</body>
</html>
<script src="./js/vue.global.js"></script>
<script>
const { createApp } = Vue;
createApp({
data(){
return{
url:'https://www.sina.com.cn'
}
}
}).mount('#app')
</script>
绑定style
<!-- 绑定style -->
<h2 :style="{ color:'#04be02',fontSize:'30px' }">{{ str }}</h2>
<div :style="style"></div>
<div :style="'font-size:20px;color:#f00;'">多行不义必自毙</div>
<div :style="[ {color:'#04be02'},{ fontSize:'30px' } ]">多行不义必自毙</div>
<div class="abc">柳宗元</div>
<div :class="'abc aa'">曾巩</div>
数组形式绑定class
<div :class="[ 'abc','aa' ]">韩愈</div>
对象形式绑定class
使用对象形式绑定class,属性名为class名,属性的值是一个boolean值,如果布尔值为true,则绑定该class名,否则不绑定
<div :class="{'abc':3>4,'aa':3<4}">苏轼</div>
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绑定style和class</title>
<style>
* {
margin:0;
padding:0;
}
.abc {
width:200px;
height: 200px;
background:#f60;
margin:30px auto;
}
.aa {
background:#f0f;
}
</style>
</head>
<body>
<div id="app">
<!-- 绑定style -->
<h2 :style="{ color:'#04be02',fontSize:'30px' }">{{ str }}</h2>
<div :style="style"></div>
<div :style="'font-size:20px;color:#f00;'">多行不义必自毙</div>
<div :style="[ {color:'#04be02'},{ fontSize:'30px' } ]">多行不义必自毙</div>
<div class="abc">柳宗元</div>
<div :class="'abc aa'">曾巩</div>
<!-- 使用 数组形式绑定class -->
<div :class="[ 'abc','aa' ]">韩愈</div>
<!-- 使用对象形式绑定class,属性名为class名,属性的值是一个boolean值,如果布尔值为true,则绑定该class名,否则不绑定 -->
<div :class="{'abc':3>4,'aa':3<4}">苏轼</div>
<!-- 总结:style和class的绑定都支持 数组形式和对象形式 -->
<div :class="3<4?className:''">欧阳修</div>
<div :class="3<4&&className">欧阳封</div>
</div>
</body>
</html>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
createApp({
data(){
return {
str:'从此君王不早朝',
style:{
height:'200px',
width:'200px',
background:'#04be02'
},
className:'abc'
}
}
}).mount('#app');
</script>
四事件绑定
绑定事件
v-on:事件名= "表达式/方法名"
方法名的参数问他,如果没有参数可以不用加()
事件绑定指令的简写
@时间名="表达式/方法名"
<button v-on:click="num++">点击++</button>
<button v-on:click="show('天涯何处有房产')">点击显示</button>
<button @click="show('天涯何处没有草')">点击显示</button>
<button @click="()=>show('天涯何处没有草')">点击显示</button>
<hr>
<button @click="num++">点击显示或者隐藏元素</button>
<div class="wp" :style="{display:num%2==0?'block':'none'}"></div>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
num:100
}
}
//methods中存放了组件所有的方法,方法只能存储在 methods中
,methods: {
show(str){
alert('东边日出西边雨'+str)
}
},
}).mount('#app')
事件的修饰符
vue提供了事件的修饰符,用来提高开发效率
@事件名.修饰符.修饰符.修饰符...=触发方式
stop 阻止事件冒泡
prevent 阻止默认事件
once 只执行一次事件
self当event.target是当前绑定元素的时候触发
capture 事件捕获的时候触发
passive 触发滚动事件的默认行为
相关代码
<body>
<div id="app">
<p>{{num}}</p>
<button @click="add">点击添加</button>
<div class="wp" @click="showInfo">
<div class="cont" @click.stop.once="showMsg" @contextmenu.prevent="showMsg" > </div>
</div>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
num:100
}
},
methods: {
add(){
//在vue实例中获取data中的数据,直接
this.num++
},
showInfo(){
console.log('外层触发');
},
showMsg(){
console.log('内层触发');
}
}
}).mount('#app')
</script>
按键修饰符
按键修饰符,当按下或者抬起对应对应修饰符的按键时触发事件
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
.exact 非系统键
相关代码
<body>
<div id="app">
<input type="text" value="" @keyup.enter="show"> <br>
<textarea cols="30" rows="10" @keyup.up="show"></textarea>
<!-- 非系统键 -->
<input type="text" value="" @keyup.exact="show">
</div>
</body>
</html>
<script type="module">
/*
按键修饰符,当按下或者抬起对应对应修饰符的按键时触发事件
.enter
.tab
.delete (捕获“Delete”和“Backspace”两个按键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
.exact 非系统键
*/
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {}
},
methods: {
show(e){
console.log(e.target.value);
}
},
}).mount('#app')
五数据双向绑定
在表单元素中使用v-model 实现数据的双向绑定
双向绑定:简言之就是数据在视图层的更改会立即体现在model层,反之在model层的改变也会立即体现在视图层。
设置单选框的 v-model
<!-- 设置单选框的 v-model -->
<label>性别</label>
<label><input type="radio" name="sex" v-model="sex" value="男">男</label>
<label><input type="radio" name="sex" v-model="sex" value="女">女</label>
<button @click="showSex">点击显示选择的性别</button>
<br>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
val:'货卖堆山',
val2:'男要俏一身皂',
sex:'男',
hero:['张居正','海瑞','王阳明','朱熹'],
num:'100',
str:'玩物丧志'
}
}
,methods: {
show(){
alert(this.val2)
},
showSex(){
alert(this.sex)
},
showHero(){
console.log(this.hero);
},
showNum(){
console.log(this.num);
}
},
}).mount('#app')
</script>
设置复选框的 v-model
<label for="">英雄</label>
<label for=""><input type="checkbox" v-model="hero" value="张居正">张居正</label>
<label for=""><input type="checkbox" v-model="hero" value="海瑞">海瑞</label>
<label for=""><input type="checkbox" v-model="hero" value="王阳明">王阳明</label>
<label for=""><input type="checkbox" v-model="hero" value="朱熹">朱熹</label>
<label for=""><input type="checkbox" v-model="hero" value="张载">张载</label>
<label for=""><input type="checkbox" v-model="hero" value="程颐">程颐</label>
<br>
<button @click="showHero">选中的值</button>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
val:'货卖堆山',
val2:'男要俏一身皂',
sex:'男',
hero:['张居正','海瑞','王阳明','朱熹'],
num:'100',
str:'玩物丧志'
}
}
,methods: {
show(){
alert(this.val2)
},
showSex(){
alert(this.sex)
},
showHero(){
console.log(this.hero);
},
showNum(){
console.log(this.num);
}
},
}).mount('#app')
</script>
修饰符
number 修饰符
把输入框中的内容转化为数字
trim 修饰符
去掉输入内容左右两变的空格
lazy 修饰符
把input事件改为change事件 (可以优化性能)
<input type="number" v-model.number="num">
<p>{{num}}</p>
<button @click="showNum">点击显示数字</button>
<hr>
<input type="text" v-model.lazy="str">
<p style="border: 1px #f00 solid;">{{str}}</p>
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据双向绑定</title>
</head>
<body>
<div id="app">
<input type="text" :value="val" @input="e=>val=e.target.value">
<p>{{val}}</p>
<!-- 在表单元素中使用v-model 实现数据的双向绑定
双向绑定:简言之就是数据在视图层的更改会立即体现在model层,反之在model层的改变
也会立即体现在视图层
-->
<input type="text" v-model="val2">
<p>{{val2}}</p>
<button @click="show">点击显示</button>
<hr>
<!-- 设置单选框的 v-model -->
<label>性别</label>
<label><input type="radio" name="sex" v-model="sex" value="男">男</label>
<label><input type="radio" name="sex" v-model="sex" value="女">女</label>
<button @click="showSex">点击显示选择的性别</button>
<br>
<!-- 设置复选框的 v-model
设置复选框的 v-model的值是一个数组,该数组存储复选框选中的内容
-->
<label for="">英雄</label>
<label for=""><input type="checkbox" v-model="hero" value="张居正">张居正</label>
<label for=""><input type="checkbox" v-model="hero" value="海瑞">海瑞</label>
<label for=""><input type="checkbox" v-model="hero" value="王阳明">王阳明</label>
<label for=""><input type="checkbox" v-model="hero" value="朱熹">朱熹</label>
<label for=""><input type="checkbox" v-model="hero" value="张载">张载</label>
<label for=""><input type="checkbox" v-model="hero" value="程颐">程颐</label>
<br>
<button @click="showHero">选中的值</button>
<hr>
<!-- 修饰符
number 修饰符,把输入框中的内容转化为数字
trim 修饰符,去掉输入内容左右两变的空格
lazy 修饰符,把input事件改为change事件 (可以优化性能)
-->
<input type="number" v-model.number="num">
<p>{{num}}</p>
<button @click="showNum">点击显示数字</button>
<hr>
<input type="text" v-model.lazy="str">
<p style="border: 1px #f00 solid;">{{str}}</p>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
val:'货卖堆山',
val2:'男要俏一身皂',
sex:'男',
hero:['张居正','海瑞','王阳明','朱熹'],
num:'100',
str:'玩物丧志'
}
}
,methods: {
show(){
alert(this.val2)
},
showSex(){
alert(this.sex)
},
showHero(){
console.log(this.hero);
},
showNum(){
console.log(this.num);
}
},
}).mount('#app')
</script>
六常用指令
v-if和v-show
v-show 指令,如果他的值是true,则他所绑定的元素显示,否则他绑定的元素会自动添加一个display:none 无隐藏,v-show改变的是css样式,属于元素重绘
v-if 指令,如果他的值是true,则他所绑定的元素从dom树中对应的位置渲染,如果为false,他所绑定的元素会在dom书中删除
v-if 改变的是dom树的结构,属于元素重排
v-else-if 需要结合 v-if使用,用法同js的if- else-if
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-if和v-show</title>
<style>
*{
margin: 0;
padding: 0;
}
.wp{
width: 200px;
height: 200px;
background: #04be02;
}
</style>
</head>
<body>
<div id="app">
<div class="wp" v-show="bol">show</div>
<div class="wp" v-if="bol">if</div>
<button @click="show">点击显示或者隐藏</button>
<hr>
<div v-if="num%2==0">晚上吃啥{{num}}</div>
<div v-else-if="num%3==0">螺蛳粉{{num}}</div>
<div v-else>麻辣烫{{num}}</div>
<button @click="num++">点击++</button>
<ul>
<li v-for="(item,index) in arr">
{{item+index}}
<button @click="arr.splice(index,1)">删除</button>
</li>
</ul>
<button @click="add">添加数组</button>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
createApp({
data() {
return {
bol:true,
num:1,
arr:['晚上吃啥','螺蛳粉','麻辣烫']
}
}
,methods: {
show(){
this.bol = !this.bol
},
add(){
this.num+=1;
this.arr.push('老母鸡汤'+this.num)
}
},
}).mount('#app')
</script>
v-for循环
v-for 结合 template 标签(组件)循环数据
template 标签 不会被渲染到页面上,一般用来实现数据绑定的功能
注意
v-for
语法:v-for="形参 in 数组/对象"
如果需要 下标或者对象的属性 v-for="(形参,下标形参/属性名形参) in 数组/对象"
使用 v-for 的标签元素,都需要绑定一个key属性,属性的值一般都是要循环对象中的唯一值(列如id)
使用key属性的目的是 使已经渲染过的列表内容不再从新渲染, 提高列表的渲染效率,注意 index 虽然可以设置key的值,但是由于index的值
会发生变化,这样会导致 列表从新渲染 因此慎用
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-for</title>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,index) in arr" :key="index" @click="showAlert(item.name)">
<span>{{index}}-{{item.name}}:{{item.nickname}}</span>
</li>
</ul>
<hr>
<ul v-for="aa in arr">
<li>{{aa.name}}:{{aa.nickname}}</li>
</ul>
<p v-for="(item,key) in obj">{{key}}:{{item}}</p>
<hr>
<!--
v-for 结合 template 标签(组件)循环数据
template 标签 不会被渲染到页面上,一般用来实现数据绑定的功能
-->
<template v-for="item in arr" :key="item.name">
<p>{{item.name}}</p>
</template>
<hr>
<!-- 循环数字,一般是整数,每一个整体是一个循环的项 -->
<p v-for="n in 10">{{n}}</p>
<!-- 循环字符串 -->
<p v-for="t in set">{{t}}</p>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js'
createApp({
data() {
return {
arr:[
{
name:'吕布',
nickname:'奉先'
},
{
name:'马岱',
nickname:'丁玲'
},
{
name:'马超',
nickname:'孟起'
},
{
name:'文鸳',
nickname:'文鸳'
},
],
obj:{
name:'孙尚香',
age:20,
job:'射手'
},
str:'念天地之悠悠,独怆然而涕下'
}
},
methods: {
showAlert(str){
alert(str)
}
},
}).mount('#app')
</script>
其他内置指令
v-pre
他所绑定的元素不进行vue的编译,原样输出
v-once
他所绑定的元素只渲染一次,忽略之后所有的更新
相关代码
<body>
<div id="app">
<!-- v-pre 他所绑定的元素不进行vue的编译,原样输出 -->
<p>{{str}}</p>
<!-- v-once 他所绑定的元素只渲染一次,忽略之后所有的更新 -->
<p v-once>{{num}}</p>
<button @click="num++">点击++</button>
<hr>
<!-- <div v-for="(item,index) in arr" v-memo="arr">{{item}}</div>
<button @click="change">点击改变数据</button> -->
<!-- 实现组件内容的缓存,如果他的值不发生改变,那么他绑定的元素内部不会各跟
据数据的改变而重新渲染 -->
<div v-memo="arr">
<h1>{{str}}</h1>
</div>
<button @click="change1">点击改变数据</button>
</div>
</body>
</html>
<script type="module" >
import {createApp} from './js/vue.esm-browser.js'
createApp({
data() {
return {
str:'诸葛亮',
num:100,
arr:['诸葛亮','诸葛瑾']
}
},
methods: {
change(){
this.arr.push('诸葛均')
},
change1(){
this.arr.push('诸葛均')
this.str = '司马光'
}
},
}).mount('#app')
</script>
七计算属性
如果在插值表达式中直接渲染数据,非常方便,但是如果有比较复杂的逻辑运算,{{}}的渲染效率就会受到影响,并且不利于后期维护,因此可以把比较复杂的运算逻辑放到计算属性中。
注意
每个计算属性,实际上都包含 get和set两个方法,默认是get方法
在计算属性的get方法中,不要异步请求数据(ajax)或者操作dom
给计算属性设置值的时候,执行的是set方法
从计算属性获取值的时候,执行的是 get方法
计算属性的优点
1.数据没有发生变化的时候,优先读取缓存在computed中经过逻辑运算操作的数据,把数据渲染在dom树中,并且不用考虑 methods和watch中数据的变化
2.计算属性值会基于其响应式依赖被缓存
3.他有get方法和set方法,可以进行灵活设置
get在获取的时候被触发,如果没有set,则默认是get
set在数据设置的时候被触发
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>计算属性</title>
</head>
<body>
<div id="app">
<h2>{{num}}</h2>
<p>{{str.split('').reverse().join('')}}</p>
<p>{{changeStr}}</p>
<template v-for="item in arr">
<p v-if="item%2==0">{{item}}</p>
</template>
<p v-for="item in numArr">{{item}}</p>
<h1>{{aa}}</h1>
<button @click="setVal('零陵上将邢道荣')">点击设置</button>
</div>
</body>
</html>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
let app = createApp({
data() {
return {
num:100,
str:'相见时难别亦难东风无力百花残',
arr:[1,2,3,4,5,6,7,8,9],
txt:'尔今死去'
}
},
methods: {
setVal(str){
//设置计算属性的值
this.aa = str;
}
},
//设置计算属性
computed:{
changeStr(){
return this.str.split('').reverse().join('')
},
numArr(){
return this.arr.filter(item=>{
return item%2 == 0;
})
} ,
aa:{
get(){
return this.txt +'-林黛玉'
},
set(val){
console.log(val);
this.txt = val;
}
} ,
}
})
app.mount('#app')
</script>
八侦听器
什么场景下需要侦听器
如果需要数据的变化来执行操作,可以使用数据侦听器
书写方法
书写侦听器的方法:
方法名就是侦听器侦听data数据中数据的属性名,该方法具有两个参数
第一个参数是 数据当前的值(新值) 第二个参数是 数据变化之前的值(老值)
//数据侦听
watch:{
num(newVal,oldVal){
let r = this.rand(0,255);
let g = this.rand(0,255);
let b = this.rand(0,255);
console.log(newVal,oldVal);
if (newVal%10==0) {
this.col =`rgb(${r},${g},${b})`
}
},
val(newVal,oldVal){
console.log(newVal,oldVal);
},
//设置侦听器的深度监听
obj:{
//设置监听的回调方法
handler(newVal,oldVal){
console.log(newVal,oldVal);
},
//设置深度监听
deep:true,
//设置加载立即监听
immediate:true
},
//监听对象中某一个属性的变化
//可通过此方法,直接监听路由对象的变化
'obj.name':{
//设置监听的回调方法
handler(newVal,oldVal){
console.log('监听名字的变化');
console.log(newVal,oldVal);
},
}
}
设置外部的侦听器
app.$watch('name',(newVal,oldVal)=>{
console.log(newVal,oldVal);
})
九生命周期
生命周期常用函数
Mounted() 注册一个回调函数,在组件挂载完成后执行。
Updated() 注册一个回调函数,在组件因为响应式状态变更而更新其 DOM 树之后调用 Unmounted() 注册一个回调函数,在组件实例被卸载之后调用。
beforeCreate 在组件实例初始化完成之后立即调用。
created() 在组件实例处理完所有与状态相关的选项后调用。
BeforeMount() 注册一个钩子,在组件被挂载之前被调用
BeforeUpdate() 注册一个钩子,在组件即将因为响应式状态变更而更新其 DOM 树之前调用。
BeforeUnmount()注册一个钩子,在组件实例被卸载之前调用。
相关代码
<body>
<div id="app">
<h1 id="abc">{{num}}</h1>
<button @click="num++">点击++</button>
<ul id="list">
<li v-for="(item,index) in arr" :key="index">{{item}}</li>
</ul>
<button @click="add">点击添加高端学府</button>
<button @click="die">销毁组件实例</button>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
let app=createApp({
data(){
return{
str:'中午吃啥',
num:100,
arr:['郑州大学','西亚斯学院','郑州科技学院']
}
},
//在组件实例初始化完成之后立即调用。此刻其他的属性和方法均没有执行或者编译
beforeCreate(){
console.log(this.str);
},
/*
在组件实例处理完所有与状态相关的选项后调用。当这个钩子被调用时,以下内容已经设置完成:响应式数据、计算属性、方法和侦听器。然而,此时挂载阶段还未开始,因此 $el 属性仍不可用。此时不能操作dom
*/
created(){
console.log('created',this.str);
let abc=document.querySelector('#abc');
console.log(abc);
this.num+=100;
},
/*
vue的组件模板,如果在实例中设置的有组件的模板,则会替换掉挂载的dom元素
模板的第一层需要是一个完整的dom元素(vue2版本)
*/
// template:`
// <h3>{{num}}</h3>
// <h2>{{str}}</h2>
// `
/*
在组件被挂载之前调用。此刻还没有挂载任何模板,因此还无法操作dom
*/
beforeMount(){
console.log('beforeMount');
},
/*
组件被挂之后调用。此时,所有的模板内容都已经被挂载,可以操作组件中所有的dom
常用此钩子函数来进行,加载立即执行的操作
*/
mounted(){
console.log('mounted');
this.show()
},
methods:{
show(){
let abc=document.querySelector('#abc');
console.log(abc);
abc.style.border='1px #f00 solid ';
},
add(){
this.arr.push('河南建筑职业技术学院');
},
die(){
//销毁vue实例
// this.$destroy();
//解绑/卸载vue实例
console.log(app);
app.unmount();
}
},
/*
beforeUpdate 钩子 数据更新前触发,显示的数据是更新后的数据
但是如果改变了dom结构,那么改函数中的dom结构是更新前的内容
*/
beforeUpdate(){
let list=document.querySelector('#list');
console.log('beforeUpdate',this.num,list.innerHTML);
},
/*
Update 钩子 数据更新后触发,显示的数据是更新后的数据
但是如果改变了dom结构,那么该函数中的dom结构是更新后的内容
*/
updated(){
console.log('updated',this.num,list.innerHTML);
},
/*
在一个组件实例被卸载之前调用。
*/
beforeUnmount(){
console.log('beforeUnmount');
},
/*
在一个组件实例被卸载之后调用。
*/
unmounted(){
log('unmounted');
},
});
//挂载
app.mount('#app');
</script>
十自定义属性
<body>
<div id="app">
<div v-aa="'#f0f'" class="wp"></div>
<div v-abc="col" class="wp">
<button @click="col='#000'">点击更新</button>
</div>
</div>
</body>
</html>
<script type="module">
import {createApp} from './js/vue.esm-browser.js'
createApp({
data() {
return {
col:'#0ff'
}
},
methods: {
},
//自定义指令
directives:{
/*
aa是指令名,
参数
el表示的是自定义指令绑定的元素
binding 是一个对象 包含是属性是
value 传递给指令的值。
oldValue 指令绑定的数据或者元素内部发生改变的值,
仅在beforeUpdate 和 updated中有值
*/
aa(el,binding){
console.log(el,binding);
el.onmouseenter=()=>{
el.style.background = '#f00'
}
el.onmouseleave=()=>{
el.style.background = binding.value
}
},
//配置指令
abc:{
created(el,binding) {
console.log('created',el,binding);
},
mounted(el,binding) {
el.onmouseenter=()=>{
el.style.background = '#f00'
}
el.onmouseleave=()=>{
el.style.background = binding.value
}
},
updated(el,binding) {
console.log('更新了',binding.oldValue);
el.onmouseleave=()=>{
el.style.background = binding.value
}
},
}
}
}).mount('#app')
十一组件
组件基础
组件,将来项目开发的时候使用的都是组件,组件具有极高的复用性
注册组件
外部注册组件的关键字是 component 在实例内部注册组件。属性名为 components
app.component(组件名,组件的配置)
组件的命名
1.命名不能和原生html冲突
2.可以使用驼峰,使用驼峰的时候,在视图模版中书写,驼峰的大写字母可以变为 - , 列如abcd 使用的时候写 <ab-cd/>
3.推荐使用w3c的命名规则 aa-bb
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>组件基础</title>
<style>
*{
margin: 0;
padding: 0;
}
</style>
</head>
<body>
<div id="app">
<h1>{{name}}</h1>
<abc></abc>
<my-show></my-show>
<my-run></my-run>
</div>
</body>
</html>
<template id="run">
<h1>辛弃疾</h1>
<h2>柳永</h2>
<h2>{{name}}</h2>
</template>
<script type="module">
import {createApp} from './js/vue.esm-browser.js'
let app = createApp({
data() {
return {
name:'袁世凯'
}
},
//实例的内部注册组件
components:{
'myShow':{
template:'<p class="abc">最喜小儿无赖</p>',
data(){
return {
nme:'孙终末'
}
}
},
//w3c 推荐
'my-run':{
template:'#run',
data() {
return {
name:'原神启动'
}
},
}
}
})
//外部注册
app.component('abc',{
template:`
<h1>相顾无言,惟有泪千行</h1>
<h1>相顾无言,惟有泪千行</h1>
<h1>相顾无言,惟有泪千行</h1>
<h1>相顾无言,惟有泪千行</h1>
`
})
app.mount('#app')
</script>
外部组件配置
<body>
<div id="app">
<abc></abc>
<abc></abc>
</div>
</body>
</html>
<template id="abc">
<h1>郑州科技学院-郑科公园</h1>
<h1>我在郑科很想你{{num}}</h1>
<button @click="add">点击++</button>
</template>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
let abc = {
template:'#abc',
data(){
return {
num:100,
}
},
methods: {
add(){
this.num++;
},
mounted(){
this.add();
},
components:{
aa:{
template:'<h4>组件内部的</h4>'
}
}
},
}
createApp({
data() {
return {
};
},
components:{
abc:abc
}
}).mount('#app');
</script>
组件的属性
给组件设置属性,属性名设置在一个数组中,简写
props:['abc','aa','obj']
设置属性的具体类型,设置属性的多样性
props:{
abc:{
//设置属性abc的值,必须是一个字符串
type:String
},
设置默认属性
obj:{
type:Object,
//设置默认值,对象类型的默认值是一个函数,返回一个默认对象
default(){
return {
name:'燕青',
age:20
}
}
},
设置必读属性
aa:{
type:String,
//设置为必写属性
required:true,
//设置属性的默认值,当属性没有值的时候,默认显示的内容
default:'中午吃啥子'
}
十二组件传值
父传子
组件中,通过 this.获取所有携带属性的子组件实例,refs是一个集合 this.$refs.aa 就可以 获取 ref="aa" 的 组件实例
methods:{
change(){
//获取组件实例
console.log(this.$refs.son);
//执行组件实例中的方法
this.$refs.son.add();
this.$refs.wp.innerHTML=this.$refs.son.num;
}
}
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ref</title>
<style>
*{
margin: 0;
padding: 0;
}
.wp{
width: 200px;
height: 200px;
background: #04be02;
}
</style>
</head>
<body>
<div id="app">
<show ref="son"></show>
<button @click="change">点击++</button>
<div class="wp" ref="wp"></div>
</div>
</body>
</html>
<template id="show">
<h2>{{num}}</h2>
</template>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
/*
组件中通过this.$refs 获取所有携带ref属性的子组件实例
this.$refs 是一个集合,this.$refs.aa 就可以获取 ref="aa" 的组件实例
*/
let show = {
data() {
return {
num:1,
}
},
template:'#show',
methods: {
add(){
this.num++;
}
},
}
createApp({
data() {
return {
}
},
components:{
show:show
},
methods:{
change(){
//获取组件实例
console.log(this.$refs.son);
//执行组件实例中的方法
this.$refs.son.add()
this.$refs.wp.innerHTML = this.$refs.son.num;
}
}
}).mount('#app')
</script>
子传父
解析
使用 $emit() 触发自定义事件,并且可以传递参数
子组件中的操作
this.$emit('event-name',args参数)
然后把 event-name 绑定到子组件上
<son @event-name="父组件的接收方法"></son>
过程:
子组件中 执行 this.$emit() ,触发了 绑定在子组件上的 event-name,然后执行父组件的接收方法,
父组件的接收方法接收一个默认的参数,参数的值是 子组件中 this.$emit传递的参数,这样通过参数的形式,
把数据从子组件传递到父组件
$parent 获取当前组件的父组件,如果没有父组件则返回null
$root 获取当前组件的根组件,如果当前组件没有父组件,则返回当前组件
$emit 在当前组件触发一个自定义事件。任何额外的参数都会传递给事件监听器的回调函数。
this.$emit('abc',this.msg);
},
相关代码
<body>
<div id="app">
<h1>{{info}}</h1>
<button @click="">点击++</button>
<son @abc="changeInfo"></son>
</div>
</body>
</html>
<template id="son">
<div class="wp">
<h1>{{msg}}</h1>
<button @click="pass">点击传递给父组件</button>
<button @click="getFu">点击获取父组件</button>
</div>
</template>
<script type="module">
import {createApp} from './js/vue.esm-browser.js';
let son={
data(){
return{
msg:'道不轻传'
}
},
template:'#son',
methods:{
pass(){
// $emit 在当前组件触发一个自定义事件。任何额外的参数都会传递给事件监听器的回调函数。
this.$emit('abc',this.msg);
},
//通过获取父组件的实例传递数据
getFu(){
// this.$parent.changeInfo(this.msg);
this.$root.changeInfo(this.msg);
}
}
};
createApp({
data(){
return{
info:'稻香'
}
},
components:{
son
},
methods:{
changeInfo(data){
console.log('触发方法',data);
this.info=data;
}
}
}).mount('#app');
</script>
非父子传值
<body>
<div id="app">
<h1>摇滚不死</h1>
<son1></son1>
<son2></son2>
</div>
</body>
</html>
<template id="son1">
<div class="son1">
<h2>子组件1</h2>
<h4>{{msg}}</h4>
<button @click="pass">点击传递给子组件2</button>
</div>
</template>
<template id="son2">
<div class="son2">
<h2>子组件2</h2>
<h4>{{info}}</h4>
</div>
</template>
<!-- 引入 mitt 插件 的js -->
<script src="https://unpkg.com/mitt/dist/mitt.umd.js"></script>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
//引入mitt实例
let bus = mitt();
console.log( bus );
//声明两个组件
let son1 = {
template:'#son1',
data(){
return {
msg:'假行僧'
}
},
methods: {
pass(){
//执行 mitt 实例中的 emit() 方法,来触发自定义事件 并且 传递参数
bus.emit('abc', this.msg);
}
},
};
let son2 = {
template:'#son2',
data(){
return {
info:'一块红布'
}
},
mounted() {
//执行 mitt 实例中的 on() 方法,来监听 自定义事件是否被触发,如果被触发,则执行回调函数
//回调函数默认传入一个参数,该参数的值即为 通过 emit 触发事件传递的数据
bus.on('abc',data=>{
this.info = data;
});
},
};
createApp({
data(){
return {
}
},
components:{
son1:son1,
son2:son2
}
}).mount('#app');
</script>
provide和inject
</head>
<body>
<div id="app">
<h1>{{str}}</h1>
<zi />
</div>
</body>
</html>
<template id="zi">
<div class="wp">
<h1>子组件</h1>
<p>{{msg}}</p>
<sun></sun>
</div>
</template>
<template id="sun">
<div class="wp">
<h1>孙组件</h1>
<p>{{msg}}</p>
</div>
</template>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
let sun = {
template:'#sun',
//通过inject 直接接收 provide 传递的数据
inject:['msg']
}
let zi = {
template:'#zi',
components:{
sun
},
inject:['msg']
};
createApp({
data() {
return {
str:'却惹六千烦恼丝'
}
},
//配置直接传入后代的值
// provide:{
// msg:'却惹三千烦恼丝',
// },
//如果直接获取 data 中的数据作为传递到后代组件的数据,则使用函数的形式返回数据
provide(){
return{
msg:this.str
}
},
components:{
zi
}
}).mount('#app')
</script>
十三动态组件
动态组件 使用标签 component 该组件具有一个 is 属性,is 属性的值 是 要渲染组件的名字,即为is属性的值是哪一个组件名,components标签就会渲染哪一个组件
缺点: component 可以动态渲染组件的内容,但是每一次切换,都会重新渲染组件内容,降低渲染效率
使用 keep-alive 标签(组件),可以缓存曾经渲染过的组件,从而提高渲染
<body>
<div id="app">
<div class="wp">
<span :class="num==1&&'on'" @click="num=1">水浒传</span>
<span :class="num==2&&'on'" @click="num=2">红楼梦</span>
<span :class="num==3&&'on'" @click="num=3">西游记</span>
<span :class="num==4&&'on'" @click="num=4">三国演义</span>
</div>
<!-- <comp1 v-if="num==1"></comp1>
<comp2 v-if="num==2"></comp2>
<comp3 v-if="num==3"></comp3>
<comp4 v-if="num==4"></comp4> -->
<!--
动态组件 使用标签 component
该组件具有一个is属性,is属性的值 是 要渲染组件的名字,即为is属性的值是哪一个组件名,
component 标签就会渲染哪一个组件
缺点:component 可以动态渲染组件的内容,但是每一个切换,都会重新渲染组件内容,降低渲染效率
使用keep-alive 标签(组件),可以缓存曾经渲染过的组件,从而提高渲染效率
-->
<keep-alive>
<component :is="'comp'+num"></component>
</keep-alive>
</div>
</body>
</html>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
let comp1={
template:'<h1>水浒传</h1>'
}
let comp2={
template:'<h1>红楼梦</h1>'
}
let comp3={
template:`
<h1>西游记</h1>
<p>{{n}}</p>
<button @click = "n++">点击++</button>
`,
data() {
return {
n:100,
}
},
}
let comp4={
template:'<h1>三国演义</h1>'
}
let aa = {
template:'<h1>金瓶梅</h1>'
}
createApp({
data() {
return {
num:1,
}
},
components:{
comp1,comp2,comp3,comp4,aa
}
}).mount('#app')
</script>
十四插槽
插槽 指的是 写入自定义组件中包括的内容,一般都是html结构或者自定义组件
插槽的出口,在自定义内部,设置一个slot标签,表示插槽的出口,将来插槽的内容会渲染在slot标签所在的位置
如果需要不同的 插槽内容渲染在 组件中不同的位置,那么就需要使用具名插槽。具名插槽的名字设置当是是
1.在插槽的内部部分,设置v-slot: 插槽名 来包裹需要渲染在具体位置的html内容结构
2.在自定义组件中,设置slot 在对应的位置,并且slot 的name 属性值是 插槽名
注意
v-slot:插槽名 可以简写成 #插槽名
使用指令 v-slot 绑定的插槽名字可以是一个变量
v-slot:[变量名] #[变量名]
<body>
<div id="app">
<son1>
<h2>一夫当关,鸡犬升天</h2>
<p>我爱云和</p>
</son1>
<son2>
<template v-slot:header>
<h3 slot="header">一人得道鸡犬升天</h3>
</template>
<p>芶使郑州</p>
<p>鸡你太美</p>
<p>鸡你太美</p>
<p>鸡你</p>
<template #footer>
<h3>风吹草低见牛羊</h3>
</template>
<hr>
<son3>
<template #[dog]>
<h3>一人得道鸡犬升天</h3>
</template>
<button @lick="dog='footer'">点击修改插槽的值</button>
</son3>
</son2>
</div>
</body>
</html>
<template id="son1">
<slot></slot>
<h1>一眼碗面</h1>
</template>
<template id="son2">
<slot></slot>
<h1>方便面</h1>
<slot></slot>
<slot name="footer"></slot>
</template>
<template id="son3">
<slot name="footer">
<h1>中午吃啥</h1>
</slot>
</template>
<script type="module">
import { createApp } from './js/vue.esm-browser.js';
let son1 ={
template:'#son1'
}
let son2={
template:'#son2'
}
let son3={
template:'#son3'
}
createApp({
data() {
return {
dog:'header'
}
},
components:{
son1,son2,son3
}
}).mount('#app')
</script>
十五过渡动画
设置过渡的流程
1,把需要使用过渡的动画的元素使用 transition 组件包裹起来
2.给transition 组件设置一个name属性
3.给name属性的值,设置过渡动画
4.控制元素或者组件的显示或者隐
过度动画的应用场景
1.结合 v-if 使用
2.结合 v-show 使用
3.结合 路由切换 使用
transition-group 组件,常用来操作一系列数据,他具有一个tag属性,可以把当前的transition-group组件 渲染为tag属性设置的html标签
相关代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过度动画</title>
<style>
*{
margin: 0;
padding: 0;
}
.wp{
width: 200px;
height: 200px;
background: pink;
}
.aa-enter-active,
.aa-leave-active {
transition: opacity 1s ease;
}
.aa-enter-from,
.aa-leave-to {
opacity: 0;
}
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from,
.list-leave-to {
opacity: 0;
transform: translateX(30px);
}
</style>
</head>
<body>
<div id="app">
<transition name="aa">
<div class="wp" v-show="bol"></div>
</transition>
<button @click="bol=!bol">点击</button>
<hr>
<!--
设置动画组
-->
<transition-group name="list" tag="ul">
<li v-for="(n,index) in arr" :key="index">{{n}}</li>
</transition-group>
<button @click="arr.push('前端开发')">点击添加</button>
</div>
</body>
</html>
<script type="module">
/*
设置过渡的流程
1,把需要使用过渡的动画的元素使用 transition 组件包裹起来
2.给transition 组件设置一个name属性
3.给name属性的值,设置过渡动画
4.控制元素或者组件的显示或者隐藏
transition-group 组件,常用来操作一系列数据,他具有一个tag属性,可以把当前的transition-group组件
渲染为tag属性设置的html标签
过度动画的应用场景
1.结合 v-if 使用
2.结合 v-show 使用
3.结合 路由切换 使用
*/
import { createApp } from './js/vue.esm-browser.js';
createApp({
data() {
return {
bol:true,
arr:['java','c++','ui设计','php']
}
},
}).mount('#app')
</script>