前端vue入门(纯代码)14

内容创作不易,各位帅哥美女,求个小小的赞!!!

15.给todoList案例添加编辑按钮

本篇内容在TodoList案例的基础上添加个编辑按钮,要求:
(1)点击编辑按钮后,编辑事项,此时编辑按钮隐藏,输入框自动获取焦点

(2)编辑完后当输入框失去焦点,保存编辑后的内容

(1)TodoItem.vue文件中先添加一个编辑按钮和input框。

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

页面展示:

在这里插入图片描述

(2)TodoItem.vue文件中,上图中的12中只能展示一个。

  • v-show="todo.isEdit"v-show="!todo.isEdit"二选一来展示。

  • 【补充一个点】:v-show=“undefined”【判断为false,页面不展示】;v-show=“!undefined”【判断为true,页面展示】

    <span v-show="!undefined">答案是多所</span>
    

写法一:handleEdit(todo):将props传过来的数据todo传入函数handleEdit()中,然后<script></script>中定义函数handleEdit时需要用到todo这个对象时,可以直接用。【正常情况使用props传过来的数据要这样写this.todo

<label>
  <input type="checkbox" 
  :checked="todo.done"
  @change="handleCheck()"
  />
   <span v-show="!todo.isEdit">{{todo.title}}</span>
  <input type="text"
  :value="todo.title"
  v-show="todo.isEdit"
  >
</label>
<button class="btn btn-danger" @click="handleDelete()">删除</button>
<button class="btn btn-edit" @click="handleEdit(todo)">编辑</button>
//编辑
handleEdit(todo){
  // 判断对象todo里面是否有isEdit属性
  if(todo.hasOwnProperty('isEdit')){
    todo.isEdit=true
  }else{
    // 把todo.isEdit设置成响应式数据
    this.$set(todo,'isEdit',true)
  }
},

写法二:handleEdit():点击事件触发后,直接调用函数handleEdit()中【不带参数】,然后<script></script>中定义函数handleEdit时需要用到props传过来的数据todo这个对象时,不可以直接用,需要**this.todo**去调用props中的数据。【正常情况使用props传过来的数据要这样写this.todo

<label>
  <input type="checkbox" 
  :checked="todo.done"
  @change="handleCheck()"
  />
   <span v-show="!todo.isEdit">{{todo.title}}</span>
  <input type="text"
  :value="todo.title"
  v-show="todo.isEdit"
  >
</label>
<button class="btn btn-danger" @click="handleDelete()">删除</button>
<button class="btn btn-edit" @click="handleEdit()">编辑</button>
//编辑
handleEdit(){
  // 判断对象todo里面是否有isEdit属性
  if(this.todo.hasOwnProperty('isEdit')){
    this.todo.isEdit=true
  }else{
    // 把todo.isEdit设置成响应式数据
    this.$set(this.todo,'isEdit',true)
  }
},
  • A.hasOwnProperty(‘B’):是用来判断对象A里是否有你给出的名称的属性或对象【B】。有则返回true,没有返回false,不过需要注意的是,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。

  • A.$set(target,propertyName/index,value)添加的属性propertyName做响应式处理。

  • 参数

    • {Object | Array} target:对象或数组所在的地方 ,注:但不能是Vue实例或Vue实例的根元素

    • {string | number} propertyName/index:需要添加的属性名【比如:“性别”】

    • {any} value:添加的属性值【比如:“男”】

  • 返回值:设置的值

  • 用法向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.todo.isEdit=true)

为什么使用Vue.set()vm.$set()vc.$set()

  • 因为受现代JS的限制,vue不能检测到对象属性的添加或删除。由于vue会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在data对象上存在才能让vue转换它,这样它才能是响应的。vue不允许在已经创建的实例上动态添加新的根级响应式属性,不过可以使用Vue.set()方法将响应式属性添加到嵌套的对象上。

  • //这样配置的属性,不是响应式的,Vue无法探测普通的新增property :isEdit
    this.todo.isEdit=true
    

(3)点击编辑后,input编辑框自动获取焦点。

  • 获取焦点:xxx.focus()【xxxDOM元素获取焦点】【xxxDOM可借用Vue里面的ref属性来获取DOM元素】

  • ref属性:

    1. 被用来给元素或子组件注册引用信息(id的替代者)
    2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
    3. 使用方式:
      1. 打标识:<h1 ref="xxx">.....</h1><School ref="xxx"></School>
      2. 获取:this.$refs.xxx
    • vue也有自带的获取DOM的方法,那就是ref。它不仅可以获取DOM元素还可以获取组件

      1、如果给普通的dom元素使用,引用指向的是dom元素。
      2、如果是给子组件使用,引用指向的是子组件的实例。【ref 加在子组件上,用this.$refs.(ref值) 获取到的是组件实例,可以使用组件的所有方法和属性。】

  • $nextTick:

    • 语法:this.$nextTick( 箭头函数体 )
    • 作用: this.$nextTick这个方法作用是当数据被修改后使用这个方法 回调函数获取更新后的dom再渲染出来【Vue在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新,即不在此轮【1轮】更新,等到下一轮【2轮】更新】。
  • 不要$nextTick这个API行不行?不行。

    • 因为下面这段代码【没有$nextTick】执行到this.$refs.inputTitle.focus()这里时【即点击编辑的时候】,这一轮【1轮】:整个页面模板还未重新解析呢【得先把所有的代码执行完,把需要修改的数据修改完后,再进行模板解析,并展示】,但是这一轮【1轮】执行代码this.$refs.inputTitle.focus()时,页面中的编辑input框在这一轮【1轮】:模板还未解析,又如何能够拿到input框,并聚焦呢?
 //编辑
    handleEdit(){
      // 判断对象this.todo里面是否有isEdit属性
      if(this.todo.hasOwnProperty('isEdit')){
        this.todo.isEdit=true
      }else{
        // 把todo.isEdit设置成响应式数据
        this.$set(this.todo,'isEdit',true)
      }
      this.$refs.inputTitle.focus()
    },

正确的代码示例

<input type="text"
:value="todo.title"
v-show="todo.isEdit"
ref="inputTitle"
>
 //编辑
handleEdit(){
  // 判断对象this.todo里面是否有isEdit属性,并设置成true
  if(this.todo.hasOwnProperty('isEdit')){
     this.todo.isEdit=true
  }else{
     // 把todo.isEdit设置成响应式数据
     this.$set(this.todo,'isEdit',true)
  }
    
  this.$nextTick(()=>{
    this.$refs.inputTitle.focus()
  })
},

也可以放在updated()钩子中

  • updated钩子中的事件执行时,页面和数据已经保持同步了,都是最新的,即这一轮【1轮】已经更新过了,在【2轮】重新再次渲染页面。
 //编辑
handleEdit(){
  // 判断对象this.todo里面是否有isEdit属性,并设置成true
  if(this.todo.hasOwnProperty('isEdit')){
     this.todo.isEdit=true
  }else{
     // 把todo.isEdit设置成响应式数据
     this.$set(this.todo,'isEdit',true)
  }
},
// 也可以放在updated钩子中,
updated() {
this.$refs.inputTitle.focus()
},

展示效果:

在这里插入图片描述

(4)input编辑框失去焦点,更新编辑框里输入的数据,并正确展示出来。

  • @blur="handleBlur(todo,$event)": 失去焦点触发,并调函数handleBlur(),并传给函数两个参数【todo,$event

    • vue中关于$event的通俗理解

      $event是指当前触发的是什么事件(鼠标事件,键盘事件等)【此处的$event:FocusEvent

      $event.target则指的是事件触发的目标,即哪一个元素触发了事件,这将直接获取该dom元素。【此处的$event.target:<input>

TodoItem.vue

<span v-show="!todo.isEdit">{{todo.title}}</span>
<input type="text"
:value="todo.title"
v-show="todo.isEdit"
ref="inputTitle"
@blur="handleBlur(todo,$event)"
>
handleBlur(todo,e){
  // todo.isEdit设置成false,展示<span>里面的数据【<span>里面的v-show为真】
  todo.isEdit = false
  if(!e.target.value.trim()) return alert('输入不能为空!')
   //利用 数据总线通信,触发事件updateTodo,传递两个参数本DOM元素的id,value
  this.$bus.$emit('updateTodo',todo.id,e.target.value)
}
  • e.target.value:拿到触发事件里面的值【此处是input框里面的值】
  • trim() 方法用于删除字符串的头尾空白符。

App.vue

 methods: {
//更新一个todo
    updateTodo(id,title){
        this.todos.forEach((todo)=>{
            if(todo.id === id) todo.title = title
        })
     },  
 }               
mounted() {
      // 利用数据总线去通信,方法写在methods里面
      this.$bus.$on('updateTodo',this.updateTodo)
    },
beforeDestroy() {
   // 解绑事件updateTodo
  this.$bus.$off('updateTodo')
},               

在这里插入图片描述
在这里插入图片描述

完整代码:

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:拿到的是一个字符串,需要解析成一个对象
        //【A||B】:第一个操作数A为true,则不会执行第二个操作B。第一个操作数A为false,则会执行第二个操作B。
        todos:JSON.parse(localStorage.getItem('todos')) ||[],
        // todos为空时,解析出来的对象为null,即todos:null || [],
        // 举例:console.log(null || 3); //3
      }
    },
     // 监视属性todos
      watch: {
      todos:{
        // 深度监视开启
        deep:true,
       //handler什么时候调用?当todos属性发生改变时
       // newValue:该属性变化之后的值
        handler(newValue){
          // newValue:传过来是一个数组对象,需要通过JSON.stringify()转化成一个字符串存储在本地
          localStorage.setItem('todos',JSON.stringify(newValue))
      }
      }
    },
    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
        }
        )
      },
      //更新一个todo
			updateTodo(id,title){
				this.todos.forEach((todo)=>{
					if(todo.id === id) todo.title = title
				})
			},
    },
    mounted() {
      // 利用数据总线去通信
      //勾选or取消勾选一个todo
      this.$bus.$on('checkTodo',(id)=>{
        this.todos.forEach((todo) => {
          if(todo.id === id) todo.done = !todo.done
        })
      }),
      this.$bus.$on('updateTodo',this.updateTodo)
      // 利用消息的订阅与发布去通信
      // 订阅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'])
      this.$bus.$off('updateTodo')
      // 取消订阅
      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-edit{
    /* 字体颜色设置:白色 */
		color: #fff;
		background-color: #4d79b2;
		border: 1px solid #1b57a5;
	}
  /* 鼠标移动到删除按钮时 */
	.btn-edit:hover {
		color: #fff;
		background-color: #1a67ca;
	}

	.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 v-show="!todo.isEdit">{{todo.title}}</span>
      <input type="text"
      :value="todo.title"
      v-show="todo.isEdit"
      ref="inputTitle"
      @blur="handleBlur(todo,$event)"
      >
      <!-- <span v-show="!undefined">答案是多所</span> -->
		</label>
		<button class="btn btn-danger" @click="handleDelete()">删除</button>
    <button class="btn btn-edit" @click="handleEdit()">编辑</button>
	</li>
</template>

<script>
import pubsub from "pubsub-js";
export default {
	name: 'TodoItem',
  // 声明接受从别的组件中的todoObj对象,todo
  props: ['todo'],
  data() {
    return {
      inputValue:''
    }
  },
  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)
      }
    },
     //编辑
    handleEdit(){
      // 判断对象this.todo里面是否有isEdit属性
      if(this.todo.hasOwnProperty('isEdit')){
        this.todo.isEdit=true
      }else{
        // 把todo.isEdit设置成响应式数据
        this.$set(this.todo,'isEdit',true)
      }
      this.$nextTick(()=>{
        this.$refs.inputTitle.focus()
      })
    },
    handleBlur(todo,e){
      // console.log(e)
      // console.log(e.target)
      // todo.isEdit设置成false,展示1的数据
      todo.isEdit = false
      if(!e.target.value.trim()) return alert('输入不能为空!')
      this.$bus.$emit('updateTodo',todo.id,e.target.value)
    }
  },
  // 也可以放在updated钩子中,
  // updated() {
  //   this.$refs.inputTitle.focus()
  // },
 
};
</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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据挖掘——宁县(区、市)农村居民人均可支配收入影响因子分析(论文)

《数据挖掘与分析》课程论文 题目&#xff1a;宁县&#xff08;区、市&#xff09;农村居民人均可支配收入影响因子分析 xx学院xx班&#xff1a;xxx 2022年6月 摘要&#xff1a;农村居民人均可支配收入可能被农作物产量、牲畜存栏、农作物播种数量等诸多因素影响。为此&#…

我的内网渗透-代理转发(1)

概念 网关 必须经过 用来进行路由转发的设备&#xff0c;网关的作用是让不同网段之间能够通信 代理 委托访问 无论代理后面挂了几台设备&#xff0c;都认为是从代理进行访问&#xff0c;对外只表现为代理一台。外部认为是与代理进行…

css小兔鲜项目搭建

目录 精灵图 精灵图的使用步骤 背景图片大小 background连写 文字阴影 盒子阴影 过渡 骨架标签 SEO三大标签 版心的介绍 css书写顺序 项目结构搭建 精灵图 场景&#xff1a;项目中将多张小图片&#xff0c;合并成一张大图片&#xff0c;这张大图片称之为精灵图 优点…

机器人项目创新课题汇总提示

创新课题推荐自己思考并给出&#xff0c;如下案例仅供参考&#xff1a; 不想看&#xff0c;不愿意做&#xff0c;就遵循自己内心想法&#xff0c;做自己喜欢的事情吧。 题目和描述&#xff1a; 自动导航机器人&#xff1a;设计一种能够自主导航的机器人&#xff0c;可以在不需…

pgsql序列的使用

大家都知道pgsql和mysql不同&#xff0c;mysql字段有有自增属性&#xff0c;pgsql并没有&#xff0c;但是pgsql和oracle一样有序列&#xff0c;很多人刚接触pgsql的时候&#xff0c;并不知道序列是什么&#xff0c;怎么用&#xff0c;下面这篇文章就介绍序列&#xff0c;并且怎…

idea如何集成Tomcat

&#xff08;1&#xff09;、这里应该找Add Configuration点击这里&#xff1a;如果没有标志&#xff0c;点击Exit (2)、这里可以配置一个配置项&#xff1a; &#xff08;3&#xff09;、loacl是本地&#xff0c;那个是远程&#xff1a;这里我选择本地 &#xff08;4&#xff…

DJ4-4 NAT、ICMP、IPv6

目录 一、NAT&#xff1a;网络地址转换 1、工作原理 2、NAT 的限制 二、ICMP 1、ICMP 协议 2、ICMP 类型和代码 3、Traceroute 命令 三、IPv6 地址 1、IPv6 的引入 2、IPv6 的表示 一、NAT&#xff1a;网络地址转换 动机&#xff1a;对外部网络来讲&#xff0c;本地…

11-高性能JSON库——fastjson2

目录 1.具体使用 1.1.添加fastjson2依赖 1.2.常用类和方法 1.3.将JSON字符串转换成对象 1.3.1.JSON字符串转换成对象 1.3.2.JSON字符串转换成数组 1.4.将对象转换成JSON字符串 1.4.1.将对象转换成JSON字符串 1.4.2.将数组转换成 JSON 字符串 2.性能测试报告 3.总结 …

Prompt Engineering 面面观

作者&#xff1a;紫气东来 项目地址&#xff1a;https://zhuanlan.zhihu.com/p/632369186 一、概述 提示工程&#xff08;Prompt Engineering&#xff09;&#xff0c;也称为 In-Context Prompting&#xff0c;是指在不更新模型权重的情况下如何与 LLM 交互以引导其行为以获得…

总结905

今日已做&#xff1a; 1.核聚课程 2.进步本回顾&#xff0c;重做8道题&#xff0c;有两道还没掌握&#xff0c;记录3页。 3.线性代数第5讲 4.三大计算&#xff0c;刷题15道&#xff0c;纠错。 5.每日长难句。 6.考研常识课 明日必做 1.熟练背诵《the king’s speech》并默写 2…

字符设备驱动内部实现原理解析

字符设备驱动内部实现原理解析 一. 字符设备驱动对象内部实现原理解析二. 字符设备驱动的注册流程三. 代码示例 一. 字符设备驱动对象内部实现原理解析 用户层&#xff1a; ​ 当用户打开&#xff08;open&#xff09;一个文件时,会生成一个文件描述符表 内核层&#xff1a; 内…

spark 和 flink 的对比

一、设计理念 Spark 的数据模型是 弹性分布式数据集 RDD(Resilient Distributed Dattsets)&#xff0c;这个内存数据结构使得spark可以通过固定内存做大批量计算。初期的 Spark Streaming 是通过将数据流转成批 (micro-batches)&#xff0c;即收集一段时间(time-window)内到达的…

SD/StableDiffusion模型,ai绘画部署教程,谷歌云端零成本部署,支持中文

目录 前言 准备前提 说明 开始搭建 1、第一步&#xff0c;下载ipynb脚本文件 2、第二步&#xff0c;上传一键脚本文件到谷歌云盘 3、选择该.ipynb文件--右键--打开方式--关联更多应用 4、输入框搜索Colaboratory找到该应用&#xff0c;安装 5、安装过程中&#xff0c;…

Linux网络基础

网络基础 认识 "协议"网络协议初识协议分层OSI七层模型TCP/IP五层(或四层)模型 网络传输基本流程网络传输流程图数据包封装和分用 网络中的地址管理认识IP地址认识MAC地址 认识 “协议” “协议” 是一种约定。 举个栗子&#xff0c;你和好友之间提前约好在某个地方…

第九章 形态学图像处理

文章目录 9形态学图像处理9.1预备知识9.2腐蚀与膨胀9.2.1腐蚀9.2.2膨胀9.2.3对偶性 9.3开操作和闭操作9.4击中或击不中变换9.5一些基本形态学方法9.5.1边界提取9.5.2空洞填充9.5.3连通分量的提取9.5.4凸壳9.5.5细化9.5.6粗化 9.6灰度级形态学9.6.3一些基本的形态学算法 9形态学…

kotlin从入门到精通之内置类型

基本类型 声明变量 val&#xff08;value的简写&#xff09;用来声明一个不可变的变量&#xff0c;这种变量在初始赋值之后就再也不能重新赋值&#xff0c;对应Java中的final变量。 var&#xff08;variable的简写&#xff09;用来声明一个可变的变量&#xff0c;这种变量在初始…

C51单片机期末复习第八章单片机接口技术

一 总线&#xff1a; 传送同类信息的连线 三总线&#xff1a; 地址总线AB&#xff0c;数据总线DB,控制总线CB 目录(ppt给的没啥用&#xff0c;乱还不全)&#xff1a; 8.1 单片机的系统总线 8.2 简单并行I/O口扩展 8.3 可编程并行I/O口扩展 8.4 D/A转换与DAC0832应用 8…

衣服面料相关基础

总结自 BiliBili视频&#xff1a;原来衣服的面料还能这么选&#xff0c;几个方法教你买到优质的短袖&#xff0c;再也不怕买衣服踩坑了 面子里子 既不能皱巴巴 又不能不透气 混纺 涤纶 粘纤 氨纶 涤纶 不变性 挺阔感 氨纶 弹性 粘纤 吸水透气40-50% 怕热 真丝与亚麻 …

【python】js逆向基础案例——有道翻译

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 课程亮点: 1、爬虫的基本流程 2、反爬的基本原理 3、nodejs的使用 4、抠代码基本思路 环境介绍: python 3.8 pycharm 2022专业版 >>> 免费使用教程文末名片获取 requests >>> pip install req…

软件设计原则与设计模式

设计中各各原则同时兼有或冲突&#xff0c;不存在包含所有原则的设计 一&#xff1a;单一职责原则又称单一功能原则 核心&#xff1a;解耦和增强内聚性&#xff08;高内聚&#xff0c;低耦合&#xff09; 描述&#xff1a;类被修改的几率很大&#xff0c;因此应该专注于单一的…