前端vue入门(纯代码)13

news2025/1/11 19:54:36

13.Vue的消息订阅与发布

  • 备注:全局事件总线用的更多些,消息订阅与发布只需了解即可。
  • 【注意点1】:由于“消息订阅与发布”可依赖的第三方库太多了,这里使用pubsub-js

问题:“全局事件总线”和“消息订阅与发布”都可以实现任意组件间通信,那用哪个好?

答案:推荐使用“全局事件总线”,因为它是vue提供的,完全使用的vue技术,而“消息订阅与发布”则是第三方。

  • 消息订阅与发布的作用:一种组件间通信的方式,适用于任意组件间通信【与数据总线的作用相似】。

图解消息发布与订阅

在这里插入图片描述

【举例】C组件想给A组件传递数据:

  • A组件是订阅者,A订阅一个名叫demo的消息,并设置一个test回调函数;C组件是发布者,C会发布一个名叫demo的消息,并将C组件里面的数据传递出去。如上图所示,一旦C发布了demo消息【附带传递的数据,‘888’】,就会让A组件收到订阅消息,并执行回调函数test,并且来接收C传递过来的数据。【注意:回调函数test收到的第一个参数是订阅的消息名,第二个参数才是收到的data】

Student组件给School组件传递数据的使用步骤:

  1. 安装pubsub:npm i pubsub-js(安装不成功、使用管理员权限运行)

  2. 引入pubsub-js库【该库安装在node_modiles文件中】: import pubsub from 'pubsub-js'(订阅和发布都要引入)

  3. 订阅者订阅:School.vue文件中

    // 挂载
    mounted() {
        // 订阅消息:haha     回调函数:箭头函数  
        // params:接收的参数【传过来的数据是一个数组】
        //下划线【_】:接受的参数是haha[订阅的消息]
        this.pubId = pubsub.subscribe('haha', (_,params) => {
        console.log("收到的第一个参数",params[0]); //haha
        console.log("收到的第二个参数",params[1]); //何大春
        this.StudentAge=params[1]
        this.StudentName=params[0]
        });
    },
    
  4. 发布者发布:Student.vue文件中

    methods: {
    SendStudentData(){
      // 发布订阅消息haha,并传递数据params 
      const params =[this.name,this.age] 
      pubsub.publish('haha',params)
    }
    },
    
  5. 订阅者取消订阅:School.vue文件中

    // 销毁前取消订阅
    beforeDestroy() {
        // 取消订阅
        pubsub.unsubscrib(this.pubId)
    },
    

完整代码:

  • main.js文件中需要修改的代码

    //引入Vue
    import Vue from 'vue'
    //引入App
    import App from './App.vue'
    //关闭Vue的生产提示
    Vue.config.productionTip = false
    
    //创建vm
    new Vue({
    	el:'#app',
    	render: h => h(App),
    })
    
  • App.vue文件中需要修改的代码

    <template>
      <div> 
        <School/>
        <br/>
        <Student/>
      </div>
    </template>
    
    <script>
    import School from "./components/School";
    import Student from './components/Student';
    export default {
    	name: 'App',
      components: {School,Student},
    };
    </script>
    
  • School.vue文件

    <template>
    	<div class="school">
    		<h1>School组件</h1>
    		<h2>兄弟组件Student传过来的name:{{ StudentName }}</h2>
    		<h2>兄弟组件Student传过来的age:{{ StudentAge }}</h2>
    	</div>
    </template>
    
    <script>
    import pubsub from 'pubsub-js';
    export default {
    	name: 'School',
    	data() {
    		return {
    			StudentName: '',
    			StudentAge: '',
    		};
    	},
    	// 挂载
    	mounted() {
    		// 订阅消息:haha     回调函数:箭头函数  
    		// params:接收的参数
    		this.pubId=pubsub.subscribe('haha', (_,params) => {
            console.log("收到的第一个参数",params[0]); //haha
            console.log("收到的第二个参数",params[1]); //何大春
            console.log("收到的params参数",params); //何大春
            this.StudentAge=params[1]
            this.StudentName=params[0]
    		});
    	},
    	// 销毁前取消订阅
    	beforeDestroy() {
        // 取消订阅
        pubsub.unsubscrib(this.pubId)
      },
    };
    </script>
    
    <style scoped>
    .school {
    	background-color: rgb(73, 192, 150);
    }
    </style>
    
  • Student.vue文件

    <template>
    	<div class="student">
        <h1>Student组件信息</h1>
    		<h2>学生姓名:{{ name }}</h2>
    		<h2>学生性别:{{ sex }}</h2>
    		<h2>学生年龄:{{ age }}</h2>
    		<h2>学生成绩:{{ score }}</h2>
    		<button class="haha" @click="SendStudentData">
          <h2>点击此处给兄弟组件School传值</h2></button>
    	</div>
    </template>
    
    <script>
    import pubsub from 'pubsub-js'
    export default {
    	name: 'Student',
    	data() {
    		return {
    			name: '何大春',
    			sex: '男',
    			age: '22',
    			score: '88',
    		};
    	},
    	methods: {
        SendStudentData(){
          // 发布订阅消息haha,并传递数据
          const params =[this.name,this.age] 
          pubsub.publish('haha',params)
        }
    	},
    };
    </script>
    
    <style lang="less" scoped>
    .student {
    	background-color: tomato;
    	padding: 50px;
    	margin-top: 50px;
    	margin-left: 50px;
    	width: 300px;
    	height: 350px;
    }
    .h2 {
      padding: 5px;
      margin: 5px 5px 5px 5px;
    }
    .haha {
      background-color: rgb(211, 233, 130);
    }
    </style>
    

在这里插入图片描述

补充知识点:

注意1:“取消订阅方式和“全局事件总线”不同,取消订阅得指定订阅返回的id,且每次返回的id都不同,而“全局事件总线”指定的是“自定义事件名称”

 this.pubId = pubsub.subscribe('订阅消息名',(_,params)=>{ })
beforeDestroy() {
    // 取消订阅
    pubsub.unsubscrib(this.pubId)
},

注意2:订阅【pubsub.subscribe()】回调配置一定要使用箭头函数【如上面的代码】或者外部定义方法【将回调函数配置在methods中,再去订阅中引用】,在订阅中引用也行,千万不要使用普通函数,因为普通函数中this不指代vc,而是undefind。

注意3:消息订阅会接收到2个参数,第1个参数为消息名称,第2个参数才是传递过来的值,但是实际msgName参数1他跟用不到它,所以可使用下划线“_”占个位。【写法如下】

this.pubId = pubsub.subscribe('hello',(msgName,data)=>{
// console.log('有人发布了hello消息,hello消息的回调执行了',msgName,data)
})

注意4:如果想传递多个参数,需使用对象的形式{}或数组的形式[]【写法如下】

发送方

// 发布订阅消息haha,并传递数据
// 方法一:利用数组传递多个数据
// const paramsArray =[this.name,this.age] 
// pubsub.publish('haha',paramsArray)

// 方法二:利用对象传递多个数据
const paramsObeject = {name:this.name,age:this.age}
pubsub.publish('haha',paramsObeject)

接收方

// 挂载
	mounted() {
	// 订阅消息:haha     回调函数:箭头函数  
	// params:接收的参数
/*  this.pubId=pubsub.subscribe('haha', (_,params) => {
    console.log("收到的第一个参数",params[0]); //haha
    console.log("收到的第二个参数",params[1]); //何大春
    console.log("收到的params参数",params); //何大春
    this.StudentAge=params[1]
    this.StudentName=params[0]
		}); */
        
    // 方法二:利用对象传递多个数据
     this.pubId=pubsub.subscribe('haha', (_,paramsObeject) => {
	 console.log("对象的name参数",paramsObeject.name); //haha
	 console.log("对象的age参数",paramsObeject.age); //何大春
	 console.log("收到的params参数",paramsObeject); //{name: '何大春', age: '22'}
     this.StudentAge=paramsObeject.age
     this.StudentName=paramsObeject.name
		});
	},

14.TodoList案例之消息订阅与发布

  • 备注:主要是将之前利用全局事件总线来实现组件间的通信,改为利用消息订阅与发布来实现组件间的通信

  • App.vue文件中需要修改的代码

    • 原本 Todo案例中TodoItem给App组件传递数据【通信】的方法:利用全局事件总线去通信
    <TodoList 
     :todos="todos"
    />
    
    mounted() {
      //勾选or取消勾选一个todo
      this.$bus.$on('checkTodo',(id)=>{
        this.todos.forEach((todo) => {
          if(todo.id === id) todo.done = !todo.done
        })
      })
      this.$bus.$on('deleteTodo',(id)=>{
       // 删除一个todo
       // deleteTodo里面的id指的是:点击事件对应的id
        console.log('deleteTodo',id);
    
        this.todos=this.todos.filter(
          (todo)=>{
            return todo.id != id
          }
        )
      })
    },
    beforeDestroy() {
      this.$bus.$off(['deleteTodo','checkTodo'])
    },
    
    • 修改后: Todo案例中TodoItem给App组件传递数据【通信】的方法:利用消息的订阅与发布去通信
    <TodoList 
     :todos="todos"
    />
    
        mounted() {
          // 利用数据总线去通信
          //勾选or取消勾选一个todo
          this.$bus.$on('checkTodo',(id)=>{
            this.todos.forEach((todo) => {
              if(todo.id === id) todo.done = !todo.done
            })
          })
          
          // 利用消息的订阅与发布去通信
          // 订阅deleteTodo
          this.pubId = pubsub.subscribe('deleteTodo',(_,id)=>{
            this.todos=this.todos.filter(
              (todo)=>{
                return todo.id != id
              }
            )
          })
        },
        beforeDestroy() {
          // this.$bus.$off(['deleteTodo','checkTodo'])
          this.$bus.$off(['checkTodo'])
          // 取消订阅
          pubsub.unsubscribe(this.pubId)
        },
    
  • TodoItem.vue文件中需要修改的代码

    • 原本 Todo案例中TodoItem给App组件传递数据【通信】的方法:利用全局事件总线去通信
    //点击后,自定义事件deleteTodo触发后通知App组件将对应的todo对象删除,传参数
    this.$bus.$emit('deleteTodo',this.todo.id)
    
    • 修改后: Todo案例中TodoItem给App组件传递数据【通信】的方法:利用消息的订阅与发布去通信
    //点击后,发布订阅后通知App组件接收订阅消息deleteTodo和参数this.todo.id
    pubsub.publish('deleteTodo',this.todo.id)
    

完整代码:

main.js

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
//关闭Vue的生产提示
Vue.config.productionTip = false

//创建vm
new Vue({
	el:'#app',
	render: h => h(App),
  // 生命周期钩子beforeCreate中模板未解析,且this是vm
  beforeCreate() {
    // this:指的是vm
		Vue.prototype.$bus = this  //安装全局事件总线$bus
  }
})

App.vue

<template>
	<div id="root">
		<div class="todo-container">
			<div class="todo-wrap">
        <TodoHeader @addTodo="addTodo"/>
				<TodoList 
         :todos="todos"
        />
				<TodoFooter
        :todos="todos"
        @checkAllTodo="checkAllTodo"
        @clearAllTodo="clearAllTodo"
        />
			</div>
		</div>
	</div>
</template>

<script>
import pubsub from "pubsub-js";
//引入App的子组件
import TodoHeader from './components/TodoHeader'
import TodoFooter from './components/TodoFooter'
import TodoList from './components/TodoList'

  export default {
    name:'App',
    components: { TodoHeader,TodoFooter,TodoList },
    data() {
      return {
        //由于todos是TodoHeader组件和TodoFooter组件都在使用,所以放在App中(状态提升)
        todos:[
          {id:'001',title:'练功夫',done:true},
					{id:'002',title:'睡觉',done:false},
					{id:'003',title:'打豆豆',done:true}
        ],
      }
    },
    methods: {
      //添加一个todo
      addTodo(todoObj){
        // 在数组的开头添加一个数据
        this.todos.unshift(todoObj)
      },
      //全选or取消全选
      checkAllTodo(done){
        this.todos.forEach(todo => todo.done = done)
      },
      // 清除所有已经完成的todo
      clearAllTodo(){
        this.todos= this.todos.filter(todo =>{
          return todo.done == false
          // 或者换成 return !todo.done
        }
        )
      },
    },
    mounted() {
      // 利用数据总线去通信
      //勾选or取消勾选一个todo
      this.$bus.$on('checkTodo',(id)=>{
        this.todos.forEach((todo) => {
          if(todo.id === id) todo.done = !todo.done
        })
      })
      
      // 利用消息的订阅与发布去通信
      // 订阅deleteTodo
      this.pubId = pubsub.subscribe('deleteTodo',(_,id)=>{
        this.todos=this.todos.filter(
          (todo)=>{
            return todo.id != id
          }
        )
      })
    },
    beforeDestroy() {
      // this.$bus.$off(['deleteTodo','checkTodo'])
      this.$bus.$off(['checkTodo'])
      // 取消订阅
      pubsub.unsubscribe(this.pubId)
    },

  }
</script>

<!-- style没有scoped属性:【全局样式】 -->
<!-- style有scoped属性:样式设置只在本组件里起作用【局部样式】 -->
<style>
	/*base*/
	body {
		background: #fff;
	}
  .btn {
    /* 行内的块级元素 */
		display: inline-block;
		padding: 4px 12px;
		margin-bottom: 0;
		font-size: 14px;
		line-height: 20px;
    /* 文本内容居中 */
		text-align: center;
    /* 垂直居中 */
		vertical-align: middle;
		cursor: pointer;
		box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
		border-radius: 4px;
	}
	.btn-danger {
    /* 字体颜色设置:白色 */
		color: #fff;
		background-color: #da4f49;
		border: 1px solid #bd362f;
	}
  /* 鼠标移动到删除按钮时 */
	.btn-danger:hover {
		color: #fff;
		background-color: #bd362f;
	}
	.btn:focus {
		outline: none;
	}

	.todo-container {
		width: 600px;
    /* 上下外边距为0,左右自动,实际效果为左右居中*/
		margin: 0 auto;
	}
  /* 后代选择器(包含选择器),选择到的是todo-container下面的所有后代todo-wrap  */
	.todo-container .todo-wrap {
		padding: 10px;
		border: 1px solid #67dbd1;
		border-radius: 5px;
	}
</style>

TodoHeader.vue

<template>
	<div class="todo-header">
    <!-- @keyup.enter="add" :按下回车按键,调用add方法 -->
		<input type="text" placeholder="请输入你的任务名称,按回车键确认" @keyup.enter="add" v-model="title"/>
	</div>
</template>

<script>
// 引入nanoid库生成ID号
import { nanoid } from 'nanoid'
export default {
	name: 'TodoHeader',
/*   //接收从App组件【父组件】传递过来的addTodo方法
  props:['addTodo'], */
  data() {
    return {
      title: '',
    }
  },
  methods: {
    add(){
      // 如果输入框里为空,就跳过下面的代码,并弹窗
      if (!this.title.trim()) return alert('请输入值')
      //将用户的输入包装成一个todo对象
      const todoObj={id:nanoid(),title:this.title,done:false}
      //通知App组件去添加一个todo对象
      //触发自定义事件addTodo,并把子组件中的参数todoObj传给父组件
      this.$emit('addTodo',todoObj)
      //清空输入
      this.title = ''
    }
  },
};
</script>

<style scoped>
    /* 头部样式设置 */
    /* 后代选择器(包含选择器),选择到的是todo-header下面的所有后代input */
    .todo-header input {
		width: 560px;
		height: 28px;
		font-size: 14px;
		border: 1px solid #ccc;
		border-radius: 4px;
    /* 内边距:上下4px,左右7px */
		padding: 4px 7px;
	}

  /* :focus获得焦点,并设置其新样式:例如:用户单击一个input输入框获取焦点,然后这个input输入框的边框样式就会发生改变,和其他的输入框区别开来,表明已被选中。 */
	.todo-header input:focus {
    /* outline 与 border 相似,不同之处在于 outline 在整个元素周围画了一条线;它不能像 border 那样,指定在元素的一个面上设置轮廓,也就是不能单独设置顶部轮廓、右侧轮廓、底部轮廓或左侧轮廓。 */
		outline: none;
    /* 定义边框的颜色 */
		border-color: rgba(82, 168, 236, 0.8);
    /* boxShadow 属性把一个或多个下拉阴影添加到框上 */
    /* 设置inset:内部阴影,不设置inset:外部阴影 */
    /* 【0 0】:不设置X轴与Y轴偏移量 */
    /* 第三个值【如10px,8px】:设置值阴影模糊半径为15px */
		box-shadow: inset 0 0 10px rgba(124, 56, 207, 0.075), 0 0 8px rgba(224, 58, 17, 0.6);
    background-color: bisque;
	}
</style>

TodoList.vue

<template>
	<ul class="todo-main">
		<TodoItem 
    v-for="todoObj in todos" 
    :key="todoObj.id" 
    :todo="todoObj"
    />
	</ul>
</template>

<script>
import TodoItem from './TodoItem'
export default {
	name: 'TodoList',
  components:{TodoItem},
  //声明接收App传递过来的数据,其中todos是自己用的,checkTodo和deleteTodo是给子组件TodoItem用的
  props: ['todos']

};
</script>

<style scoped>
	/*main*/
	.todo-main {
    /* 左外边距:0px 【盒子贴着盒子】*/
		margin-left: 0px;
		border: 1px solid #ddd;
		border-radius: 2px;
		padding: 0px;
	}

	.todo-empty {
		height: 40px;
		line-height: 40px;
		border: 1px solid #ddd;
		border-radius: 2px;
		padding-left: 5px;
		margin-top: 10px;
	}
</style>

TodoItem.vue

<template>
	<li>
		<label>
			<input type="checkbox" 
              :checked="todo.done"
              @change="handleCheck()"
              />
			<span>{{todo.title}}</span>
		</label>
		<button class="btn btn-danger" @click="handleDelete()">删除</button>
	</li>
</template>

<script>
import pubsub from "pubsub-js";
export default {
	name: 'TodoItem',
  // 声明接受从别的组件中的todoObj对象,todo
  props: ['todo'],
  methods: {
    //勾选or取消勾选【别弄混了:这里的id其实就是上面change事件中的todo.id】
    handleCheck(){
      //change事件触发后,通知App组件将对应的todo对象的done值取反
      // this.checkTodo(id)
      this.$bus.$emit('checkTodo',this.todo.id)
      // console.log(this.todo.id);
    },
    //删除
    handleDelete(){
      if (confirm('Are you sure you want to delete?')) {
        //点击后,发布订阅后通知App组件将对应的todo对象删除,参数
        pubsub.publish('deleteTodo',this.todo.id)
      }
    }
  },
};
</script>

<style scoped>
 /*item*/
 li {
    /* ul无序列表 ol有序列表*/
    /* 列表前面无标记 */
		list-style: none;
    /* height定义了一个li盒子的高度 */
		height: 36px;
    /* 行高:指的是文字占有的实际高度 */
		line-height: 36px;
    /* 当height和line-height相等时,即盒子的高度和行高一样,内容上下居中 */
		padding: 0 5px;
    /* 边框底部:1px的实心线 颜色*/
		border-bottom: 1px solid #c0abc3;
	}

  /* 后代选择器(包含选择器),选择到的是li下面的所有后代label */
	li label {
    /* 左对齐浮动【元素一旦浮动就会脱离文档流(不占位,漂浮)】 */
		float: left;
    /* 鼠标放在label元素上时变成小小手 */
		cursor: pointer;
	}

	li label input {
     /* 垂直居中 */
		vertical-align: middle;
		margin-right: 6px;
		position: relative;
		top: -1px;
	}

   /* 后代选择器(包含选择器),选择到的是li下面的所有后代button */
	li button {
    /* 向右浮动 */
		float: right;
    /* 不为被隐藏的对象保留其物理空间,即该对象在页面上彻底消失,通俗来说就是看不见也摸不到。 */
		display: none;
    /* 上边距为3px */
		margin-top: 3px;
	}

	li:before {
    /* initial:它将属性设置为其默认值。 */
		content: initial;
	}

   /* 结构伪类选择器 选择最后一个li元素 */ 
	li:last-child {
    /* 边框底部没有线 */
		border-bottom: none;
	}

	li:hover{
		background-color: #ddd;
	}
	
  /* 鼠标移动到该元素上时,将button按钮显示出来 */
	li:hover button{
    /*  display:block将元素显示为块级元素 */
		display: block;
	}
</style>

TodoFooter.vue

<template>
	<div class="todo-footer" v-show="total">
		<label>
			<!-- <input type="checkbox" :checked="isAll" @change="checkAll"/> 
      可以用下面这行代码代替-->
      <!--对于type="checkbox",v-model绑定的就是一个布尔值,isAll为false or true  -->
			<input type="checkbox" v-model="isAll"/>
		</label>
		<span>
			<span>已完成{{ doneTotal }}</span> / 全部{{ total }}
		</span>
		<button class="btn btn-danger" @click="clearAllDone">清除已完成任务</button>
	</div>
</template>

<script>
export default {
	name: 'TodoFooter',
  props: ['todos'],
  computed:{
    //总数
    total(){
      return this.todos.length
    },
    // 已完成数
    doneTotal(){
      //此处使用reduce方法做条件统计
      /* return this.todos.reduce(
        // todo:遍历数组todos中的每一个元素
        // 比如:数组遍历时,把数组todos中的每一个元素分别赋值给todo【包含id='001'】
        (pre,todo)=>{
          // console.log('@',pre,todo)
          return pre + (todo.done ? 1 : 0)
        }
      ,0) */
      //简写
      return this.todos.reduce((pre,todo)=>pre + (todo.done ? 1 : 0),0)
    },
    //控制全选框
 /*    isAll(){
       //计算属性简写:isAll属性,只能被读取,不能被修改
      return this.total === this.doneTotal && this.total>0
    } */
    isAll:{
      //get有什么作用?当有人读取isAll时,get就会被调用,且返回值就作为isAll的值
			//get什么时候调用?1.初次读取isAll时。2.所依赖的数据发生变化时。
      get(){
        //全选框是否勾选  【&&:且】
        return this.total === this.doneTotal && this.total>0
      },
      //set什么时候调用? 当isAll被修改时。
      // value就是:v-model绑定的值false【未勾选】 or true【勾选】
      set(value){
        console.log(value)
        this.$emit('checkAllTodo',value)
      }
    },
  },
  methods: {
/*     checkAll(e){
      console.log(e.target.checked);
      // 拿到的是全选或者全不选的布尔值
      this.checkAllTodo(e.target.checked)
    } */

    // 清空所有已完成
    clearAllDone(){
      // this.clearAllTodo()
      this.$emit('clearAllTodo')
    }
  },
};
</script>

<style scoped>
	/*footer*/
	.todo-footer {
		height: 40px;
		line-height: 40px;
		padding-left: 6px;
		margin-top: 5px;
	}

	.todo-footer label {
		display: inline-block;
		margin-right: 20px;
		cursor: pointer;
	}

	.todo-footer label input {
		position: relative;
		top: -1px;
		vertical-align: middle;
		margin-right: 5px;
	}

	.todo-footer button {
		float: right;
		margin-top: 5px;
	}
</style>

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

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

相关文章

看完这篇 教你玩转渗透测试靶机vulnhub—Emplre: Breakout

Vulnhub靶机Emplre: Breakout渗透测试详解 Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a;②&#xff1a;登入后台&#xff1a;③&#xff1a;GetShell&#xff1a;④…

oracle操作xml格式数据

新建一张用来测试的表 -- Create table create table XMLTEST (id NUMBER,content VARCHAR2(4000) );往表中插入数据 insert into XMLTEST (id, content) values (1, <root><app><id>1</id><name>张三</name><age>18</age…

《网络安全0-100》经典访问控制策略

1经典访问控制策略 1.1自主访问控制 允许用户自己对客体将已有的权限赋予给其他主体&#xff0c;也可以撤销自己赋予给其他主体的权限。 矩阵结构分为三个主要的表&#xff1a; 访问控制矩阵 访问控制列表 权能表 矩阵的局限性&#xff1a; 大小为主体数量客体数量&…

【FPGA】Verilog:时序电路设计 | 自循环移位寄存器 | 环形计数 | 扭环计数 | 约翰逊计数器

前言&#xff1a;本章内容主要是演示Vivado下利用Verilog语言进行电路设计、仿真、综合和下载 示例&#xff1a;计数器 ​​ 功能特性&#xff1a; 采用 Xilinx Artix-7 XC7A35T芯片 配置方式&#xff1a;USB-JTAG/SPI Flash 高达100MHz 的内部时钟速度 存储器&#xff1a;2Mb…

Bresenham直线算法

文章目录 1.Bresenham直线算法1.1 算法流程1.2 Bresenham算法实现1.3matlab中应用1.4 算法优势1.5 对比以往方法的改进和优化1.6 算法改进和缺陷 2.国内外研究现状3.个人感想及算法改进 1.Bresenham直线算法 Bresenham直线算法是一种用于将两点之间的线段绘制在屏幕上的算法。…

什么是MLOps?为什么要使用MLOps进行机器学习实践

随着数字化和计算能力的发展&#xff0c;机器学习&#xff08;Machine Learning&#xff09;技术在提高企业生产力方面所涌现的潜力越来越被大家所重视&#xff0c;然而很多机器学习的模型及应用在实际的生产环境并未达到预期&#xff0c;大量的ML项目被证明是失败的。从机器学…

【Red Hat7.9安装Oracle11g】---调用图形化界面的几种方式

【Red Hat7.9安装Oracle11g】---调用图形化界面的几种方式 &#x1f53b; 一、续上一篇[【Red Hat 7.9---详细安装Oracle 11g---图形化界面方式】](https://blog.csdn.net/qq_41840843/article/details/131198718?spm1001.2014.3001.5501)⛳ 1.1 前言⛳ 1.2 方式一、使用Xmana…

MIT 6.S081 Lab Five

MIT 6.S081 Lab Five 引言xv6 lazy page allocationEliminate allocation from sbrk() (easy)代码解析 Lazy allocation (moderate)代码解析 Lazytests and Usertests (moderate)代码解析 可选的挑战练习 引言 本文为 MIT 6.S081 2020 操作系统 实验五解析。 MIT 6.S081课程前…

从C语言到C++_21(模板进阶+array)+相关笔试题

目录 1. 非类型模板参数 1.1 array 1.2 非类型模板参数的使用场景 1.3 注意事项 2. 模板的特化 2.1 函数模板的特化 2.2 类模板的特化 2.3 全特化和偏特化(半特化) 3. 模板关于分离编译 4. 模板优缺点 5. 模板相关笔试题 本章完。 1. 非类型模板参数 对于函数模板…

dhtmlx Event Calendar JavaScript new Crack

DHTMLX Event Calendar可帮助您开发类似 Google 的 JavaScript 事件日历&#xff0c;以高效地组织约会。用户可以通过拖放来管理事件&#xff0c;并以六种不同的模式显示它们。 JavaScript 事件日历功能 轻的 简单的 JavaScript API 六个默认视图&#xff1a;日、周、月、年、议…

Java并发编程学习16-线程池的使用(中)

线程池的使用&#xff08;中&#xff09; 引言1. 配置 ThreadPoolExecutor1.1 线程的创建与销毁1.2 管理队列任务1.3 饱和策略1.4 线程工厂1.5 定制 ThreadPoolExecutor 2. 扩展 ThreadPoolExecutor总结 引言 上篇分析了在使用任务执行框架时需要注意的各种情况&#xff0c;并…

死锁的成因以及解决方案(简析)

目录 一.为什么会产生死锁? 二.死锁产生的几个场景 一个线程一把锁的情况 关于可重入和不可重入锁的简单举例 两个线程两把锁的情况 多线程多把锁 如何解决死锁 一.为什么会产生死锁? 简单来说,就是进程加锁之后,没有被解锁而处于一直等待的状态 二.死锁产生的几个场景…

深入理解深度学习——BERT(Bidirectional Encoder Representations from Transformers):BERT的结构

分类目录&#xff1a;《深入理解深度学习》总目录 相关文章&#xff1a; BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;&#xff1a;基础知识 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09…

软件架构模式—分层架构

这是软件架构模式博客系列第 2 章&#xff0c;我们将讨论分层架构模式。 分层架构模式是一种n层模式&#xff0c;其中组件按照水平层次进行组织。这是设计大多数软件的传统方法&#xff0c;旨在实现自我独立。这意味着所有组件之间相互连接&#xff0c;但彼此之间不相互依赖。…

测试体系与测试方案设计

如果我们想要测试一个系统&#xff0c;我们得先需要了解被测系统架构 业务架构:业务模型分析技术架构:技术组件、通讯协议分析数据架构:数据模型、数据存储引擎分析 电子商城 Mall 开源项目技术架构 经典技术架构 网关产品 Nginx Apache HttpdWeb 应用开发 Vue.js React移动应…

福州大学学报退稿率【爬虫+数据处理】

目录 一、爬虫 二、数据处理 2.1 历年投稿总数&#xff1a; 2.2 各稿件状态比例&#xff1a; 2.3 历年退稿率 三、总结&#xff08;福州大学学报退稿率&#xff09; 一、爬虫 从福州大学学报微信公众号可以发现稿件状态的查询接口&#xff0c; 根据测试可知稿件号由年份与当…

Linux共享内存

博客内容&#xff1a;共享内存 文章目录 一、认识共享内存结构二、如何创建共享内存&#xff1f;1.创建共享内存2.关联进程&#xff0c;取消进程3.释放共享内存 三、代码示例总结 一、认识共享内存结构 共享内存 共享内存指 (shared memory)在多处理器的计算机系统中&#xff…

新手速成!如何使用ChatGPT成为你的导师

1. 写在前面 最近我发现咱们的团队现在是人手ChatGPT&#xff0c;不光是我们团队&#xff0c;我整个行业的人都在用它解决生活跟工作中遇到的问题。可以看到的是大家也都是对它赞赏度很高 本文我将为大家介绍如何更加高效的使用ChatGPT提高工作效率&#xff0c;面向ChatGPT编程…

JavaScript高级学习总结

函数作用域 函数内部声明的变量&#xff0c;在函数外部无法被访问函数的参数也是函数内部的局部变量不同函数内部声明的变量无法互相访问函数执行完毕之后&#xff0c;函数内部的变量实际被清空了 块作用域 let声明的变量会产生块作用域&#xff0c;var不会产生块作用域cons…

QT +OpenSSL配置

QT OpenSSL配置 1 查看自己QT支持的OPenSSL版本号1.1 查看版本号1.2 是否配置了OPenSSL 2 安装OPenSSL2.1 下载已经编译好的库2.2 自己编译代码2.2.1 下载perl2.2.1 下载OPenSSL源码 1 查看自己QT支持的OPenSSL版本号 1.1 查看版本号 新建项目testOpenSSLpro文件中加入QT ne…