VUE深度解析

Posted springboot葵花宝典

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VUE深度解析相关的知识,希望对你有一定的参考价值。

VUE深度解析

ES6语法-var-const-let用法详解

javascript作用域

javascript只有函数作用域,没有块级作用域。即在​​dunction​​里面定义的变量是有作用域的,if、for等代码块定义的变量是没有作用域的。

<!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>ES6语法-var-const-let用法详解</title>
</head>

<body>
<div id="app">
<button>测试1</button>
<button>测试2</button>
<button>测试3</button>
</div>
<script>
//作用域代码
if(true)
//externalVal没有作用域
var externalVal = "externalVal";

function domainTest()
var funVal ="funVal";
//这里可以访问到externalVal和funVal
console.log(externalVal + "----" + funVal);

domainTest()
if(true)
console.log(externalVal); //可以访问到externalVal
//console.log(funVal); 这一行访问不到变量,报错


//使用var定义变量的局限性
var btns = document.getElementsByTagName(button)
for(let i = 0;i < btns.length;i++)
btns[i].onclick = function()
alert("点击了第" + (i+1) + "个按钮");


</script>
</body>
</html>

VUE深度解析_vue

var局限性

在上面代码中添加三个button,然后定义监听

VUE深度解析_html_02

然后测试结果如下:

VUE深度解析_作用域_03

为什么会一直出现的是3呢?这是因为作用域,for代码块没有作用域,当循环for结束的时候,监听的i是几?肯定是3,那么当我们点击按钮的时候i就是3。所以打印出来的就是"点击了第三个按钮"

let用法

var作用域在js中存在的缺陷,在ES6版主中,使用新的定义变量let就可以解决。

//使用var定义变量的局限性
var btns = document.getElementsByTagName(button)
for(let i = 0;i < btns.length;i++)
btns[i].onclick = function()
alert("点击了第" + (i+1) + "个按钮");

结果如下:

VUE深度解析_html_04

点击第1个按钮,打印“点击了第3个按钮”的情况就不会再出现。因为let定义的变量自带块级作用域

const用法

当我们希望定义的变量不要被二次赋值的时候(也就是常量),使用const关键字来定义。

const c = 80;
c = 100;//报错
const c; //报错,常量定义的时候必须赋值

ES6语法-对象的增强写法

ES5对象定义语法

function Player(name,age)//定义对象
this.name = name;
this.age = age;

//定义对象的成员函数
Player.prototype.toPrint = function()
alert(this.name + "---" + this.age)

var player1 = new Player("james",35);
var player2 = new Player("kobe",39);
player1.toPrint() //james---35 调用函数方法
player2.toPrint() //kobe---39

结果如下:

VUE深度解析_数据_05

ES5中对象最令人觉得繁琐的就是构造函数、prototyp、依靠原型链实现继承。因为它使用的不是面向对象的语法,所以使用过程比较混乱。下面我们结束如何使用简介的ES6语法定义对象和继承的增强语法。

ES6定义对象语法

ES6语法中,js引入了传统的面向对象编程语法(和java相似)。新的写法比较符合面向对象思想,也比较容易理解。

//class定义对象
class Player
//constructor 定义构造函数
constructor(name,age)
console.log(name + fdasfada + age)
this.name = name;
this.age = age;

//定义方法
toPrint()
console.log(this.name + "---" + this.age)


//使用对象
let player1 = new Player("james",35);
//使用对象方法
player1.toPrint() //james---35
  • 引入class关键字,用于定义对象
  • 构造函数方法名称固定,就叫做constructor。
  • 在对象定义类中,this关键字代表当前实例对象
class BestPlayer extends Player
constructor()
super()
this.name = "jordan"
this.age = 49


let bestPlayer = new BestPlayer();
bestPlayer.toPrint() //jordan---49
  • 通过class关键字实现了类的继承
  • 通过super()关键字调用父类构造函数,如果不传参数,默认是undefined
  • super()方法必须显示调用,否则子类找不到this指针。

ES6定义对象简写

let name = "curry"
let age = 33
let player3 =
name :name,
age : age,
toPrint:function()
console.log(player3) //name: "curry", age: 33


player3.toPrint() //name: "curry", age: 33, toPrint: ƒ

ES6语法-箭头函数与this指针

箭头函数简写形式

VUE深度解析_数据_06

可以发现,箭头函数方法写的很简单,箭头左侧定义参数,右侧定义函数体。

对象中this指针

//class 定义对象    
class Player
//constructor 定义构造函数
constructor(nickname,age)
this.nickname = nickname;
this.age = age;

//定义成员方法
toPrint()
console.log(this.nickname + "---" + this.age)

在对象中,this指针指向的就是对象本身。可以this可以引用对象的属性和方法。

VUE组件化

graph LR
调用Vue.extend定义组件 --> 调用Vue.component组测组件 --> 在vue实例试图范围内使用组件
<!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>
<div id="app" style="background-color: aqua;">
<first-component></first-component>
</div>
<div id="app2" style="background-color: aquamarine;">
<second-component></second-component>
</div>
<div id="app3" style="background-color: blue;">
<third-component></third-component>
</div>

<!--父子组件的嵌套-->
<template id="child">
<p style="font-size: larger;">子组件</p>
</template>
<template id="parent">
<div>
<h2>父组件 template</h2>
<child></child>
<child></child>
</div>
</template>
<div id="app4" style="background-color: brown;">
<parent></parent>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>

const firstComponent= Vue.extend(
template:`
<div>
<span>template用于定义组件试图</span>
<h3>测试组件</h3>
<h2>测试组件内容</h2>
</div>
`
);
//组测组件
Vue.component("firstComponent",firstComponent);

var app = new Vue(
el: #app
);
</script>
<script>
var app2 = new Vue(
el: #app4,
components:
parent:
template: #parent,
components:
child: template: #child,



);
</script>
<script>
//组测组件
Vue.component("secondComponent",
template:`
<div>
<span>template用于定义组件二合一试图</span>
<h3>测试组件二合一</h3>
<h2>测试组件二合一内容</h2>
</div>
`
);

var app = new Vue(
el: #app2,
data: function()
return count: 0
,
methods:
incr()
this.count ++

,
);
</script>

<script>
var app = new Vue(
el: #app3,
components:
thirdComponent:
template:`
<div>
<span>template用于定义私有组件试图</span>
<h3>测试私有组件</h3>
<h2>测试私有组件内容2</h2>
</div>
`


);
</script>
</body>
</html>

VUE深度解析_数据_07

  • 全局组件要先定义vue.extend(),在注册vue.component(),任何再使用
  • ​template​​用于定义组件视图
  • 如果用new VUE()定义多个vue实例,全局组件可以跨多个实例使用
  • 通常组件定义的名称为首字母大写,驼峰标志。如:firstComponent
  • 在dom中使用组件,通常遵循使用“-”分隔单词,小写规范。如:first-component

最终结果如下:

VUE深度解析_html_08

全局组件简写

使用Vue.component()方法 + template组件视图层模板一步完成全局组件的定义与注册

//组测组件
Vue.component("secondComponent",
template:`
<div>
<span>template用于定义组件二合一试图</span>
<h3>测试组件二合一</h3>
<h2>测试组件二合一内容</h2>
</div>
`
);

局部私有组件

局部私有组件和全局组件的区别在于,私有组件只能在定义它的实例或者父组件里面使用。如下:定义的组件thirdComponent只能在​​<div id="app3">​​里面使用,其他vue实例无法使用该组件。

<script>
var app = new Vue(
el: #app3,
components:
thirdComponent:
template:`
<div>
<span>template用于定义私有组件试图</span>
<h3>测试私有组件</h3>
<h2>测试私有组件内容2</h2>
</div>
`


);
</script>

父子组件嵌套

<!--父子组件的嵌套-->
<template id="child">
<p style="font-size: larger;">子组件</p>
</template>
<template id="parent">
<div>
<h2>父组件 template</h2>
<child></child>
<child></child>
</div>
</template>
<div id="app4" style="background-color: brown;">
<parent></parent>
</div>

一个父组件Parent里面包含两个子组件Child,并将父组件放在app2实例页面渲染范围内。下文中是使用私有局部组件的方式定义的。也就是Parent组件是app2实例的私有局部组件,Child是Parent组件的私有局部组件。

<script>
var app4 = new Vue(
el: #app4,
components:
parent:
template: #parent,
components:
child: template: #child,



);
</script>

结果如下:

VUE深度解析_vue_09

父子组件间数据定义和访问

<!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>
<template id="secondComponent">
<div>
<span>count</span><br>
<button @click="incr">+</button>
</div>
</template>
<div id="app2" style="background-color:burlywood;">
<h2>secondComponent</h2><br>
<second-component></second-component>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>

var app = new Vue(
el: #app2,
components:
secondComponent:
template:#secondComponent,
data:function()
return count:0
,
methods:
incr()
this.count++;





);
</script>
</body>
</html>
  • ​secondComponent​​组件有自己的视图模板template#secondComponent
  • ​secondComponent​​组件有自己的数据定义,data()函数。这里定义的是一个函数,而不是对象,通过函数返回对象数据
  • ​secondComponent​​组件有自己的操作方法,定义在methods代码块中

父子组件的数据访问

<!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>
<!--父子组件的嵌套-->
<!-- <template id="Child">
<div>
<p>childMessage</p>
<input type="text" v-model="childMessage"><br>
<button @click="parentInfo()">打印父组件信息</button>
</div>
</template> -->


<template id="Child">
<div style="background-color: brown;">
<p>childMsg</p>
<input type="text" v-model="childMsg"><br>
<button @click="parentInfo()">调用父组件信息</button>
<h2>txt</h2>
</div>
</template>
<template id="Parent">
<div>
<p>parentMsg</p>
<input type="text" v-model="parentMsg"><br>
<button @click="childInfo()">打印子组件信息</button>
<child ref="childRef"></child>
<h2>msgL</h2>
<!-- <child></child> -->
</div>
</template>
<div id="app">
<parent></parent>
</div>
</div>
<!--从CDN引入vue.js-->
<script src="vue.min.js"></script>
<script>
var app2 = new Vue(
el: #app,
components:
Parent:
template: #Parent,
data: function()
return
parentMsg: "父组件的数据",
msgL:""

,
methods:
childInfo()
// console.log(this.$children[0].childMsg)
this.msgL="msgL: "+this.$children[0].childMsg
// console.log(this.$refs.childRef.childMsg)

,
components:
Child:
template: #Child,
data: function()
return
childMsg: "我是子组件的数据",
txt:""

,
methods:
parentInfo()
this.txt="txt: "+this.$parent.parentMsg
//console.log(this.$parent.parentMsg)






);
</script>
</body>

</html>

父组件是没有办法直接访问子组件的数据的,子组件也没有办法直接使用父组件的数据,那么就出现了

、children、$ref

VUE深度解析_vue_10

我们希望在子组件中使用this.打印父组件信息,在父组件中调用children[0]打印子组件信息

VUE深度解析_html_11

上面的方法中,父组件使用this.$children[0]来获取多个子组件的数据。如果我们希望快速的,从父组件获取子组件的数据,还可以为子组件加上一个属性ref。相当于为子组件起了一个别名,便于查找。

VUE深度解析_作用域_12

然后父组件通过如下代码即可打印子组件的属性数据:

console.log(this.$refs.childRef.childMsg)

使用props父组件向子组件传递数据

<!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>使用props父组件向子组件传递数据</title>
</head>
<body>
<div id="app">
<child :child-msg="msg" :child-ary="ary"></child>
<example :prop-a="propA" :prop-c="propC" ></example>
</div>
<template id="child">
<div>
<h2>childMsg</h2>
<h2>childAry</h2>
</div>
</template>
<template id="example">
<div>
<span>"propA"</span> <h2>propA</h2><br>
<span>"propC"</span> <h2>propC</h2><br>
<span>"propD"</span> <h2>propD</h2><br>
<span>"propE"</span> <h2>propE</h2><br>
</div>
</template>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script>
const child =
template: #child,
props: [childMsg,childAry]

const example =
template: #example,
props:
propA:type: Number,
propC:
type: String,
required: true
,
propD:
type: Number,
default: 100
,
propE:
type: Object,
default: function ()
return message: hello




const app = new Vue(
el: #app,
data:
ary:
name: 张三,age: 39,sex:"男"
,
msg: 父组件数据->子组件,
propA:10,
propC:"propC",
propD:40,
propF:5
,
components:
child,
example

)
</script>
</body>
</html>

VUE深度解析_vue_13

  • 父实例将自己数据msg,传递给child
  • 子组件通过绑定属性child-msg绑定父组件数据msg
  • 子组件标签属性child-msg对应子组件模型定义属性props:childMsg
  • childMsg属性可以使用插值表达式,显示template模板里面

props数据

通常我们定义一个组件是应该可以提供给其他模块或其他人使用的。使用者可能对该组件的用法并不熟悉,可能会导致错误。所以有必要在子组件内,对父组件传递过来数据进行校验。

VUE深度解析_作用域_14

子组件向父组件传播事件

父组件可以通过和ref的方式获取子组件的数据。但是在实际开发过程中,还有另外一种需求,即:子组件中发生了某些动作,从而改变了子组件的数据。那么父组件如何实时的监听到子组件数据的变化呢?那就是我们这一小节需要讲的核心内容

  • 在子组件使用$emit(‘事件名称’,参数),触发并发送事件,并且可以通过参数传值
methods:
incr()
this.count++
this.$emit(increment,this.count)
,
decr()
this.count--
this.$emit(decrement,this.count)

  • 在父组件中嵌入子组件,并使用v-on指令(简写为@)监听事件,从而触发回调函数,回调函数接受子组件发送的参数。图中changePcounter就是针对increment事件和decrment事件监听的回调函数
<div id="app">
<child-cpn @increment="changePCounter" @decrement="changePCounter"></child-cpn>
<h2>PCounter: pCounter</h2>
</div>
  • 父组件定义回调函数接收实践触发源传递的参数,即$emit的第二个参数
changePCounter(counter)
this.pCounter = counter

整体需求的实现

子组件与视图的定义。子组件点击加一按钮触发incr函数,incr函数触发increment事件,并将当前cCounter作为事件参数传递出去。父组件范围监听到increment事件,从而触发changePCounter方法,该方法接受cCounter作为参数。

VUE深度解析_数据_15

父组件的定义

VUE深度解析_数据_16

如果您觉得本文不错,欢迎关注,点赞,收藏支持,您的关注是我坚持的动力!

原创不易,转载请注明出处,感谢支持!如果本文对您有用,欢迎转发分享!


以上是关于VUE深度解析的主要内容,如果未能解决你的问题,请参考以下文章

Vue 核心

Vue 核心

VUE深度解析

深度解析 Vue 响应式原理

vue2.6.11源码深度解析

vue语法安装viteproperty 组件属性计算属性 watch深度监听