Vue框架入门与实践之一

1.Vue基础原理:
(1)vue.js中有两个核心功能:响应式数据绑定,组件系统
(2)MVC,MVP,MVVM之间的区别和理解;
*****MVC:
1) 视图(View):用户界面2) 控制器(Controller):业务逻辑3) 模型(Model):数据保存

MVC各个部分之间的通信方式如下:
1)视图传送指令到控制器2)控制器完成业务逻辑后要求模型改变状态3)模型将新的数据发送到视图,用户得到反馈

以上的所有通信都是单向的;接受用户指令的时候,MVC有两种方式。一种是通过视图接受指令,然后传递给控制器;另一种是用户直接给控制器发送指令;
实际使用中可能更加灵活,下面是Backbone.js为例说明:
1) 用户可以向视图(View)发送指令(DOM事件),再由View直接要求Model改变状态;2) 用户也可以向Controller发送指令(改变URL触发hashChange事件,再由Controller发送给View3) Controller很薄,只起到路由作用,而View非常厚,业务逻辑都放在View,所以Backbone索性取消了Controller,只保留了Router(路由器)

*****MVP:MVP适用于 事件驱动的应用架构中,如asp.net web form,window forms应用
1)各部分之间的通信都是双向的;2)视图(View)和模型(Model)不发生联系,都是通过表现(Presenter)传递的3)View非常薄,不部署任何业务逻辑,称之为被动视图(Passive View)即没有任何主动性,而Presenter非常厚,所有逻辑都在这里

*****MVVM: MVVM模式将Presenter层替换为ViewModel,其他与MVP基本一致,示意图如下:
1) 它和MVP的区别是,采用双向绑定,视图层(View)的变动,自动反映在ViewModel,反之亦然,Angular和Vue,React采用这种方式2) MVVM的提出源于WPF,主要用于分离应用界面层和业务逻辑层,WPF,Siverlight都基于数据驱动开发3) MVVM模式中,一个ViewModel和一个View匹配,完全和View绑定,所有View中的修改变化,都会更新到ViewModel中,同时ViewModel的任何变化都会同步到View上显示;之所以自动同步是ViewModel的属性都实现了observable这样的接口,也就是说当使用属性的set方法,会同时出发属性修改的事件,使绑定的UI自动刷新;

(3)数据双向绑定的流程:
1) 建立虚拟DOM Tree,通过document.createDocumentFragment(),遍历指定根节点内部节点,根据{{prop}},v-model等规则进行compile(主要负责给node节点赋值);2) 通过Object.defineProperty()进行数据变化拦截3) 截取到的数据变化,通过发布者-订阅者模式,触发Watcher,从而改变虚拟DOM中的具体数据;订阅发布模式(又称为观察者模式)定义一种一对多的关系,让多个观察者同时监听一个主题对象,主题对象状态发生改变的时候通知所有的观察者。发布者发出通知 => 主题对象收到通知并推送给订阅者 => 订阅者执行相应的操作

4) 通过改变虚拟DOM元素值,从而改变最后渲染dom树的值,完成双向绑定
 完成数据双向绑定的关键在于:Object.defineProperty()
Vue的数据驱动主要实现建立在是三个对象上 Dep( 主题对象 ),Watcher,Compiler
Dep 主要负责依赖的收集Watcher 主要负责Dep和Compiler之间的联系Compiler 可以理解为virtual dom(虚拟DOM)  + patch 也就是负责视图层的渲染

(4)简易双绑:首先,我们把注意力集中到这个属性上: Object.defineProperty;
Object.defineProperty()方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象语法:Object.defineProperty(obj,prop,descriptor)obj:要在其上定义属性的对象
prop:要定义或者修改的属性名字
descriptor:将定义或修改的属性描述符

举例如下:
var obj = {};
Object.defineProperty(obj,'hello',{   //这里整个都是属性描述符get:function(){//我们在这里拦截到了数据console.log("get方法被调用");},set:function(newValue){//改变数据的值,拦截下来额console.log("set方法被调用");}
});
obj.hello//输出为“get方法被调用”,输出了值。
obj.hello = 'new Hello';//输出为set方法被调用,修改了新值

通过以上方法可以看出, 获取对象属性值触发get,设置对象属性值触发set,因此我们可以想象到数据模型对象的属性 设置和读取可以驱动view层的数据变化,view的数据变化传递给数据模型对象,在Set里面可以做很多事情。
在这基础上,我们可以做到数据的双向绑定:
  
  let obj = {};Object.defineProperty(obj, 'name', {set: function(newValue){console.log('触发setter');document.querySelector('.text-box').innerHTML = newValue;document.querySelector('.inp-text').value = newValue;},get: function(){console.log('触发getter');}});document.querySelector('.inp-text').addEventListener('keyup', function(e){obj.name = e.target.value;}, false);

html:
<input class="inp-text" type="text">
<div class="text-box"></div>

以上只是 Vue的核心思想,通过对象底层属性的set和get进行数据拦截,vue的虚拟DOM又是怎么实现的呢?且看以下分解
(5)虚拟DOM树:
*****创建虚拟DOM的关键:var frag =  document.createDocumentFragment()
DocumentFragment(文档片段) 可以看做是 节点容器 ,它可以包含多个子节点,可以把它插入到DOM中,只有它的子节点会插入目标节点,所以可以把它看做是一组节点容器。使用DocumentFragment处理节点 速度和性能优于直接操作DOM 。Vue进行编译的时候就是将 挂载目标的所有子节点劫持到DocumentFragment 中,进过处理后再将DocumentFragment 整体返回到挂载目标
*****view层的{{msg}}和 v-model的HTML如下:
<div id="container">{{ msg }}<input class="inp-text" type="text" v-model="inpText"><div class="text-box"><p class="show-text">{{ msg }}</p></div>
</div>

*****view层的{{msg}}和 v-model的编译规则如下:
  
  var container = document.getElementById('container');//这里我们把vue实例中的data提取出来,更加直观var data = {msg: 'Hello world!',inpText: 'Input text'};var fragment = virtualDom(container, data);container.appendChild(fragment);//虚拟dom创建方法,将目标盒子内所有子节点添加到其内部,注意这里只有子节点function virtualDom(node, data){let frag = document.createDocumentFragment();let child;// 遍历dom节点while(child = node.firstChild){compile(child, data);frag.appendChild(child);}return frag;}//编译规则,子节点通过compile进行编译,a:如果节点为元素,其nodeType = 1;b:如果节点为文本,其nodeType = 3 function compile(node, data){let reg = /\{\{(.*)\}\}/g;if(node.nodeType === 1){ // 标签let attr = node.attributes;for(let i = 0, len = attr.length; i < len; i++){// console.log(attr[i].nodeName, attr[i].nodeValue);if(attr[i].nodeName === 'v-model'){let name = attr[i].nodeValue;node.value = data[name];   //给node节点赋值data}}if(node.hasChildNodes()){node.childNodes.forEach((item) => {compile(item, data); // 递归,如果第二步子节点仍有子节点,通过hasChildNodes()来确认,如果有递归调用Compile方法});}}if(node.nodeType === 3){ // 文本节点if(reg.test(node.nodeValue)){let name = RegExp.$1;name = name.trim();node.nodeValue = data[name];}}}

(6)响应式原理:
第一步:核心思想:Object.defineProperty(obj,key,{set,get})----定义访问器属性
    
function defineReact(obj, key, value){Object.defineProperty(obj, key, {set: function(newValue){console.log(`触发setter`);value = newValue;console.log(value);},get: function(){console.log(`触发getter`);return value;}});}

第二步:这里只是针对data数据的属性的响应式定义(从数据出发去理解原理,数据驱动),但是如何去实现 vue实例vm绑定data每个属性,通过以下方法:
    function observe(obj, vm){Object.keys(obj).forEach((key) => {defineReact(vm, key, obj[key]);   //定义访问器属性})}

第三步:vue的构造函数:到这里就实现了Vue实例绑定data属性
    function Vue(options){this.data = options.data;let id = options.el;observe(this.data, this); // 将每个data属相绑定到Vue的实例上this}

第四步:如何去实现Vue,实例化Vue:
    var vm = new Vue({el: 'container',data: {msg: 'Hello world!',inpText: 'Input text'}});console.log(vm.msg); // Hello world!console.log(vm.inpText); // Input text

第五步:要实现第四步的效果,必要前提是在Vue内部初始化虚拟Dom:
     function Vue(options){this.data = options.data;let id = options.el;observe(this.data, this); // 将每个data属相绑定到Vue的实例上this//------------------------添加以下代码let container = document.getElementById(id);let fragment = virtualDom(container, this); // 这里通过vm对象初始化container.appendChild(fragment);}

第六步:至此我们已经实现了 dom的初始化下一步我们在v-model元素添加监听事件,这样就可以通过view层的操作来修改vm对应的属性值;在compile编译的时候,可以准确的找到v-model属性元素,因此我们把监听事件添加到compile内部
    function compile(node, data){let reg = /\{\{(.*)\}\}/g;if(node.nodeType === 1){ // 标签let attr = node.attributes;for(let i = 0, len = attr.length; i < len; i++){// console.log(attr[i].nodeName, attr[i].nodeValue);if(attr[i].nodeName === 'v-model'){let name = attr[i].nodeValue;node.value = data[name];// ------------------------添加监听事件node.addEventListener('keyup', function(e){data[name] = e.target.value;}, false);// -----------------------------------}}if(node.hasChildNodes()){node.childNodes.forEach((item) => {compile(item, data);});}}if(node.nodeType === 3){ // 文本节点if(reg.test(node.nodeValue)){let name = RegExp.$1;name = name.trim();node.nodeValue = data[name];}}}

第七步: 这一步我们操作页面输入框,可以看到以下效果,证明监听事件添加有效。
到这里我们已经实现了MVVM, 即 Model -> vm -> View || View -> vm -> Model  中间桥梁就是vm实例对象;
(7)进一步完善响应式数据绑定,引入观察者模式原理:

*****订阅者:三个订阅者都有update方法

var subscribe_1 = {update: function(){console.log('This is subscribe_1');}};var subscribe_2 = {update: function(){console.log('This is subscribe_2');}};var subscribe_3 = {update: function(){console.log('This is subscribe_3');}};

*****发布者:发布者通过notify方法对订阅者广播,订阅者通过update来接受信息

function Publisher(){this.subs = [subscribe_1, subscribe_2, subscribe_3]; // 添加订阅者}Publisher.prototype = {constructor: Publisher,notify: function(){      this.subs.forEach(function(sub){sub.update();})}};

*****实例化publisher:

var publisher = new Publisher();publisher.notify();*****创建中间件来处理发布者-订阅者模式:var publisher = new Publisher();var middleware = {publish: function(){publisher.notify();}};middleware.publish();
(8)观察者模式嵌入:
我们已经实现了,接下来要实现:更新视图,同事把订阅-发布者模式嵌入
1) 修改 v-model 属性元素  -> 触发修改vm的属性值  -> 触发set
2) 发布者添加订阅  ->  notify分发订阅  -> 订阅者update数据

*****发布者:

function Publisher(){this.subs = []; // 订阅者容器}Publisher.prototype = {constructor: Publisher,add: function(sub){this.subs.push(sub); // 添加订阅者},notify: function(){this.subs.forEach(function(sub){sub.update(); // 发布订阅});}};
*****订阅者: 考虑到要把订阅者绑定data的每个属性,来观察属性的变化,参数:name参数可以有compile中获取的name传参;
                     由于传入的node节点类型分为两种,可以分为两个订阅者来处理,同时可以对node节点类型进行判断,通过switch分别处理:
 
   function Subscriber(node, vm, name){this.node = node;this.vm = vm;this.name = name;}Subscriber.prototype = {constructor: Subscriber,update: function(){let vm = this.vm;let node = this.node;let name = this.name;switch(this.node.nodeType){case 1:node.value = vm[name];  //赋值功能移到了订阅者这里break;case 3:node.nodeValue = vm[name];  //赋值功能移到了订阅者这里break;default:break;}}};

*****我们要把订阅者添加到compile进行虚拟dom的初始化,替换掉原来的赋值:

function compile(node, data){let reg = /\{\{(.*)\}\}/g;if(node.nodeType === 1){ // 标签let attr = node.attributes;for(let i = 0, len = attr.length; i < len; i++){// console.log(attr[i].nodeName, attr[i].nodeValue);if(attr[i].nodeName === 'v-model'){let name = attr[i].nodeValue;// --------------------这里被替换掉// node.value = data[name];new Subscriber(node, data, name);// ------------------------添加监听事件node.addEventListener('keyup', function(e){data[name] = e.target.value;}, false);}}if(node.hasChildNodes()){node.childNodes.forEach((item) => {compile(item, data);});}}if(node.nodeType === 3){ // 文本节点if(reg.test(node.nodeValue)){let name = RegExp.$1;name = name.trim();// ---------------------这里被替换掉// node.nodeValue = data[name];new Subscriber(node, data, name);}}}
*****既然是对虚拟dom编译的初始化, Subscriber也要初始化,即Subscriber.update,因此要对Subscriber作进一步的处理:
   function Subscriber(node, vm, name){this.node = node;this.vm = vm;this.name = name;this.update();}Subscriber.prototype = {constructor: Subscriber,update: function(){let vm = this.vm;let node = this.node;let name = this.name;switch(this.node.nodeType){case 1:node.value = vm[name];break;case 3:node.nodeValue = vm[name];break;default:break;}}};

*****发布者添加到 defineRect函数,来观察数据的变化:

function defineReact(data, key, value){let publisher = new Publisher();Object.defineProperty(data, key, {set: function(newValue){console.log(`触发setter`);value = newValue;console.log(value);publisher.notify(); // 发布订阅},get: function(){console.log(`触发getter`);if(Publisher.global){ //这里为什么来添加判断条件,主要是让publisher.add只执行一次,初始化虚拟dom编译的时候来执行publisher.add(Publisher.global); // 添加订阅者}return value;}});}
*****这一步将订阅者添加到发布者容器内, 对订阅者改造:
  function Subscriber(node, vm, name){Publisher.global = this;this.node = node;this.vm = vm;this.name = name;this.update();Publisher.global = null;}Subscriber.prototype = {constructor: Subscriber,update: function(){let vm = this.vm;let node = this.node;let name = this.name;switch(this.node.nodeType){case 1:node.value = vm[name];break;case 3:node.nodeValue = vm[name];break;default:break;}}};

2.Vue的状态管理Vuex:
(1)vuex是一个专门为vue.js设计的状态管理模式,并且也可以使用devtools进行调试,可以多个组件共享状态;
简单来说,就是 共享的状态用state存放,用mutations来操作state,但是需要用store.commit来主动式的操作mutations;
(2)举例说明:
***** 在使用vues之前要先安装依赖(前提是已经 用Vue脚手架工具构建好项目
cnpm install vuex –save

*****在入口文件main.js里需要 引入 vuex,注册vuex,实例化store,把store放在全局的实例化对象
import Vue from 'vue'
import App from './App'
//1.引入vuex
import Vuex from 'vuex'
import Apple from './components/Apple'
import Banana from './components/Banana'
Vue.config.productionTip = false
//2.注册
Vue.use(Vuex);
//3.实例化store
let store=new Vuex.Store({state:{totalPrice:0},mutations:{increment(state,price){state.totalPrice+=price},decrement(state,price){state.totalPrice-=price}},actions:{increase (context,price){context.commit('increment',price)},decrease (context,price){context.commit('decrement',price)}},getters:{discount(state){return state.totalPrice *0.8;}}
})
new Vue({el: '#app',//4.把store放在全局的实例化对象里,可以在全局的所有地方用store,components: { App},template: '<App/>'
})

*****参数介绍:


1) statevuex使用单一状态树,那么就可以用一个对象包含全部的应用层级状态,所以state就作为数据源2) mutations更改Vuex的store中的状态的唯一方法就是提交mutations,Vuex中的mutations非常类似于事件:每个mutation都有一个字符串的 事件类型(type)和一个回调函数(handler),这个回调函数就是我们实际进状态更改的地方,并且它会接受state作为第一个参数。不能直接调用一个mutation handler,这个选项更像是事件注册:当触发一个type为 increment的mutation时,就调用handler。要唤醒一个mutation handler,需要调用store.commit方法触发相应的type,可以向store.commit传入额外的参数,这个参数就叫做mutation的载荷。在更多的情况下,载荷应该是一个对象,这样可以包含更多的字段;mutations必须是同步函数,那么我们如何来异步的更新state呢?答案就是actions3) actionsactions类似于mutations,不同的是:actions提交的是mutations,而不是直接变更状态,这也就形成了actions--mutations--state的过程;actions可以包含任意异步操作;action 函数接受一个与store实例具有相同方法和属性的context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state和context.getter来获取state和getter,但是如何触发呢?答案是:store.dispatch4) getters有时候我们需要从store中的state中派生出一些状态,getter会暴露为store.getter对象在组件中使用。5) modules除了上边用到的4个参数,store还有另一个参数:modules;vuex允许把store进行一个功能拆分,分割成不同的模块(module),每个模块都拥有自己的store,mutation,action,getters
*****App.vue:
<template><div id="app"><Apple></Apple><Banana></Banana><p> 总价{{totalPrice}}</p><p> 折后价:{{discountPrice}}</p></div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
import Apple from './components/Apple'
import Banana from './components/Banana'
export default {name: 'App',components: {HelloWorld,Apple,Banana},computed:{totalPrice(){//由于vuex的状态存储是响应式的,所以从store实例中读取状态的最简单方法就是使用计算属性来返回某个状态:return this.$store.state.totalPrice},discountPrice(){//getter 会暴露为 store.getters 对象return this.$store.getters.discount    }}
}
</script>

*****当一个组件需要获取多个状态的时候,将这些状态都声明为计算属性会有些重复和冗余,为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性;
import { mapState } from 'vuex'computed: {...mapState(['totalPrice'])...}*****Banana.vue:<template>
<div><p>{{msg}} 单价{{price}}</p>    <button @click="addOne">add one</button><button @click="minusOne">minus one</button>
</div>
</template>
<script>
export default{data(){return{msg:'banana',price:15}},methods:{addOne(){                       //addOne()函数调用store.commit方法触发type为"increment"的mutation//直接commit一个mutationthis.$store.commit('increment',this.price)},minusOne(){                    //minusOne()函数调用store.commit方法触发type为"decrement"的mutationthis.$store.commit('decrement',this.price)}}
}
</script>

*****可以在组件中使用this.$store.commit('xxxx')提交mutation,或者使用 mapMutations辅助函数将组件中的methods映射为 store.commit调用;
methods:{addOne(){this.increment(this.price)},minusOne(){this.decrement(this.price)},...mapMutations(['increment', 'decrement'])
}

*****Apple.vue:  action相当于中介
<template>
<div><p> {{msg}}单价:{{price}} </p>    <button @click="addOne">add one</button><button @click="minusOne">minus one</button>
</div>
</template>
<script>
export default{data(){return{msg:'apple',price:5}},methods:{addOne(){                 //addOne()函数里调用store.dispatch方法触发名为"increase"的action,对应的,在increase这个action里再去调用context.commit方法触发type为"increment"的mutation//dispatch一个action,以action作为一个中介再去commit一个mutationthis.$store.dispatch('increase',this.price)},minusOne(){this.$store.dispatch('decrease',this.price)}}
}
</script>

*****mutation和actions的区别与联系:
1) action只能调用mutation不能直接更改state,执行action来分发(dispatch)事件通知store去改变
2) action里可以进行一些异步的操作,再去触发mutation
3) mutation里必须是同步的触发操作state

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

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

相关文章

开发者热评:关于App出海营销,他们表示要做好两件事!

NetMarvel 投身于开发者出海用户增长/广告变现业务已将近9个年头&#xff0c;帮助国内外众多开发者解决全球移动营销难题&#xff0c;最大化收益&#xff0c;实现全球范围内的极速增长。 NetMarvel有效助力Piggy Go、VNG、Candy Crack等游戏应用&#xff0c; Shopee、Tango等非…

进度猫:让项目进度更加可控的项目管理工具

你是否曾经在项目管理中遇到过以下问题&#xff1a; 无法准确掌握项目进度&#xff1b;任务分配不公平不合理&#xff1b;项目资源无法得到有效利用&#xff1b;项目风险无法及时发现和应对&#xff1b;项目质量无法得到保障&#xff1b;项目团队成员之间缺乏有效的沟通和协作…

【分布式微服务专题】从单体到分布式(二、SpringCloud整合Nacos)

目录 前言阅读对象阅读导航前置知识笔记正文一、下载安装二、项目整合2.1 服务注册与发现2.2 动态配置管理 三、其他实验四、服务之间的调用 学习总结感谢 前言 本篇笔记主要是记录我整合Nacos项目进来的过程。以实现服务注册发现&#xff0c;以及分布式配置管理。关于Nacos&a…

重塑未来工作方式,亚马逊云科技re:Invent推出生成式AI助手Amazon Q

亚马逊云科技在re:Invent 2023宣布推出Amazon Q&#xff0c;这是一种新型生成式AI支持的助手&#xff0c;专门用于满足办公场景需要&#xff0c;可以根据客户业务进行定制。客户可以快速获得复杂问题的相关答案、生成内容并采取行动——所有这些都基于客户自身的信息存储库、代…

超详细GitHub注册和登录教程

GitHub 是程序员开源精神之所系。在这个神奇的开源社区&#xff0c;职业程序员和编程爱好者畅所欲言&#xff0c;探寻自己感兴趣的项目、分享源代码、交流学习。最近看到好多朋友私信我&#xff0c;让我出一个详细的githup注册和登录的教程&#xff0c;现在它来啦&#xff01; …

CodeSys学习笔记

文章目录 1.运动控制的两种方式1.1.SM3_CNC1.2.SM3_Robotics 2.两种运动控制方式的速度、加速度等参数的控制2.1.SM3_CNC2.2.SM3_Robotics 3.CNC的M指令的使用&#xff08;实现&#xff09;逻辑。4.SM3_Robotics中的坐标系5.SM3_Robotics如何实现插补并连续执行&#xff1f;6.J…

《Linux源码趣读》| 好书推荐

目录 一. &#x1f981; 前言二. &#x1f981; 像小说一样趣读 Linux 源码三. &#x1f981; 学习路线 一. &#x1f981; 前言 最近、道然科技给狮子送了两本书&#xff1a;一本是付东来的《labuladong的算法笔记》、一本是闪客著的《Linux源码趣读》&#xff0c;《labulado…

回文日期

//每次枚举前四位,把前四位反转拼接到后面去,这样就是在回文数里判断一个数是不是合法日期 import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader;public class Main{static int n,m,res;static BufferedReader in new BufferedRead…

前端性能优化的一些方法和策略

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

【EI征稿中|ACM出版】2023 人工智能、系统与网络安全国际学术会议 (AISNS 2023)

2023 人工智能、系统与网络安全国际学术会议 (AISNS 2023&#xff09; 2023 International Conference on Artificial Intelligence, Systems and Network Security 由西南科技大学计算机科学与技术学院主办的2023人工智能、系统与网络安全国际学术会议 (AISNS 2023&#xff…

实现跨VLAN通信、以及RIP路由协议的配置

一、如下图片&#xff1a; 1. 按照拓扑图所示&#xff0c;将8台计算机分别配置到相应的VLAN中。&#xff08;20分&#xff09; 2. 配置实现同一VLAN中的计算机可以通信。&#xff08;22分&#xff09; 3. 配置实现PC1,PC2,PC3,PC4可以互相通信&#xff0c;PC5,PC6,PC7,PC8可以互…

数组指针与函数指针

欢迎关注博主 Mindtechnist 或加入【智能科技社区】一起学习和分享Linux、C、C、Python、Matlab&#xff0c;机器人运动控制、多机器人协作&#xff0c;智能优化算法&#xff0c;滤波估计、多传感器信息融合&#xff0c;机器学习&#xff0c;人工智能等相关领域的知识和技术。关…

超参数优化的多功能贝叶斯优化包SMAC3

地址 关键词 Bayesian optimization, hyperparameter optimization, SMAC3 文章概述 本文介绍了SMAC3&#xff0c;一个用于超参数优化的多功能贝叶斯优化包。SMAC3使用随机森林作为代理模型&#xff0c;并结合了多样性的BO和强化策略&#xff0c;如积极竞赛和多样性方法…

Python编程技巧 – 异常处理

Python编程技巧 – 异常处理 Python Programming Skills – Exception Handling By JacksonML 每一个程序都未必是健壮的&#xff0c;有时候很脆弱。只有在人的理想思维状况下&#xff0c;返回的结果才是正确的&#xff0c;如意的。 1. 错误发生及异常输出 面对种种编写有疏…

PR剪辑视频做自媒体添加字幕快速方式(简单好用的pr视频字幕模板)

如何选择合适的字幕添加进短视频呢&#xff1f;首先要先确定增加的视频风格&#xff0c;简约、商务、科技感、炫酷&#xff1b;再确定用途&#xff0c;注释、标记、语音翻译、引用、介绍&#xff1b;最后在相应的模板中挑选几个尝试&#xff0c;悬着一个最切合主题的使用&#…

推荐的国外自动控制原理优秀教材:现代控制系统

推荐国外著名高等院校信息科学与技术优秀教材《现代控制系统》&#xff08;Modern Control Systems&#xff09;&#xff0c;全书930页。自动控制原理课程教程,控制系统基础教材,涵盖控制工程方法,大量例题详细演示设计流程,电子版教学PPT和教学辅导手册供师生使用。 现代控制…

23、文件上传漏洞——Web容器及IIS

文章目录 一、常见web容器1.1 名词解释1.2 什么是web容器 二、IIS简介2.1 什么是IIS2.2 什么是文件解析 三、IIS6.0 文件解析漏洞3.1 漏洞利用 一、常见web容器 1.1 名词解释 服务器&#xff1a;一种管理资源并为用户提供服务的计算机。 web服务器&#xff0c;即www服务器或h…

C语言三种循环输出9*9乘法表

解题思路&#xff1a; 1、外层循环控制1~9循环 2、内层控制循环的次数 比如&#xff1a; 1 * 1 1 循环一次 1 * 1 1 1 * 2 循环两次 依此类推 int i, j;printf("for 打印9*9乘法表\r\n");for(i 1; i <10; i) {for(j 1; j < i;j) {printf("%d * %d %d…

QT----自定义信号和槽

第二天 2.1自定义信号和槽 新建一个Qtclass 自定义信号&#xff1a;返回值是void &#xff0c;只需要声明&#xff0c;不需要实现&#xff0c;可以有参数&#xff0c;可以重载 自定义槽&#xff1a;返回值void &#xff0c;需要声明&#xff0c;也需要实现&#xff0c;可以有…

学习设计模式的一个好网址

常用设计模式有哪些&#xff1f; (refactoringguru.cn)https://refactoringguru.cn/design-patterns