Vue是一套用于构建用户界面的渐进式JavaScript框架。
尤雨溪
Vue官网:https://cn.vuejs.org/
官网导航菜单栏中最重要的是教程和API。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>初识Vuetitle>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>Hello,{{name}}h1>
div>
<script>
Vue.config.productionTip = false; //阻止Vue在启动时生成生产提示
//创建Vue实例
new Vue({
el:'#root', //el用于指定当前Vue实例为那个容器服务,值通常为css选择器字符串。
data:{ //data中用于存储数据,数据供el所指定的容器使用,值我们暂时先写成一个对象。
name:'尚硅谷'
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>初识Vuetitle>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>Hello,{{name.toUpperCase()}},{{address}},{{Date.now()}}h1>
div>
<script>
Vue.config.productionTip = false; //阻止Vue在启动时生成生产提示
//创建Vue实例
new Vue({
el:'#root',
data:{
name:'shangguigu',
address:'北京'
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>模板语法title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>1-插值语法:h1>
<h3>你好,{{name}}h3>
<hr>
<h1>2-指令语法:h1>
<a v-bind:href="school.url">点我去{{school.name}}学习a>
div>
body>
<script>
Vue.config.productionTip = false; //阻止Vue在启动时生成生产提示
new Vue({
el:'#root',
data:{
name:'jack',
school:{
name:'尚硅谷',
url:'http://www.atguigu.com'
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据绑定title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
1-单项数据绑定:<input type="text" v-bind:value="name">
<br>
2-双项数据绑定:<input type="text" v-model:value="name">
<hr>
1-单项数据绑定(简写方式实现):<input type="text" :value="name">
<br>
2-双项数据绑定(简写方式实现):<input type="text" v-model="name">
<hr>
div>
body>
<script>
new Vue({
el:"#root",
data:{
name:"尚硅谷"
}
})
script>
html>
Vue中一个重要的原则:
由Vue管理的函数,一定不要写箭头函数,一旦写了箭头函数,this就不再是Vue实例了。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>el的两种写法title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>你好,{{name}}h1>
div>
body>
<script>
var v = new Vue({
// 容器挂载第一种写法
// el:'#root',
data:{
name:'尚硅谷'
}
})
// 输出Vue实例
console.log(v);
// 1秒后执行
setTimeout(()=>{
// 容器挂载第二种写法
v.$mount('#root');
},1000)
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>data的两种写法title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>你好,{{name}}h1>
div>
body>
<script>
var v = new Vue({
el:'#root',
// data的第一种写法:对象式
/* data:{
* name:'尚硅谷'
* }
*/
// data的第一种写法:函数式
data:function(){
console.log('@@@',this) //此处的this是Vue实例对象
return {
name:'尚硅谷'
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MVVM模型title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>学校名称:{{name}}h1>
<h1>学校地址:{{address}}h1>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'北京'
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>回顾Object.defineproperty方法title>
head>
<body>
<script>
let person = {
name:'张三',
sex:'男'
}
Object.defineProperty(person,'age',{
value:18,
enumerable:true, //控制属性是否可以枚举,默认值是false
writable:true, //控制属性是否可以修改,默认值是false
configurable:true //控制属性是否可以被删除,默认值是false
})
console.log(Object.keys(person));
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>回顾Object.defineproperty方法title>
head>
<body>
<script>
let number = 18;
let person = {
name:'张三',
sex:'男',
}
Object.defineProperty(person,'age',{
// value:18,
// enumerable:true, //控制属性是否可以枚举,默认值是false
// writable:true, //控制属性是否可以修改,默认值是false
// configurable:true, //控制属性是否可以被删除,默认值是false
// 当有人读取person的age属性时,get函数就会被调用,且返回值就是age的值
get:function(){
console.log('有人读取了age属性了')
return number;
},
// 当有人修改person的age属性时,set函数就会被调用,且会收到修改的值
set(value){
console.log('有人修改了age属性,且值是30');
number = value;
}
})
// console.log(Object.keys(person));
console.log(person);
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>何为数据代理title>
head>
<body>
<script>
let obj = {x:100};
let obj2 = {y:200};
Object.defineProperty(obj2,'x',{
get(){
return obj.x;
},
set(value){
obj.x = value;
}
})
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vue中的数据代理title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
div>
body>
<script>
let data = {
name:'尚硅谷',
address:'宏福科技园'
}
const vm = new Vue({
el:'#root',
data
// data:{
// name:'尚硅谷',
// address:'宏福科技园'
// }
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件的基本使用title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
<button v-on:click="showInfo1">点我提示信息1(不传参)button>
<button @click="showInfo2(66,$event)">点我提示信息2(传参数)button>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷'
},
methods:{
showInfo1(event){
console.log(this); //此处的this是vm实例化对象
console.log(event.target.innerText);
alert('信息1:同学你好!');
},
showInfo2(number,event){
console.log(event);
alert('信息2:同学你好!!'+number);
},
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>事件修饰符title>
<script src="../js/vue.js">script>
<style>
*{
margin-top: 20px;
}
.demo1{
height: 50px;
background-color: skyblue;
}
.box1{
padding: 5px;
background-color: skyblue;
}
.box2{
padding: 5px;
background-color: pink;
}
.list{
width: 200px;
height: 200px;
background-color: peru;
overflow: auto;
}
li{
height: 100px;
}
style>
head>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
<a href="http://www.atguigu.com" @click.prevent="showInfo">点我提示信息a>
<div class="demo1" @click="showInfo">
<a href="http://www.atguigu.com" @click.stop.prevent="showInfo">点我提示信息a>
div>
<button @click.once="showInfo">点我提示信息button>
<div class="box1" @click.capture="showMessage(1)">
div1
<div class="box2" @click="showMessage(2)">
div2
div>
div>
<div class="demo1" @click.self="showInfo">
<button @click="showInfo">点我提示信息button>
div>
<ul class="list" @wheel.passive="demo">
<li>1li>
<li>2li>
<li>3li>
<li>4li>
ul>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷'
},
methods:{
showInfo(e){
alert('同学你好!');
// e.preventDefault(); //阻止默认事件
// e.stopPropagation(); //阻止事件冒泡
console.log(e.target);
},
showMessage(msg){
console.log(msg);
},
demo(){
for (let i = 0; i < 100000; i++) {
console.log('@'); //滚动输出@
}
console.log('累坏了');
}
}
})
script>
html>
键盘事件
keydown
:按下按键不用抬起来就可以触发事件;keyup
:按下按键抬起来才会触发事件;Vue中常用的按键别名:
enter
delete
esc
space
tab
(必须配合keydown使用)up
down
left
right
Vue未提供别名的按键,可以使用按键原始key值去绑定,但注意要转为kebab-case(短横线命名)
系统修饰键(用法特殊):ctrl
、alt
、shift
、meta(win键)
keyup
使用:按下修饰键的同时,再按下其他键,随后释放其他键,事件才被触发;keydown
使用,正常触发事件。也可以使用keyCode去指定具体的按键(不推荐)。
Vue.config.keyCode.自定义键名 = 键码
,可以去定制按键别名。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>键盘事件title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>欢迎来到{{name}}学习h2>
Enter键:<input type="text" placeholder="按下回车提示输入" @keyup.enter="showInfo">
<hr>
当按下Ctrl+Y键:<input type="text" placeholder="按下Ctrl+Y键提示输入" @keyup.ctrl.y="showInfo">
<hr>
CapsLock键:<input type="text" placeholder="按下CapsLock键提示输入" @keyup.caps-lock="showInfo">
<hr>
Enter键:<input type="text" placeholder="按下huiche键提示输入" @keyup.huiche="showInfo">
div>
body>
<script>
Vue.config.keyCodes.huiche = 13; //自定义键名称
new Vue({
el:'#root',
data:{
name:'尚硅谷',
},
methods:{
showInfo(e){
console.log(e.key);
console.log(e.keyCode);
// // 13为enter回车键
// if(e.keyCode != 13) return;
console.log(e.target.value);
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例_插值语法实现title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{firstName.slice(0,3)}}-{{lastName}}span>
div>
body>
<script>
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例_methods实现title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName()}}span>
div>
body>
<script>
new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
methods:{
fullName(){
return this.firstName+'-'+this.lastName;
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例_计算属性实现title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}span>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
fullName:{
// get有什么作用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值。
// get什么时候调用?1.初次读取fullName时,get会被调用。2.所依赖的数据发生变化时,get会被调用。
get(){
console.log('get就被调用了。');
return this.firstName + '-' + this.lastName;
},
// set()什么时候调用?当fullName被修改时,set就会被调用、
set(value){
console.log('set被调用了');
const arr = value.split('-');
this.firstName = arr[0];
this.lastName = arr[1];
}
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例_计算属性简写title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}span>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三'
},
computed:{
/* 1-完整写法
fullName:{
get(){
console.log('get就被调用了。');
return this.firstName + '-' + this.lastName;
},
set(value){
console.log('set被调用了');
const arr = value.split('-');
this.firstName = arr[0];
this.lastName = arr[1];
}
} */
// 2-简写写法:只考虑读取不考虑修改的时候用简写方式
fullName(){
console.log('get被调用了');
return this.firstName + '-' + this.lastName;
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>今天天气很{{info}}h2>
<button @click="changeWeather">切换天气1button>
<button @click="isHot = !isHot">切换天气2button>
div>
body>
<script>
new Vue({
el:'#root',
data:{
isHot:true
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽';
}
},
methods:{
changeWeather(){
this.isHot = !this.isHot;
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例_监视属性title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>今天天气很{{info}}h2>
<button @click="changeWeather">切换天气button>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
isHot:true
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽';
}
},
methods:{
changeWeather(){
this.isHot = !this.isHot;
}
},
// watch监视的第一种写法
watch:{
isHot:{
immediate:true, // 初始化时让handler调用一下。
// handler什么时候调用?当isHot发生改变时调用。
handler(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
},
info:{
immediate:true, // 初始化时让handler调用一下。
// handler什么时候调用?当isHot发生改变时调用。
handler(newValue,oldValue){
console.log('info修改了',newValue,oldValue);
}
}
}
})
// watch监视第二种写法
vm.$watch(
'isHot',
{
immediate:true,
handler(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
}
)
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例_监视属性title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>今天天气很{{info}}h2>
<button @click="changeWeather">切换天气button>
<hr>
<h3>a的值是{{numbers.a}}h3>
<button @click="numbers.a++">点我a+1button>
<hr>
<h3>b的值是{{numbers.b}}h3>
<button @click="numbers.b++">点我b+1button>
<hr>
<h3>彻底改变numbersh3>
<button @click="numbers = {a:11,b:22}">彻底改变numbersbutton>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1
}
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽';
}
},
methods:{
changeWeather(){
this.isHot = !this.isHot;
},
},
watch:{
isHot:{
// immediate:true,
handler(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
},
// 监视多级结构中某个属性的变化
'numbers.a':{
handler(){
console.log('a变了');
}
},
// 监视多级结构中所有属性的变化
numbers:{
deep:true,
handler(){
console.log('numbers彻底被改变了');
}
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>天气案例_监视属性_简写形式title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>今天天气很{{info}}h2>
<button @click="changeWeather">切换天气button>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
isHot:true,
numbers:{
a:1,
b:1
}
},
computed:{
info(){
return this.isHot ? '炎热' : '凉爽';
}
},
methods:{
changeWeather(){
this.isHot = !this.isHot;
},
},
watch:{
// 正常写法
/* isHot:{
immediate:true, //初始化时让hanlder调用一下
deep:true, //深度监视
handler(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
}, */
// 简写
isHot(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
}
})
// 正常写法
/* vm.$watch('isHot',{
immediate:true, //初始化时让hanlder调用一下
deep:true, //深度监视
handler(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}
}) */
// 简写形式
/* vm.$watch('isHot',function(newValue,oldValue){
console.log('isHot修改了',newValue,oldValue);
}) */
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>姓名案例_监视属性title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
姓:<input type="text" v-model="firstName"><br>
名:<input type="text" v-model="lastName"><br>
全名:<span>{{fullName}}span>
div>
body>
<script>
// 监视属性
const vm = new Vue({
el:'#root',
data:{
firstName:'张',
lastName:'三',
fullName:'张-三'
},
watch:{
firstName(newValue){
setTimeout(() => {
this.fullName = newValue + '-' + this.lastName;
}, 1000);
},
lastName(newValue){
this.fullName = this.firstName + '-' + newValue;
}
}
})
script>
html>
computed
和watch
之间的区别:
computed
能完成的功能,watch
都能完成;watch
能完成的功能,computed
不一定能完成,例如:watch
可以进行异步操作;两个重要的小原则:
写法:class=”xxx”
xxx可以是字符串、对象、数组。
字符串写法适用于:类名不确定,要动态获取。
对象写法适用于:要绑定多个样式,个数不确定,名字也不确定;
数组写法适用于:要绑定多个样式,个数确定,名字也确定,但是不确定用还是不用;
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绑定样式title>
<script src="../js/vue.js">script>
<style>
.basic{
width: 400px;
height: 100px;
border:1px solid black;
}
.happy{
background-color: red;
}
.sad{
background-color: green;
}
.normal{
background-color: pink;
}
.mod1{
font-family: '宋体';
font-size: 25px;
}
.mod2{
color: red;
}
.mod3{
background-color: pink;
}
style>
head>
<body>
<div id="root">
<div id="mode" class="basic" :class="mood" @click="changeMood">{{name}}div>
<hr>
<div class="basic" :class="classArr">{{name}}div>
<hr>
<div class="basic" :class="classObj">{{name}}div>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
mood:'normal',
classArr:['mod1','mod2','mod3'],
classObj:{
mod1:false,
mod2:true
}
},
methods:{
changeMood(){
// document.getElementById('mode').className = 'basic happy';
const arr = ['happy','sad','normal'];
const index = Math.floor(Math.random()*3);
this.mood = arr[index];
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绑定样式title>
<script src="../js/vue.js">script>
<style>
.basic{
width: 400px;
height: 100px;
border:1px solid black;
}
style>
head>
<body>
<div id="root">
<div class="basic" :style="styleObj">{{name}}div>
<br><hr><br>
<div class="basic" :style="[styleObj1,styleObj2]">{{name}}div>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
styleObj:{
fontSize:'40px',
color:'red',
backgroundColor:'green'
},
styleObj1:{
fontSize:'40px',
color:'red',
},
styleObj2:{
backgroundColor:'green'
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>条件渲染title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2 v-show="true">1欢迎来到{{name}}h2>
<h2 v-show="a">2欢迎来到{{name}}h2>
<h2 v-show="1==1">3欢迎来到{{name}}h2>
<h2 v-if="false">4欢迎来到{{name}}h2>
<h2 v-if="1==1">5欢迎来到{{name}}h2>
<br><hr>
<h2>当前的n值是{{n}}h2>
<button @click="n++">点我n++button>
<hr>
v-show
<div v-show="n==1">1div>
<div v-show="n==1">11div>
<div v-show="n==3">3div>
<hr>
v-if
<div v-if="n==1">1div>
<div v-if="n==1">11div>
<div v-if="n==3">3div>
<hr>
v-else-if
<div v-if="n==1">1div>
<div v-else-if="n==1">11div>
<div v-else-if="n==3">3div>
<div v-else>v-else其他div>
<h2 v-show="n==1">你好h2>
<h2 v-show="n==1">尚硅谷h2>
<h2 v-show="n==1">北京h2>
<template v-if="n==1">
<h2>你好h2>
<h2>尚硅谷h2>
<h2>北京h2>
template>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
a:true,
n:1
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>1.基本列表title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<ul>
<li v-for="p in persons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.id}}
li>
ul>
<hr>
<h2>遍历对象:汽车信息h2>
<ul>
<li v-for="(value,key) of car">
{{key}}--{{value}}
li>
ul>
<hr>
<h2>遍历字符串h2>
<ul>
<li v-for="(char,index) of str" :key="index">
{{char}}-{{index}}
li>
ul>
<hr>
<h2>遍历指定次数h2>
<ul>
<li v-for="(num,index) of 5">
{{num}}-{{index}}
li>
ul>
div>
body>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20},
],
car:{
name:'奥迪A8',
price:'70w',
color:'黑色'
},
str:'HELLO'
}
})
script>
html>
key是虚拟DOM对象的标识,当状态中的数据发生变化时,vue会根据新数据生成新的虚拟DOM,随后vue进行新虚拟DOM与旧虚拟DOM的差异比较,比较规则如下。
对比规则: 旧虚拟DOM中找到了与新虚拟DOM相同的key: 若虚拟DOM中内容没变,直接使用之前的真实DOM;
若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM。 旧虚拟DOM中未找到与新虚拟DOM相同的key:
创建新的真实DOM,随后渲染到页面上。
若对数据进行:逆序添加、逆序删除等破坏顺序的操作: 会产生没有必要的真实DOM更新→界面效果没有问题,但是效率低。
如果结构中还包含输入类DOM: 会产生错误DOM更新→界面有问题。
最好使用每条数据的唯一标识作为key,比如id、手机号、身份证号、学号等唯一值。
如果不存在对数据的逆序添加、逆序删除等破坏顺序的操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>2.key的原理title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<button @click.once="add">添加一个老刘button>
<ul>
<li v-for="(p,index) in persons" :key="index">
{{p.name}}-{{p.age}}-{{index}}
<input type="text">
li>
ul>
<hr>
<h2>遍历数组:人员列表h2>
<button @click.once="add">添加一个老刘button>
<ul>
<li v-for="p in persons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.id}}
<input type="text">
li>
ul>
<hr>
div>
body>
<script>
new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'张三',age:18},
{id:'002',name:'李四',age:19},
{id:'003',name:'王五',age:20},
],
},
methods:{
add(){
const p = {id:'004',name:'老刘',age:40};
this.persons.unshift(p); //unshift()方法将新项添加到数组的开头,并返回新的长度。
}
}
})
script>
html>
当watch属性和computed属性都可以实现的时候,最好是使用过computed属性,用起来比较方便一些。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3.列表过滤_watch写法title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="p in filterPersons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}-{{p.id}}
li>
ul>
<hr>
div>
body>
<script>
// 用watch实现
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18,sex:'女'},
{id:'002',name:'周冬雨',age:19,sex:'女'},
{id:'003',name:'周杰伦',age:20,sex:'男'},
{id:'004',name:'温兆伦',age:21,sex:'男'},
],
filterPersons:[]
},
watch:{
/* // 简写监视出现bug
keyWord(val){
console.log('keyWord被改变为:'+val); //使用监听事件拿到变化的数据
// 使用filter生成新的数组替换掉原来的persons就可以实现页面效果,但是更改了原来的数据有bug
this.filterPersons = this.persons.filter((p)=>{
// indexOf方法是判断字符串中存在第几位,如果返回-1则表示不存在
// indexOf一个空字符串是0
return p.name.indexOf(val) != -1;
})
} */
// 这种情况不要写成简写形式的监视
keyWord:{
immediate:true,
handler(val){
this.filterPersons = this.persons.filter((p)=>{
return p.name.indexOf(val) != -1;
})
}
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>4.列表过滤_computed写法title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<ul>
<li v-for="p in filterPersons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}-{{p.id}}
li>
ul>
<hr>
div>
body>
<script>
// 用computed实现
new Vue({
el:'#root',
data:{
keyWord:'',
persons:[
{id:'001',name:'马冬梅',age:18,sex:'女'},
{id:'002',name:'周冬雨',age:19,sex:'女'},
{id:'003',name:'周杰伦',age:20,sex:'男'},
{id:'004',name:'温兆伦',age:21,sex:'男'},
],
},
computed:{
filterPersons(){
return this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) != -1;
})
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>5.列表排序title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<input type="text" placeholder="请输入名字" v-model="keyWord">
<button @click="sortType=2">年龄升序button>
<button @click="sortType=1">年龄降序button>
<button @click="sortType=0">原顺序button>
<ul>
<li v-for="p in filterPersons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}-{{p.id}}
li>
ul>
<hr>
div>
body>
<script>
// 用computed实现
new Vue({
el:'#root',
data:{
keyWord:'',
sortType:'0', //排序类型:0:原顺序,1:降序,2:升序。
persons:[
{id:'001',name:'马冬梅',age:40,sex:'女'},
{id:'002',name:'周冬雨',age:30,sex:'女'},
{id:'003',name:'周杰伦',age:10,sex:'男'},
{id:'004',name:'温兆伦',age:20,sex:'男'},
],
},
computed:{
filterPersons(){
const arr = this.persons.filter((p)=>{
return p.name.indexOf(this.keyWord) != -1;
})
// 判断下是否需要排序
if(this.sortType != 0){
arr.sort((p1,p2)=>{
return this.sortType == 1 ? p2.age-p1.age : p1.age-p2.age;
})
}
return arr;
}
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>6.更新时的一个问题title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>遍历数组:人员列表h2>
<button @click="updateMa">更新马冬梅信息button>
<ul>
<li v-for="p in persons" :key="p.id">
{{p.name}}-{{p.age}}-{{p.sex}}-{{p.id}}
li>
ul>
<hr>
div>
body>
<script>
// 用computed实现
const vm = new Vue({
el:'#root',
data:{
persons:[
{id:'001',name:'马冬梅',age:40,sex:'女'},
{id:'002',name:'周冬雨',age:30,sex:'女'},
{id:'003',name:'周杰伦',age:10,sex:'男'},
{id:'004',name:'温兆伦',age:20,sex:'男'},
],
},
methods: {
updateMa(){
// 以下代码生效
// this.persons[0].name = '马老师',
// this.persons[0].age = 50,
// this.persons[0].sex = '男'
// 以下代码未生效
// this.persons[0] = {id:'001',name:'马老师',age:50,sex:'男'}
// 以下代码奏效
this.persons.splice(0,1,{id:'001',name:'马老师',age:50,sex:'男'});
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>8.Vue.set的使用title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
<hr>
<h1>学生信息h1>
<button @click="addSex">添加一个性别属性button>
<h2>学生姓名:{{student.name}}h2>
<h2 v-if="student.sex">学生性别:{{student.sex}}h2>
<h2>学生年龄:真实:{{student.age.rAge}},对外:{{student.age.sAge}}h2>
<h2>朋友们h2>
<ul>
<li v-for="f in student.friends" :key="index">
{{f.name}}---{{f.age}}
li>
ul>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29,
},
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
},
methods: {
addSex(){
// 两种方法都可以实现
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>9.Vue监测数据改变的原理_数组title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h2>学校名称:{{name}}h2>
<h2>学校地址:{{address}}h2>
<hr>
<h1>学生信息h1>
<button @click="addSex">添加一个性别属性button>
<h2>学生姓名:{{student.name}}h2>
<h2 v-if="student.sex">学生性别:{{student.sex}}h2>
<h2>学生年龄:真实:{{student.age.rAge}},对外:{{student.age.sAge}}h2>
<h2>爱好:h2>
<ul>
<li v-for="(h,index) in student.hobby">
{{h}}
li>
ul>
<h2>朋友们h2>
<ul>
<li v-for="f in student.friends" :key="index">
{{f.name}}---{{f.age}}
li>
ul>
div>
body>
<script>
const vm = new Vue({
el:'#root',
data:{
name:'尚硅谷',
address:'北京',
student:{
name:'tom',
age:{
rAge:40,
sAge:29,
},
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
},
methods: {
addSex(){
// 两种方法都可以实现
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
}
},
})
script>
html>
如何监测对象中的数据?
通过setter实现监视,且要在new Vue时就传入要监测的数据。
(1)对象中后追加的属性,vue默认不做响应式处理。
(2)如需要给后添加的属性做响应式,请使用如下的API:
Vue.set(target,propertyName/index,value)
vm.$set(target,propertyName/index,value)
如何监测数组中的数据?
通过包裹数组更新元素的方法实现,本质就是做了两件事:
(1)调用原生对应的方法对数组进行更新。
(2)重新解析模板,进而更新页面。
在Vue修改数组中的某个元素一定要用如下方法:
(1)使用这些API:push()、pop()、shift()、unshift()、splice()、sort()、reverse()
(2)Vue.set() 或 vm.$set()
特别注意:Vue.set() 和 vm.$set() 不能给vm的根数局对象添加属性。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>10.总结Vue数据监测title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<h1>学生信息h1>
<button @click="student.age++">年龄+1button><br>
<button @click="addSex">添加性别属性,默认值:男button><br>
<button @click=" student.sex='未知' ">修改性别button><br>
<button @click="addFriends">在列表首页添加一位朋友button><br>
<button @click="updateFristFriendName">修改第一个朋友的名字为:张三button><br>
<button @click="addHobby">添加一个爱好button><br>
<button @click="updateFristHobby">修改第一个爱好为:开车button><br>
<h3>姓名:{{student.name}}h3>
<h3>年龄:{{student.age}}h3>
<h3 v-if="student.sex">性别:{{student.sex}}h3>
<h3>爱好:h3>
<ul>
<li v-for="(h,index) in student.hobby" ::key="index">
{{h}}
li>
ul>
<h3>朋友们:h3>
<ul>
<li v-for="(f,index) in student.friends" ::key="index">
{{f.name}}---{{f.age}}
li>
ul>
div>
body>
<script>
new Vue({
el:'#root',
data:{
student:{
name:'tom',
age:18,
hobby:['抽烟','喝酒','烫头'],
friends:[
{name:'jerry',age:35},
{name:'tony',age:36}
]
}
},
methods: {
addSex(){
// Vue.set(this.student,'sex','男')
this.$set(this.student,'sex','男')
},
addFriends(){
this.student.friends.unshift({name:'jack',age:'70'})
},
updateFristFriendName(){
this.student.friends[0].name = '张三'
},
addHobby(){
this.student.hobby.push('学习')
},
updateFristHobby(){
// this.student.hobby.splice(0,1,'开车')
// Vue.set(this.student.hobby,0,'开车')
this.$set(this.student.hobby,0,'开车')
}
},
})
script>
html>
收集表单数据:
(1)若:<input type="text"/> ,则v-model收集的是value值,用户输入的就是value值。
(2)若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
(3)若:<input type="checkbox"/>
1)没有配置input的value属性,那么收集的就是checked(勾选or未勾选,值是布尔值)
2)配置input的value属性:
[1]v-model的初始值是非数组,那么收集的就是checked(勾选or未勾选,值是布尔值)
[2]v-model的初始值是数组,那么收集的就是value组成的数组。
v-model的三个修饰符:
(1)lazy:失去焦点再收集数据;
(2)number:输入字符串转为有效的数字;
(3)trim:输入首尾空格过滤;
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>收集表单数据title>
<script src="../js/vue.js">script>
head>
<body>
<div id="root">
<form @submit.prevent="demo">
<label for="demo1">账号:label>
<input type="text" id="demo1" v-model.trim="userInfo.account"><br>
<label for="demo2">密码:label>
<input type="password" id="demo2" v-model="userInfo.password"><br>
性别: <br>
男<input type="radio" value="male" v-model="userInfo.sex">
女<input type="radio" value="female" v-model="userInfo.sex"><br>
年龄:<input type="number" v-model.number="userInfo.age">
爱好:<br>
抽烟<input type="checkbox" value="抽烟" v-model="userInfo.hobby">
喝酒<input type="checkbox" value="喝酒" v-model="userInfo.hobby">
烫头<input type="checkbox" value="烫头" v-model="userInfo.hobby"><br>
所属校区:
<select name="" id="" 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>
其他信息:
<textarea v-model.lazy="userInfo.other">textarea><br>
<input type="checkbox" v-model="userInfo.isAgree"> 阅读并接受<a href="http://www.atguigu.com">用户协议a>
<button>提交button>
form>
div>
body>
<script>
new Vue({
el:'#root',
data:{
userInfo:{
account:'',
password:'',
sex:'female',
age:'',
hobby:[],
city:'',
other:'',
isAgree:''
}
},
methods: {
demo(){
console.log(JSON.stringify(this._data));
}
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>过滤器title>
<script src="../js/vue.js">script>
<script src="../js/dayjs.min.js">script>
head>
<body>
<div id="root">
<h2>显示格式化后的时间h2>
<h3>computedh3><br>
<h3>现在时间:{{timeFormatComputed}}h3><hr>
<h3>methodsh3>
<h3>现在时间:{{timeFormatMethods()}}h3><hr>
<h3>filtersh3>
<h3>现在时间:{{time | timeFormatFilters}}h3><hr>
<h3>filters(传参)h3>
<h3>现在时间:{{time | timeFormatFilters('YYYY-MM-DD')}}h3><hr>
<h3>现在时间:{{time | timeFormatFilters}}h3><hr>
<h3>filters(传参)串联h3>
<h3>现在时间:{{time | timeFormatFilters('YYYY-MM-DD') | mySlice}}h3><hr>
div>
<div id="root2">
<h3>{{str | mySlice}}h3><hr>
<h3 :x="str | mySlice">看属性,过滤器不只是适用于插值h3>
div>
body>
<script>
Vue.filter('mySlice',function(value){
return value.slice(0,4);
})
new Vue({
el:'#root',
data:{
time:1621561377603 //时间戳,Date.now()获取到,注意time不能赋值成字符串,不然时间不对。
},
computed:{
timeFormatComputed(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
},
methods: {
timeFormatMethods(){
return dayjs(this.time).format('YYYY-MM-DD HH:mm:ss');
}
},
// 局部过滤器
filters:{
timeFormatFilters(value,str='YYYY-MM-DD HH:mm:ss'){
return dayjs(value).format(str);
},
// mySlice(value){
// return value.slice(0,4);
// }
}
})
new Vue({
el:'#root2',
data:{
str:'Hello! nihao!'
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-text指令title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<div>{{name}}div>
<div v-text="name">这段内容不显示,显示的是namediv>
<div v-text="str">div>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
str:'你好
'
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-html指令title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<div>{{name}}div>
<div v-html="str">div>
<div v-html="str2">div>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷',
str:'你好
',
str2:'兄弟我找到你想要的东西了'
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-cloak指令title>
<script src="../js/vue.js">script>
<style>
[v-cloak]{
display: none;
}
style>
head>
<body>
<div id="root">
<h2 v-cloak>{{name}}h2>
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-once指令title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<h2 v-once="n">初试的n值是:{{n}}h2>
<h2>当前的n值是:{{n}}h2>
<button @click="n++">点我n+1button>
div>
body>
<script>
new Vue({
el:'#root',
data:{
n:1
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>v-pre指令title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<h2 v-pre>Vue其实很简单h2>
<h2 v-pre>当前的n值是:{{n}}h2>
<button v-pre @click="n++">点我n+1button>
div>
body>
<script>
new Vue({
el:'#root',
data:{
n:1
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>自定义指令title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<h2>当前的n值是:<span v-text="n">span>h2>
<h2>放大10倍的n值是:<span v-big="n">span>h2>
<h2>放大10倍的n值是:<span v-big-number="n">span>h2>
<button @click="n++">n+1button>
<hr>
<input type="text" v-bind:value="n">
<input type="text" v-fbind2:value="n">
div>
<div id="root2">
<hr>
<h2>全局的自定义指令h2>
<input type="text" v-fbind:value="x">
<h2>全局的自定义指令——函数写法h2>
<h2>放大10倍的n值是:<span v-big-all="x">span>h2>
div>
body>
<script>
// 全局的自定义指令
Vue.directive('fbind',{
// 指令与元素成功绑定时
bind(element,binding){
console.log('fbind-bind',this);
console.log('bind');
element.value = binding.value;
},
// 指令所在元素被插入页面时。
inserted(element,binding){
console.log('fbind-inserted',this);
console.log('insert');
element.focus();
},
// 指令所在模板被重新解析时
update(element,binding){
console.log('fbind-update',this);
console.log('update');
element.value = binding.value;
}
})
Vue.directive('big-all',function(element,binding){
console.log('big',this); //指令的this都是window
console.log('big');
element.innerText = binding.value * 10;
})
new Vue({
el:'#root',
data:{
n:1
},
directives:{
// big函数何时会被调用?
// 1、指令与元素成功绑定时调用(一开始)。
// 2、指令所在的模板被重新解析时。
big(element,binding){
console.log('big',this); //指令的this都是window
console.log('big');
element.innerText = binding.value * 10;
},
// 不建议使用驼峰命名法bingNumber,建议使用big-number,但是要加引号
'big-number'(element,binding){
console.log('big');
element.innerText = binding.value * 10;
},
fbind2:{
// 指令与元素成功绑定时
bind(element,binding){
console.log('fbind-bind',this);
console.log('bind');
element.value = binding.value;
},
// 指令所在元素被插入页面时。
inserted(element,binding){
console.log('fbind-inserted',this);
console.log('insert');
element.focus();
},
// 指令所在模板被重新解析时
update(element,binding){
console.log('fbind-update',this);
console.log('update');
element.value = binding.value;
}
}
}
})
new Vue({
el:'#root2',
data:{
x:1
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>引出声明周期title>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<h2 :style="{opacity: opacity}">欢迎学习Vueh2>
div>
body>
<script>
/*
// 通过外部的定时器可以实现,但是不推荐
const vm = new Vue({
el:'#root',
data:{
opacity:1
}
})
setInterval(()=>{
vm.opacity -= 0.1;
if(vm.opacity <= 0){
vm.opacity = 1;
}
},100)
*/
new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
},
// Vue完成模板的解析并把初试的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted() {
setInterval(()=>{
this.opacity -= 0.1;
if(this.opacity<=0){
this.opacity = 1;
}
},100)
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
div>
body>
<script>
new Vue({
el:'#root',
data:{
name:'尚硅谷'
}
})
script>
html>
vm的生命周期:
将要创建==>调用beforeCreate函数
创建完毕==>调用Created函数
将要挂载==>调用beforeMount函数
挂载完毕==>调用Mounted函数==>重要钩子
将要更新==>调用beforeUpdate函数
更新完毕==>调用update函数
将要销毁==>调用beforeDestory函数==>重要钩子
销毁完毕==>调用Destory函数
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<h2 :style="{opacity}">欢迎学习Vueh2>
<button @click="opacity = 1">透明度设置为1button>
<button @click="stop">点我停止变换button>
div>
body>
<script>
new Vue({
el:'#root',
data:{
opacity:1
},
methods: {
stop(){
this.$destroy();
}
},
// Vue完成模板的解析并把初试的真实DOM元素放入页面后(挂载完毕)调用mounted
mounted(){
console.log('mounted',this);
this.timer = setInterval(() => {
this.opacity -= 0.1;
if (this.opacity<=0)
{
this.opacity = 1;
}
},16)
},
beforeDestroy() {
console.log('vm即将被销毁了');
// 清除定时器
clearInterval(this.timer)
},
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<student>student>
<hr>
<school>school>
<hr>
<hello>hello>
<hr>
div>
<div id="root2">
<hello>hello>
div>
body>
<script>
// 创建学校组件
const school = Vue.extend({
template:`
学校名称:{{schoolName}}
学校地址:{{address}}
`,
// 一定不要写el配置项,因为最终所有的组件都要被vm管理,由vm决定服务于哪个对象
// el:'#root',
data(){
return {
schoolName:'尚硅谷',
address:'北京昌平',
}
},
methods: {
showSchoolName(){
alert(this.schoolName)
}
},
})
// 创建学生组件
const student = Vue.extend({
template:`
学生姓名:{{studentName}}
学生年龄:{{age}}
`,
// 一定不要写el配置项,因为最终所有的组件都要被vm管理,由vm决定服务于哪个对象
// el:'#root',
data(){
return {
studentName:'张三',
age:18
}
}
})
// 创建hello组件
const hello = Vue.extend({
template:`
你好啊!{{name}}
`,
data(){
return {
name:'Tom'
}
}
})
// 注册组件(全局注册)
Vue.component('hello',hello)
// 注册组件
new Vue({
el:'#root',
// 注册组件(局部注册)
components:{
school,
student
}
})
new Vue({
el:'#root2',
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
<my-school>my-school>
div>
body>
<script>
const school = Vue.extend({
name:'atguigu',
template:`
学校名称:{{name}}
学校地址:{{address}}
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
}
})
new Vue({
el:'#root',
data:{
},
components:{
'my-school':school,
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<script src="../js/vue.min.js">script>
head>
<body>
<div id="root">
div>
body>
<script>
// 定义一个student组件
const student = Vue.extend({
name:'student',
template:`
学生姓名:{{name}}
学生年龄:{{age}}
`,
data(){
return {
name:'张三',
age:18
}
}
})
// 定义school组件
const school = Vue.extend({
name:'school',
template:`
学校名称:{{name}}
学校地址:{{address}}
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
components:{
student
}
})
// 定义一个hello组件
const hello = Vue.extend({
template:`
{{msg}}
`,
data(){
return {
msg:'Hello'
}
}
})
// 定义app组件
const app = Vue.extend({
template:`
`,
components:{
school,
hello
}
})
// 创建Vue
new Vue({
template:`
`,
el:'#root',
// 注册组件
components:{
app
}
})
script>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>VueComponenttitle>
<script src="../vue.js">script>
head>
<body>
<div id="root">
<school>school>
<hello/>
div>
body>
<script>
Vue.config.productionTip = false
// 定义school组件
const school = Vue.extend({
name:'school',
template:`
学校名称:{{name}}
学校地址:{{address}}
点我显示this是谁
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
methods:{
showName(){
console.log('showName',this)
}
}
})
// 定义hello组件
const hello = Vue.extend({
template:`{{msg}}
`,
data(){
return{
msg:'你好啊!'
}
}
})
console.log('@',school);
console.log('#',hello);
// 创建vm
new Vue({
el:'#root',
components:{school,hello}
})
script>
html>
School.vue文件
<template>
<div class="demo">
<h2>学校名称:{{schoolName}}h2>
<button @click="showName">点我提示学校名button>
div>
template>
<script>
//组件交互相关的代码(数据、方法等等)
export default {
name:'School',
data(){
return {
schoolName:'尚硅谷'
}
},
methods:{
showName(){
alert(this.schoolName)
}
}
}
script>
<style>
/* 组件的样式 */
.demo{
background-color: orange
}
style>
App.vue文件
<template>
<div>
<school>school>
div>
template>
<script>
// 引入组件
import School from './School.vue'
export default {
name:'App',
components:{
School
}
}
script>
<style>
style>
main.js文件
import App from './App.vue'
new Vue({
el:'#root',
template:`<App>App>`,
component:{App},
})
index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>测试一下单文件组件语法title>
head>
<body>
<div id='root'>div>
<script src="../vue.js">script>
<script src="./main.js">script>
body>
html>
https://cli.vuejs.org/zh/
npm config set registry https://registry.npm.taobao.org
npm install -g @vue/cli
vue create demo
npm run serve
## 查看@vue/cli版本,确保@vue/cli版本在4.5.0以上
vue --version
## 安装或者升级你的@vue/cli
npm install -g @vue/cli
## 创建
vue create vue_test
## 启动
cd vue_test
npm run serve
官方文档:https://v3.cn.vuejs.org/guide/installation.html#vite
vite官网:https://vitejs.cn
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
<template>
<h1>我是一个人h1>
<h2>name:{{ name }}h2>
<h2>age:{{ age }}h2>
<button @click="sayHello()">点我说话button>
template>
<script>
export default {
name: 'App',
// 测试setup,暂时不考虑响应问题
setup() {
// 数据
let name = '张三'
let age = 18
// 方法
function sayHello() {
alert(`我叫${name},我今年${age}岁了!`)
}
// 返回一个对象
return {
name,
age,
sayHello
}
}
}
script>
<style>
style>
加上返回一个渲染函数以后,页面中的渲染全部失效,变为渲染函数中的渲染结果。
<template>
<h1>我是一个人h1>
<h2>name:{{ name }}h2>
<h2>age:{{ age }}h2>
<button @click="sayHello()">点我说话button>
template>
<script>
import { h } from 'vue'
export default {
name: 'App',
// 测试setup,暂时不考虑响应问题
setup() {
// 数据
let name = '张三'
let age = 18
// 方法
function sayHello() {
alert(`我叫${name},我今年${age}岁了!`)
}
// 返回一个对象
// return {
// name,
// age,
// sayHello
// }
// 返回一个函数(渲染函数)
return () => h("h1", '你好,尚硅谷')
}
}
script>
<style>
style>
const xxx = ref(initValue)
xxx.value
{{xxx}}
Object.defineProperty()
的get
与set
完成的。reactive
函数。<template>
<h1>我是一个人h1>
<h2>name:{{ name }}h2>
<h2>age:{{ age }}h2>
<button @click="changeInfo()">点我修改个人信息button>
template>
<script>
import { ref } from 'vue'
export default {
name: 'App',
// 测试setup,暂时不考虑响应问题
setup() {
// 数据
let name = ref('张三')
let age = ref(18)
// 方法
function changeInfo() {
name.value = '李四'
age.value = 20
}
// 返回一个对象
return {
name,
age,
changeInfo
}
}
}
script>
<style>
style>
运行结果:
点击按钮后,显示的“张三 18”变成了“李四 20” 。
<template>
<h1>我是一个人h1>
<h2>name:{{ name }}h2>
<h2>age:{{ age }}h2>
<h3>工作种类:{{ job.type }}h3>
<h3>工作薪资:{{ job.salary }}h3>
<button @click="changeInfo()">点我修改个人信息button>
template>
<script>
import { ref } from 'vue'
export default {
name: 'App',
// 测试setup,暂时不考虑响应问题
setup() {
// 数据
let name = ref('张三')
let age = ref(18)
let job = ref({
type:'前端工程师',
salary:'30K'
})
// 方法
function changeInfo() {
name.value = '李四'
age.value = 20
job.value.type = 'UI设计师'
job.value.salary = '60K'
}
// 返回一个对象
return {
name,
age,
job,
changeInfo
}
}
}
script>
<style>
style>
ref
函数)const 代理对象= reactive(源对象)
接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)ref结合reactive使用的写法
<template>
<h1>我是一个人h1>
<h2>name:{{ name }}h2>
<h2>age:{{ age }}h2>
<h3>工作种类:{{ job.type }}h3>
<h3>工作薪资:{{ job.salary }}h3>
<button @click="changeInfo()">点我修改个人信息button>
template>
<script>
import { reactive, ref } from 'vue'
export default {
name: 'App',
setup() {
// 数据
let name = ref('张三')
let age = ref(18)
let job = reactive({
type:'前端工程师',
salary:'30K'
})
// 方法
function changeInfo() {
name.value = '李四'
age.value = 20
job.type = 'UI设计师'
job.salary = '60K'
}
// 返回一个对象
return {
name,
age,
job,
changeInfo
}
}
}
script>
<style>
style>
<template>
<h1>我是一个人h1>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h3>工作种类:{{ person.job.type }}h3>
<h3>工作薪资:{{ person.job.salary }}h3>
<h3>爱好:{{ person.hobby }}h3>
<button @click="changeInfo()">点我修改个人信息button>
template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
// 数据
let person = reactive({
name: '张三',
age: 18,
job: {
type: '前端工程师',
salary: '30K'
},
hobby: ['抽烟', '喝酒', '烫头']
})
// 方法
function changeInfo() {
person.name = '李四'
person.age=20
person.job.type='UI设计师'
person.job.salary = '60K'
person.hobby[0] = '学习'
}
// 返回一个对象
return {
person,
changeInfo
}
}
}
script>
<style>
style>
实现原理:
对象类型:通过Object.defineProperty()
对属性的读取、修改进行拦截(数据劫持)。
数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。
Object.defineProperty(data, 'count', {
get () {},
set () {}
})
存在问题:
实现原理:
Proxy:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy
Reflect:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
<template>
<h1>我是一个人h1>
<h2 v-show="person.name">姓名:{{ person.name }}h2>
<h2 v-show="person.sex" >性别:{{ person.sex }}h2>
<button @click="addSex()">添加一个sex属性button><br>
<button @click="deleteName()">删除一个name属性button>
template>
<script>
import { reactive } from 'vue'
export default {
name: 'App',
setup() {
// 数据
let person = reactive({
name: '张三',
sex:'',
})
// 方法
function addSex(){
person.sex = '男'
}
function deleteName(){
delete person.name
}
// 返回一个对象
return {
person,
addSex,
deleteName
}
}
}
script>
<style>
style>
reactive
转为代理对象。Object.defineProperty()
的get
与set
来实现响应式(数据劫持)。.value
,读取数据时模板中直接读取不需要.value
。.value
。setup执行的时机
setup的参数
this.$attrs
。this.$slots
。this.$emit
。<template>
template>
<script>
export default {
name: 'App',
beforeCreate() {
console.log('---beforeCreate---')
},
setup() {
console.log('---setup---')
}
}
script>
<style>
style>
App.vue
<template>
<Demo @hello="showhelloMsg" msg="你好啊" school="尚硅谷">
<template v-slot:qwe>
<span>尚硅谷span>
template>
Demo>
template>
<script>
import Demo from './components/Demo.vue'
export default {
name: 'App',
components: {
Demo
},
setup() {
function showhelloMsg(value) {
alert(`你好,你触发了hello事件,我收到的参数是:${value}`)
}
return {
showhelloMsg
}
}
}
script>
<style>
style>
Demo.vue
<template>
<h1>Demoh1>
<button @click="test()">测试触发一下Demo组件的Hello事件button>
template>
<script>
export default {
name: 'Demo',
props: ['msg', 'school'],
emits: ['hello'],
setup(props, context) {
console.log('---setup---', props)
console.log('---setup---', context)
console.log('---setup---', context.attrs) //相当于Vue2中的$attrs
console.log('---setup---', context.emit) //触发自定义事件
console.log('---setup---', context.slots) //插槽
function test() {
context.emit('hello', 666)
}
// 返回一个对象
return {
test
}
}
}
script>
<style>
style>
<template>
<h1>一个人h1>
姓:<input type="text" v-model="person.firstName"> <br>
名:<input type="text" v-model="person.lastName"> <br>
<span>全名:{{ person.fullName }}span>
template>
<script>
import { reactive, computed } from 'vue';
export default {
name: 'App',
setup() {
let person = reactive({
firstName: '张',
lastName: '三',
})
// 计算属性
person.fullName = computed(() => {
return person.firstName + person.lastName
})
return {
person
}
}
}
script>
<style>
style>
两个小“坑”:
<template>
<h1>当前求和为:{{ sum }}h1>
<button @click="sum++">点我+1button>
template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let sum = ref(0)
// 情况一:监视ref所定义的一个响应式数据
watch(sum,(newValue,oldValue)=>{
console.log(`sum的值变了${oldValue}=>${newValue}`)
})
return {
sum
}
}
}
script>
<style>
style>
(1)分开监视
<template>
<h1>当前求和为:{{ sum }}h1>
<button @click="sum++">点我+1button>
<hr>
<h2>当前的信息为:{{ msg }}h2>
<button @click="msg += '!'">点我修改信息button>
template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let sum = ref(0)
let msg = ref('你好')
// 情况二:监视ref所定义的多个响应式数据
// (1)分开监视
watch(sum,(newValue,oldValue)=>{
console.log(`sum的值变了${oldValue}=>${newValue}`)
})
watch(msg,(newValue,oldValue)=>{
console.log(`sum的值变了${oldValue}=>${newValue}`)
})
return {
sum,
msg
}
}
}
script>
<style>
style>
(2)合并起来监视
<template>
<h1>当前求和为:{{ sum }}h1>
<button @click="sum++">点我+1button>
<hr>
<h2>当前的信息为:{{ msg }}h2>
<button @click="msg += '!'">点我修改信息button>
template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let sum = ref(0)
let msg = ref('你好')
// 情况二:监视ref所定义的多个响应式数据
// (2)合起来监视
watch([sum,msg],(newValue,oldValue)=>{
console.log(`sum或msg的值变了${oldValue}=>${newValue}`)
})
return {
sum,
msg
}
}
}
script>
<style>
style>
<template>
<h1>当前求和为:{{ sum }}h1>
<button @click="sum++">点我+1button>
template>
<script>
import { ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let sum = ref(0)
// 其他参数
watch(sum, (newValue, oldValue) => {
console.log(`sum的值变了${oldValue}=>${newValue}`)
}, { immediate: true })
return {
sum
}
}
}
script>
<style>
style>
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<button @click="person.name += '!'">点我修改姓名button> <br>
<button @click="person.age++">点我修改年龄button>
<button @click="person.job.job1.salary++">点我涨工资button>
template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let sum = ref(0)
let msg = ref('你好')
let person = reactive({
job:{
job1:{
salary:20
}
}
})
/*
情况三:监视reactive所定义的一个响应式的全部数据
注意:
1、无法正确的获得oldValue
2、强制开启了深度检测(deep配置无效)
*/
watch(person, (newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}, { deep: false })
return {
person
}
}
}
script>
<style>
style>
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<button @click="person.name += '!'">点我修改姓名button> <br>
<button @click="person.age++">点我修改年龄button> <br>
<button @click="person.job.job1.salary++">点我涨工资button>
template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: '18',
job: {
job1: {
salary: 20
}
}
})
/*
情况四:监视reactive所定义的一个响应式数据中的某个属性
*/
watch(
() => person.age,
(newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}
)
return {
person
}
}
}
script>
<style>
style>
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<button @click="person.name += '!'">点我修改姓名button> <br>
<button @click="person.age++">点我修改年龄button> <br>
<button @click="person.job.job1.salary++">点我涨工资button>
template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: '18',
job: {
job1: {
salary: 20
}
}
})
/*
情况五:监视reactive所定义的一个响应式数据中的某些数据
*/
watch(
[() => person.name,() => person.age],
(newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
}
)
return {
person
}
}
}
script>
<style>
style>
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<button @click="person.name += '!'">点我修改姓名button> <br>
<button @click="person.age++">点我修改年龄button> <br>
<button @click="person.job.job1.salary++">点我涨工资button>
template>
<script>
import { reactive, ref, watch } from 'vue'
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: '18',
job: {
job1: {
salary: 20
}
}
})
// 特殊情况
watch(
()=>person.job.job1.salary,
(newValue, oldValue) => {
console.log('person变化了', newValue, oldValue)
},
{deep:true} // 由于监视的是reactive定义的对象中的某个属性,所以deep配置有效
)
return {
person
}
}
}
script>
<style>
style>
watch的套路是:既要指明监视的属性,也要指明监视的回调。
watchEffect的套路是:不用指明监视哪个属性,监视的回调中用到哪个属性,那就监视哪个属性。
watchEffect有点像computed:
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<button @click="person.name += '!'">点我修改姓名button> <br>
<button @click="person.age++">点我修改年龄button> <br>
<button @click="person.job.job1.salary++">点我涨工资button>
template>
<script>
import { reactive, ref, watch, watchEffect } from 'vue'
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: '18',
job: {
job1: {
salary: 20
}
}
})
// watchEffect()函数里面用到的数据发生改变时监视谁
watchEffect(()=>{
const x1 = person.job.job1.salary
console.log('watchEffect所指定的回调执行了')
})
return {
person
}
}
}
script>
<style>
style>
beforeDestroy
改名为 beforeUnmount
destroyed
改名为 unmounted
beforeCreate
===>setup()
created
=======>setup()
beforeMount
===>onBeforeMount
mounted
=======>onMounted
beforeUpdate
===>onBeforeUpdate
updated
=======>onUpdated
beforeUnmount
==>onBeforeUnmount
unmounted
=====>onUnmounted
什么是hook?—— 本质是一个函数,把setup函数中使用的Composition API进行了封装。
类似于vue2.x中的mixin。
自定义hook的优势: 复用代码, 让setup中的逻辑更清楚易懂。
封装目录:src\hooks\xxx.js
代码举例
把setup函数中使用的Composition API封装到别的文件中,然后通过导入引用的方式,提高代码复用性。
(1)App.vue
<template>
<button @click="isShowDemo = !isShowDemo">切换隐藏或者显示Demobutton>
<Demo v-if="isShowDemo">Demo>
template>
<script>
import Demo from './components/Demo.vue'
import {ref} from 'vue'
export default {
name: 'App',
components:{
Demo
},
setup(){
let isShowDemo = ref(true)
return {
isShowDemo
}
}
}
script>
<style>
style>
(2)Demo.vue
<template>
<h2>当前点击鼠标时的坐标为:x={{ point.x }},y={{ point.y }}h2>
template>
<script>
import usePoint from '../hooks/usePoint'
export default {
name: 'Demo',
setup() {
let point = usePoint()
return {
point
}
}
}
script>
<style>
style>
(3)usePoint.js
import { reactive, onMounted, onBeforeUnmount } from "vue"
export default function savePoint() {
// 实现鼠标打点的相关数据
let point = reactive({
x: 0,
y: 0
})
// 实现鼠标打点的相关方法
function savePoint(event) {
point.x = event.pageX
point.y = event.pageY
console.log(event.pageX, event.pageY)
}
// 实现鼠标打点的相关生命周期钩子
onMounted(() => {
window.addEventListener('click', savePoint)
})
onBeforeUnmount(() => {
window.removeEventListener('click', savePoint)
})
return point
}
const name = toRef(person,'name')
toRefs
与toRef
功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
代码示例
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ salary }}Kh2>
<button @click="name += '!'">修改姓名button>
<button @click="age++">修改年龄button>
<button @click="salary += 10">修改薪资button>
template>
<script>
import { reactive, toRef } from 'vue';
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
return {
name:toRef(person,'name'),
age:toRef(person,'age'),
salary:toRef(person.job.job1,'salary')
}
}
}
script>
<style>
style>
示例代码
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ job.job1.salary }}Kh2>
<button @click="name += '!'">修改姓名button>
<button @click="age++">修改年龄button>
<button @click="job.job1.salary += 10">修改薪资button>
template>
<script>
import { reactive, toRefs } from 'vue';
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
return {
// ...为扩展运算符
...toRefs(person)
}
}
}
script>
<style>
style>
shallowReactive:只处理对象最外层属性的响应式(浅响应式)。
shallowRef:只处理基本数据类型的响应式, 不进行对象的响应式处理。
什么时候使用?
代码示例
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ job.job1.salary }}Kh2>
<button @click="name += '!'">修改姓名button>
<button @click="age++">修改年龄button>
<button @click="job.job1.salary += 10">修改薪资button>
template>
<script>
import { reactive, toRefs, shallowReactive } from 'vue';
export default {
name: 'App',
setup() {
// shallowReactive只考虑第一层数据的响应式
let person = shallowReactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
return {
// ...为扩展运算符
...toRefs(person)
}
}
}
script>
<style>
style>
运行结果:
点击修改姓名和修改年龄会增加,但是点击深层次的修改薪资就不会增加。
此处还有一个注意点和疑问点:点完修改薪资不会变动,但是点完修改薪资以后,再次点击修改姓名或者修改年龄,则薪资会增加。
代码示例
<template>
<h2>当前x下的y的值为{{ x.y }}h2>
<button @click="x.y++">x+1button>
template>
<script>
import { reactive, toRefs, shallowRef } from 'vue';
export default {
name: 'App',
setup() {
let x = shallowRef({
y:0
})
return {
x
}
}
}
script>
<style>
style>
运行结果:
点击x+1没有变化
代码示例
<template>
<h2>当前求和为{{ sum }}h2>
<button @click="sum++">sum+1button>
<hr>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ job.job1.salary }}h2>
<button @click="name+='!'">修改姓名button> <br>
<button @click="age++">修改年龄button><br>
<button @click="job.job1.salary++">修改薪资button><br>
template>
<script>
import { reactive, toRefs, ref, readonly } from 'vue';
export default {
name: 'App',
setup() {
let sum = ref(0)
let person = reactive({
name:'张三',
age:18,
job:{
job1:{
salary:20
}
}
})
// readonly: 让一个响应式数据变为只读的(深只读)
person= readonly(person)
return {
sum,
...toRefs(person)
}
}
}
script>
<style>
style>
运行截图:
点击修改姓名、修改年龄和修改薪资都不会发生变化
代码示例
<template>
<h2>当前求和为{{ sum }}h2>
<button @click="sum++">sum+1button>
<hr>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ job.job1.salary }}h2>
<button @click="name += '!'">修改姓名button> <br>
<button @click="age++">修改年龄button><br>
<button @click="job.job1.salary++">修改薪资button><br>
template>
<script>
import { reactive, toRefs, ref, shallowReadonly } from 'vue';
export default {
name: 'App',
setup() {
let sum = ref(0)
let person = reactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
// shallowReadonly:让一个响应式数据变为只读的(浅只读)。
person = shallowReadonly(person)
return {
sum,
...toRefs(person)
}
}
}
script>
<style>
style>
reactive
生成的响应式对象转为普通对象。代码示例
<template>
<h2>姓名:{{ name }}h2>
<h2>年龄:{{ age }}h2>
<h2>薪资:{{ job.job1.salary }}h2>
<button @click="name += '!'">修改姓名button> <br>
<button @click="age++">修改年龄button><br>
<button @click="job.job1.salary++">修改薪资button><br>
<button @click="showRawPerson">输出最原始的personbutton>
template>
<script>
import { reactive, toRefs, ref, shallowReadonly, toRaw } from 'vue';
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
// 输出最原始的person
function showRawPerson(){
console.log('代理对象的person',person)
const p = toRaw(person)
console.log('原始的对象的person',p)
}
return {
...toRefs(person),
showRawPerson
}
}
}
script>
<style>
style>
代码示例
<template>
<h2>姓名:{{ person.name }}h2>
<h2>年龄:{{ person.age }}h2>
<h2>薪资:{{ person.job.job1.salary }}h2>
<h2>资产:{{ person.car }}h2>
<h2>h2>
<button @click="person.name += '!'">修改姓名button> <br>
<button @click="person.age++">修改年龄button><br>
<button @click="person.job.job1.salary++">修改薪资button><br>
<button @click="addCar">给人添加一台车button><br>
<button v-if="person.car" @click="person.car.name += '!'">修改车名button><br>
<button v-if="person.car" @click="changePrice()">修改车价格button><br>
template>
<script>
import { reactive, markRaw } from 'vue';
export default {
name: 'App',
setup() {
let person = reactive({
name: '张三',
age: 18,
job: {
job1: {
salary: 20
}
}
})
// 响应式对象身上追加一个car属性
function addCar() {
let car = {
name: '奔驰',
price: 40
}
// 标记对象不会成为响应式对象,对其更改以后,页面不会发生变法,但是他的值是变化的。
person.car = markRaw(car)
}
// 更改车的价格
function changePrice() {
person.car.price++
console.log('车的价格变为', person.car.price)
}
return {
person,
addCar,
changePrice
}
}
}
script>
<style>
style>
作用:创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制。
实现防抖效果
代码示例
<template>
<input type="text" v-model="keyWord">
<h3>{{ keyWord }}h3>
template>
<script>
import { customRef, ref } from 'vue';
export default {
name: 'App',
setup() {
// let keyWord = ref('hello') //使用vue提供的内置的ref
let keyWord = myRef('hello') //使用程序员自定义的ref
// 自定义一个ref
function myRef(value) {
let timer
return customRef((track, trigger) => {
return {
get() {
console.log(`从容器中读取了数据${value}`)
// 通知vue追踪value的变化
track()
return value
},
set(newValue) {
console.log(`myRef容器中的数据修改为了${newValue}`)
// 定时器防抖
clearTimeout(timer)
timer = setTimeout(() => {
value = newValue
// 通知vue重新解析模板
trigger()
}, 500)
}
}
})
}
return {
keyWord
}
}
}
script>
<style>
style>
作用:实现祖组件与后代组件间通信
套路:父组件有一个 provide
选项来提供数据,后代组件有一个 inject
选项来开始使用这些数据
代码示例
(1)App.vue
<template>
<div class="app">
<h3>我是App组件(祖组件)h3>
<h4>{{ name }}---{{ price }}h4>
<ChildCom>ChildCom>
div>
template>
<script>
import { provide, reactive, toRefs } from 'vue';
import ChildCom from './components/ChildCom.vue';
export default {
name: 'App',
components: {
ChildCom
},
setup() {
let car = reactive({
name: '奔驰',
price: '40W'
})
// provide() 给自己的后代组件传递数据
provide('car',car)
return {
...toRefs(car)
}
}
}
script>
<style>
.app {
background-color: #ccc;
padding: 10%;
}
style>
(2)ChildCom.vue
<template>
<div class="child">
<h3>我是Child组件(子组件)h3>
<h4>{{ name }}--{{ price }}h4>
<SonCom>SonCom>
div>
template>
<script>
import { inject, toRefs } from 'vue';
import SonCom from './SonCom.vue';
export default {
name: 'child',
components: {
SonCom
},
setup(){
let car = inject('car')
console.log('child--',car)
return {
...toRefs(car)
}
}
}
script>
<style>
.child {
background-color: skyblue;
padding: 10%;
}
style>
(3)SonCom.vue
<template>
<div class="son">
<h3>我是Son组件(孙组件)h3>
<h4>{{ car.name }}--{{ car.price }}h4>
div>
template>
<script>
import { inject } from 'vue';
export default {
name: 'son',
setup(){
let car = inject('car')
console.log('son--',car)
return {
car
}
}
}
script>
<style>
.son {
background-color: orange;
padding: 10%;
}
style>
reactive
创建的响应式代理readonly
创建的只读代理reactive
或者 readonly
方法创建的代理代码示例
<template>
<div class="app">
<h3>我是App组件h3>
div>
template>
<script>
import { isProxy, isReactive, isReadonly, isRef, reactive, readonly, ref, toRefs } from 'vue';
export default {
name: 'App',
setup() {
let car = reactive({
name: '奔驰',
price: '40W'
})
let car2 = readonly(car)
let sum = ref(0)
console.log('判断sum是不是ref类型',isRef(sum))
console.log('判断car是不是reactive类型',isReactive(car))
console.log('判断car2是不是readonly类型',isReadonly(car2))
console.log('判断car是不是代理对象类型',isProxy(car),car)
console.log('判断car2是不是代理对象类型',isProxy(car2),car2)
return {
...toRefs(car),
car2,
sum
}
}
}
script>
<style>
style>
使用传统OptionsAPI中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
什么是Teleport?—— Teleport
是一种能够将我们的组件html结构移动到指定位置的技术。
代码示例
模拟弹窗组件,使弹窗内容位居页面中心,而不是在SonCom.vue组件中显示。
(1)App.vue
<template>
<div class="app">
<h3>我是App组件h3>
<ChildCom>ChildCom>
div>
template>
<script>
import ChildCom from './components/ChildCom.vue';
export default {
name: 'App',
components: {
ChildCom
},
}
script>
<style>
.app {
background-color: #ccc;
padding: 10%;
}
style>
(2)ChildCom.vue
<template>
<div class="child">
<h3>我是Child组件h3>
<SonCom>SonCom>
div>
template>
<script>
import SonCom from './SonCom.vue';
export default {
name: 'child',
components: {
SonCom
},
}
script>
<style>
.child {
background-color: skyblue;
padding: 10%;
}
style>
(3)SonCom.vue
<template>
<div class="son">
<h3>我是Son组件h3>
div>
<Dialog>Dialog>
template>
<script>
import Dialog from './Dialog.vue';
export default {
name: 'son',
components:{
Dialog
}
}
script>
<style>
.son {
background-color: orange;
padding: 10%;
}
style>
(4)Dialog.vue
<template>
<div>
<button @click="isShow = true">点我弹个窗button>
<teleport to="body">
<div v-if="isShow" class="mask">
<div class="dialog">
<h3>我是一个弹窗h3>
<h4>写一些内容h4>
<button @click="isShow = false">关闭弹窗button>
div>
div>
teleport>
div>
template>
<script>
import { ref } from 'vue';
export default {
name: 'Dialog',
setup() {
let isShow = ref(false)
return {
isShow
}
}
}
script>
<style>
/* 遮罩层 */
.mask{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: rgb(0,0,0,0.5);
}
.dialog {
position:absolute;
top: 50%;
left: 50%;
text-align: center;
transform: translate(-50%,-50%);
width: 300px;
height: 300px;
background-color: green;
}
style>
等待异步组件时渲染一些额外内容,让应用有更好的用户体验。
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
Suspense
包裹组件,并配置好default
与 fallback
<template>
<div class="app">
<h3>我是App组件h3>
<Suspense>
<template v-slot:default>
<Child/>
template>
<template v-slot:fallback>
<h3>加载中.....h3>
template>
Suspense>
div>
template>
使用步骤:
Vue 2.x 有许多全局 API 和配置。
例如:注册全局组件、注册全局指令等。
//注册全局组件
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: 'Clicked {{ count }} times. '
})
//注册全局指令
Vue.directive('focus', {
inserted: el => el.focus()
}
Vue3.0中对这些API做出了调整:
将全局的API,即:Vue.xxx
调整到应用实例(app
)上
2.x 全局 API(Vue ) |
3.x 实例 API (app ) |
---|---|
Vue.config.xxxx | app.config.xxxx |
Vue.config.productionTip | 移除 |
Vue.component | app.component |
Vue.directive | app.directive |
Vue.mixin | app.mixin |
Vue.use | app.use |
Vue.prototype | app.config.globalProperties |
data选项应始终被声明为一个函数。
过度类名的更改:
Vue2.x写法
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
Vue3.x写法
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
移除keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
移除v-on.native
修饰符
父组件中绑定事件
子组件中声明自定义事件
移除过滤器(filter)
过滤器虽然这看起来很方便,但它需要一个自定义语法,打破大括号内表达式是 “只是 JavaScript” 的假设,这不仅有学习成本,而且有实现成本!建议用方法调用或计算属性去替换过滤器。
…