Vue 学习总结笔记 (六)

11 篇文章 0 订阅

文章目录

1. render 函数

1.1 为什么正常情况下的写法不能生效?


首先,先说正常情况下,应该是这样操作:

//创建Vue的实例对象
new Vue({
	//指定容器app
	el:"#app",
	template:`<App></App>`,
	components:{
		App
	}
})

但是在Vue脚手架中,它会报错:
在这里插入图片描述

换句话说,导入的Vue文件有问题!其实Vue的js文件有很多版本,只不过我们导入的Vuejs文件是一个精简版(缺少部分功能的Vue)。
在这里插入图片描述

而上面的vue.runtime.esm.js文件,就残缺了模板解析器,没有了模板解析器就没法解析template中的内容了。
在这里插入图片描述

1.2 使用完整版的vue.js来解决没有模板解析器的问题


完整版的vue.js,在第三方库的dist下面。

这样我们就直接导入完整版的vue.js就可以直接运行项目了,也并不会报错。
在这里插入图片描述

这样确实可以解决,但是不会被推荐的!因为我们要用render函数配合vue默认的js文件操作。

1.3 使用render函数来解决没有模板解析器的问题


render函数很关键!它会得到一个参数叫做createElement参数,这个参数是一个专门用来创建元素的函数。

import Vue from 'vue'
// import App from './App.vue'

Vue.config.productionTip = false

new Vue({
	
	el:"#app",
	
	//render函数有一个参数:createElement也是一个函数,作用就是专门用来创建元素的。
    render(createElement){
		console.log(typeof createElement);
		//例如:我们返回一个createElement创建的h1标签
		console.log(createElement('h1','你好啊'));
		return createElement('h1','你好啊');
	}
	
})

换句话说,vue默认导入的vuejs文件是没有模板解析器的,而render中的createElement参数帮他做了这件事情。

然后,将render函数进行简化一下,得到的就是vue开始的那种样式:

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

new Vue({
	
	el:"#app",
	
	//render函数有一个参数:createElement也是一个函数,作用就是专门用来创建元素的。
	//render(createElement){
	// 	console.log(typeof createElement);
	// 	//例如:我们返回一个createElement创建的h1标签
	// 	console.log(createElement('h1','你好啊'));
	// 	return createElement('h1','你好啊');
	//}
	
	//函数式写成箭头函数,一个参数,一个返回值都可以省略括号或中括号。然后将createElement换成h字符就完成最简化版了。
	render:h=>h(App)
	//有人疑惑这里为什么不是'App',因为dom中没有App标签。但是我们上面引入了App变量,这样就可以读取了。
})

Vue的分为两部分一个是核心文件 (什么生命周期等等的), 一个是模板解析器。

模板解析占很大一部分体积(大约三分之一),如果将模板解析器移除,仅仅用render函数操作就非常方便操作。省空间省代码。
在这里插入图片描述

Vue当中默认使用的是vue_runtime.esm.js文件,runtime就是运行时Vue;esm是ES module,就是如果使用ES6语法我们可以用这个包操作。


我们的组件中有template标签,既然我们设置的vuejs文件没有解析器,那么怎么解析这种标签类型的template呢?Vue也给它指定了template标签解析器,这个解析器专门用来解析.vue文件中的template标签。
在这里插入图片描述

总结:
在这里插入图片描述

2. 修改Vue Cli脚手架的默认配置


Vue脚手架的配置文件是有的,只不过隐藏到了别的地方而已。

Vue脚手架隐藏了所有的webpack相关的配置,若想看具体的webpack配置,可以执行:vue inspect > output.js命令。

  • 该命令会将vue脚手架的所有配置文件整合到output.js文件中。

在这里插入图片描述


以下五个部分文件名是不能随便改的,这是这是vue脚手架的硬性要求。
在这里插入图片描述


官方也给出了能够修改vue脚手架配置的相关信息:
在这里插入图片描述

对于这种配置的相关内容,都是先用现查就可以。这么多配置不可能记住的咱们只需要改的时候去官方看看操作和配置就可以了。


关闭语法检查,这个语法检车确实烦人,想关闭也可以配置vue脚手架环境。
在这里插入图片描述
在这里插入图片描述


脚手架文件结构:(感觉不错,就放到这里了)
在这里插入图片描述

3. ref属性(被用来给元素或子组件注册引用信息(id的替代者))


正常我们原生的js获取dom元素使用的getelementbyid方法。

<template>
	<div>
		<h1 v-text="msg" id="title"></h1>
		<button @click="showDOM">点我输出上方的DOM元素</button>
		<School/>
		<School/>
	</div>
</template>

<script>
	import School from "./components/School.vue"
	export default{
		name:'App',
		components:{School},
		data(){
			return {
				msg:"欢迎学习Vue!"
			}
		},
		methods:{
			showDOM(){
				//正常我们打印dom元素使用原生的document.getElementById("title")
				console.log(document.getElementById("title"));
			}
		}
	}
</script>

<style>
</style>

ref属性:

  • 被用来给元素或子组件注册引用信息(id的替代者)。

  • 应用在html标签上获取的是真实dom的元素,应用在组件标签上是组件实例对象。

在这里插入图片描述

4. props 配置项(父传子)

4.1 props 第一种方式:(只接受)


props配置项使用的演示:

<template>
	<div class="school">
		<h1>{{msg}}</h1>
		<h2>学生姓名: {{name}}</h2>
		<h2>学生性别: {{sex}}</h2>
		<h2>学生年龄: {{age}}</h2>
		<button @click="show">按钮</button>
	</div>
</template>

<script>
	export default{
		name:"Student",
		data(){
			return {
				msg:"清华大学的学习",
			}
		},
		props:['name','sex','age'],
		methods:{
			show(){
				console.log(this)
			}
		}
	}
</script>

<style>
	.school{
		background-color: gray;
	}
</style>

这样可以直接在父组件中定义,相关属性的配置:

<template>
	<div>
		<Student name="李四" sex="女" age="18"/>
		<Student name="王五" sex="男" age="20"/>
	</div>
</template>

<script>
	import Student from "./components/Student.vue"
	export default{
		name:'App',
		components:{Student},
	}
</script>

<style>
</style>

如果我们想要在子组件加工一下,会出现下面情况:
在这里插入图片描述

可以做乘法,但是不推荐:
在这里插入图片描述


正常在vue的操作方式,使用v-bind来解决,简写为 ': ’ 号 。

正常情况下,属性里面的值,就是一种字符串形式。

但是,如果给属性加上了v-bind指令,那么这个属性里面的值,就会被作为js表达式来处理。这样也就完美解决了相关操作。

对比一下:
在这里插入图片描述
在这里插入图片描述

4.2 props 第二种方式:(限制类型)


我们还可以限制接受类型:
在这里插入图片描述

4.3 props 第三种方式:(限制类型,限制必要性,指定默认值)


更加完整的写法如下:
在这里插入图片描述

<template>
	<div class="school">
		<h1>{{msg}}</h1>
		<h2>学生姓名: {{name}}</h2>
		<h2>学生性别: {{sex}}</h2>
		<h2>学生年龄: {{age+1}}</h2>
		<button @click="show">按钮</button>
	</div>
</template>

<script>
	export default{
		name:"Student",
		data(){
			return {
				msg:"清华大学的学习",
			}
		},
		methods:{
			show(){
				console.log(this)
			}
		},
		
		//props:['name','age','sex'] // 简单声明接受
		
		//接受的同时对属性进行类型限制
		/* props:{
			//使用这种方式来限制类型
			name:String,
			age:Number,
			sex:String
			}
		*/ 
		
		//接受的同时对数据:进行类型限制+默认值的指定+必要性的限制
		props:{
			name:{
				type:String, //name的类型是字符串
				required:true, // 名字是必须要传入的
			},
			age:{
				type:Number,
				default:99, //设置默认值99
			},
			sex:{
				type:String,
				required:true,
			}
		}
	}
</script>

<style>
	.school{
		background-color: gray;
	}
</style>

在这里插入图片描述


vue的指定是不要修改props配置项中的属性:
在这里插入图片描述
在这里插入图片描述


但是如果想要修改props配置项的内容,有需求要求这么做!我们可以通过一个data配置项中的属性来间接操作就好了。

<template>
	<div class="school">
		<h1>{{msg}}</h1>
		<h2>学生姓名: {{name}}</h2>
		<h2>学生性别: {{sex}}</h2>
		<h2>学生年龄: {{myAge}}</h2>
		<button @click="updateAge">修改学生年龄</button>
	</div>
</template>

<script>
	export default{
		name:"Student",
		data(){
			return {
				msg:"清华大学的学习",
				//通过加一个myAge来达到修改页面属性的效果。
				myAge:this.age
			}
		},
		methods:{
			updateAge(){
				this.myAge = 99
			}
		},
		
		//props:['name','age','sex'] // 简单声明接受
		
		//接受的同时对属性进行类型限制
		/* props:{
			//使用这种方式来限制类型
			name:String,
			age:Number,
			sex:String
			}
		*/ 
		
		//接受的同时对数据:进行类型限制+默认值的指定+必要性的限制
		props:{
			name:{
				type:String, //name的类型是字符串
				required:true, // 名字是必须要传入的
			},
			age:{
				type:Number,
				default:99, //设置默认值99
			},
			sex:{
				type:String,
				required:true,
			}
		},
		
	}
</script>

<style>
	.school{
		background-color: gray;
	}
</style>

注意事项:
在这里插入图片描述

5.mixin混入(混合) mixins配置项

5.1 组件中的mixins配置项(局部混入)


mixin混入的作用:可以把多个组件共用的配置提取成一个混入对象处理。

mixin的效果就是如下图:
在这里插入图片描述

在外部创建一个js文件:

//分别暴露一下
export const mixin = {
	methods:{
		showName(){
			alert(this.name)
		}
	},
	mounted(){
		console.log("我是外部js的mounted")
	}
}

export const mixin2 ={
	data(){
		return {
			x:100,
			y:200
		}
	}
}

之后,由mixins配置项引入:

<template>
	<div class="school">
		<h2 @click="showName">学生姓名: {{name}}</h2>
		<h2>学生性别: {{sex}}</h2>
	</div>
</template>

<script>
	//引入一个minin.js文件的minin(分别暴露)
	import {mixin,mixin2} from '../mixin.js'
	export default{
		name:"Student",
		data(){
			return {
				name:"张三",
				sex:"男"
			}
		},
		mixins:[mixin,mixin2],
		mounted(){
			console.log("我是组件的mounted")
		}
		
	}
</script>

<style>
	.school{
		background-color: gray;
	}
</style>

</script>

<style>
	.school{
		background-color: gray;
	}
</style>

注意:

  • 如果设定data中的内容,是以组件中的data数据为主,没有就以mixin文件的内容引入。
  • 如果是像mounted这样的钩子函数,会将组件中和外部js文件中的狗子函数整合到一起使用!(顺序是外部js先执行,之后是组件。)
    在这里插入图片描述

5.2 在main.js全局配置(全局混入)


全局混合是直接在main.js中进行配置:直接通过Vue.mixin(xxx)来全局配置了。

import Vue from "vue"
import App from "./App.vue"
import {mixin,mixin2} from "./mixin.js"

Vue.config.productionTip = false;
Vue.mixin(mixin)
Vue.mixin(mixin2)

new Vue({
	el:'#app',
	render:h=>h(App)
})

在这里插入图片描述

6. Vue的 插件

6.1 引入插件 和 应用插件


vue插件的作用:增强Vue。

实际上,vue插件就是一个包含install方法的一个对象,install方法的第一个参数是Vue构造函数,第二个以后的参数是插件使用者传递的数。

再简单的说就是,vue的插件是从外部js文件引入,并且这个插件要有一个install函数方法。

Vue想要使用该插件只需操作两部分:

  • 1.引入插件:在mian.js文件中,导入该js外部文件。
  • 2.应用插件:使用Vue.use(js外部文件),来应用插件。

例如定义一个plugins.js插件文件:

export default {
	//install函数式有参数的,并且这个参数就是Vue实例对象的创造者,Vue的构造函数。
	install(Vue){
		console.log("参数:",Vue)
	}
}

在main.js中引入插件并且应用插件:

import Vue from "vue"
import App from "./App.vue"

Vue.config.productionTip = false;

//引入插件
import plugins from './plugins.js'

//应用插件
Vue.use(plugins)

new Vue({
	el:'#app',
	render:h=>h(App)
})

6.2 插件的作用(使用案例)


主要平时设置全局配置,甚至修改Vue原型的属性或添加方法都可以使用插件来做到。

并且,我们在组件中,只需要调用对应全局配置的函数就可以了。

在这里插入图片描述


给install传递参数效果如下:
在这里插入图片描述

7. scoped样式


组件之间样式的问题!

两个组件的样式,比如样式类选择器的名字相同,那么会出现一个覆盖的效果。

由于Vue把样式放到一起,那么一个组件就会覆盖另一个组件的样式!至于谁覆盖谁这和导入组件的顺序有关!
在这里插入图片描述


对于上面的问题就需要使用scoped(英文翻译:局部的)属性:

  • scoped的作用:让样式在局部生效,防止冲突。
  • scoped属性的作用就是当前style的只能作用于当前组件。这样就解决了上面的问题。
    在这里插入图片描述
    (注意:app.vue不要使用scoped,因为app.vue是所有组件的父组件,它定义样式一般是类似全局样式的效果!!)

8. style标签的lang属性


lang属性就是language,对于样式有很多语言,一般使用css,还有less等等,默认也是css。

我们可以在style的lang属性声明当前的样式使用什么语言来编译的。

在这里插入图片描述


对于less解析器,是需要安装的:

npm view less-loader versions命令

npm view webpack versions命令

npm i less-loader@7 命令(安装7版本的less-loader)

像什么less都有严格的版本对应webpack的版本的!!!因此不能随便安装的!

9. 组件化编码流程(通用)

9.1 组件编码的通用流程


分析结构的话,大体就像下面的方式:一层一层的分析。

  • 尤其下方的item位置的组件,可以是重复多次因为是相同结构(熟知这种方式)。
    在这里插入图片描述
    组件化编码流程(通用)
  • 1.实现静态组件:抽取组件,使用组件是实现静态页面效果(就是先写出架构,不考虑指令方法等等)。
  • 2.展示动态数据:数据类型,名称是什么?数据保存在哪个组件当中。
  • 3.交互:从绑定事件监听开始。

9.2 正确的查分一个html和css的结构样式分给组件


组件起名字的问题:
在这里插入图片描述

对于一个整体页面,给他拆分为数组,是非常容易的。

  • 对每一部分进行分析,一般就是头部,中间部分,尾部。(一般中间部分中也会包含一些组件)。
  • 对于每一个部分组件的样式,都拆分好,哪些部分是通用的(放到App.vue中),哪些是自己组件用的(使用scoped)。

9.3 对于动态数据(变化的数据)的操作


在这里插入图片描述

对于这些动态数据存储的类型,名称等等,一般我们通过数组或对象的形式存储。

  • 最常用的就是数组中存取这对象。例如:
    在这里插入图片描述

9.4 NanoID的用法


NanoID的作用和uuid一样,生成唯一字符串。在javascript中,我们可以使用NanoID来生成唯一的id对象。

nodejs中安装NanoID,执行npm -i nanoid。之后在import {nanoid} from ‘nanoid’(分别暴露)就可以使用了。

在这里插入图片描述

9.5 子传父的传值


想要子组件向父组件传递值,就可以在父组件中创建一个函数,将该函数传给子组件(子组件拿到就出现在了vuecomponent上面)。此时的函数依然在父组件中,当在子组件调用该组件传递值时,函数就会在父组件收到。

  • 简而言之:通过父组件给子组件传递函数类型的props实现:子给父传递数据。
    在这里插入图片描述

9.6 兄弟组件的传值


最初级的兄弟传值,就是通过父组件来传值。
在这里插入图片描述


注意事项:通过父组件传值的各个method,computed等等都不能重名,因为会冲突!如一下错误:
在这里插入图片描述

9.7 对于props配置项修改的注意事项


vue中要求是不能修改props配置项的东西,但是对于配置项中的对象而言,不能修改对象本身,可以修改对象中的属性!这是一个误区!
在这里插入图片描述

9.8 confirm() 方法的使用


Window.confirm() 方法显示一个具有一个可选消息和两个按钮(确定和取消)的模态对话框 。
在这里插入图片描述

9.9 谷歌浏览器的隐藏


在这里插入图片描述

9.10 Array.prototype.reduce()的使用


reduce() 方法对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
在这里插入图片描述

10. 初级案例演示


在这里插入图片描述

MyFooter.vue文件:

<template>
	<div class="todo-footer" v-show="total">
		<label>
			<input type="checkbox" :checked="isAll" @change="checkAll"/>
		</label>
		<span>
			<span>已经完成{{doneTotal}} / 全部:{{total}}</span>
		</span>
		<button class="btn btn-danger" @click="clearAll">清除已完成任务</button>
	</div>
</template>

<script>
export default {
	name:"MyFooter",
	props:['todoList','checkAllTodoObj','clearAllTodoObj'],
	computed:{
		total(){
			return this.todoList.length
		},
		doneTotal(){
			//reduce的使用:
			//第一个参数是函数,当前todoList的数组长度为多少,就调用多少次。
			//第二个参数是开始的时候的pre的起始值。
			const x = this.todoList.reduce((pre,current)=>{
				//这里的pre参数是上一次执行的返回W值。起始索引是0。
				// console.log('pre参数:',pre)
				//这里的current参数是这次执行的对象。
				// console.log('current参数:',current)
				return pre + (current.done ? 1:0)
			},0)
			
			// console.log("reduce的最终返回:",x)
			return x;
		},
		isAll(){
			return this.doneTotal == this.total && this.total > 0
		}
	},
	methods:{
		checkAll(e){
			// console.log(e.target.checked)
			this.checkAllTodoObj(e.target.checked)
		},
		clearAll(){
			if(confirm("确定清除全部任务吗?"))
				this.clearAllTodoObj()
		}
	}
}
</script>

<style scoped>
	.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>

MyHeader.vue文件:

<template>
	<div class="todo-header">
		<input type="text" placeholder="请输入你的任务名称,按回车确认" @keyup.enter="add">
	</div>
</template>

<script>
	import {nanoid} from 'nanoid'
	export default {
		name:"MyHeader",
		methods:{
			add(e){
				//判断是否为空
				if(!e.target.value.trim())
					return alert('输入不能为空!')
					
				//获取用户输入信息
				console.log(e.target.value)
				
				//包装用户信息,id使用Nanoid来操作
				const todoObj = {
					id:nanoid(),
					title:e.target.value,
					done:false
				}
				
				//当前vc拿到receive方法,直接传值就可以了。
				this.receive(todoObj)
				e.target.value = ''
			}
		},
		props:['receive']
	}
</script>

<style scoped>
	.todo-header input {
		width: 560px;
		height: 28px;
		font-size: 14px;
		border: 1px solid #ccc;
		border-radius: 4px;
		padding: 4px 7px;
	}
	.todo-header input:focus {
		outline: none;
		border-color: rgba(82,168,236,0.8);
		box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
	}
</style>

MyItem.vue文件:

<template>
	<li>
		<label>
			<!-- 
				checked勾选该checkbox。
				想要下面的props元素控制checkbox,就可以使用:来使其成为js表达式。这样我们就可以通过js表达式
				来操作了。这里的itemPro我定义为了{id:'001',title:'吃饭',done:true}的结构。
				
				@click和@change都可以操作事件方面的东西。
			-->
			<input type="checkbox" :checked="itemPro.done" @click="handleCheck(itemPro.id)"/>
			<span>{{itemPro.title}}</span>
		</label>
		<button class="btn btn-danger" @click="handleDelete(itemPro.id)">删除</button>
	</li>
</template>

<script>
export default {
	name:"MyItem",
	//声明接受todo对象
	props:['itemPro','checkTodoObj','deleteTodoObj'],
	mounted(){
		// console.log(this.itemPro);
	},
	methods:{
		//勾选or取消
		handleCheck(id){
			//通知App组件将对应的itemPro对象的done值取反
			this.checkTodoObj(id)
		},
		//删除
		handleDelete(id){
			//根据用户
			if(confirm('确定删除吗?')){
				this.deleteTodoObj(id)
			}
		}
	}
}
</script>

<style scoped>
	li{
		list-style: none;
		height: 36px;
		line-height: 36px;
		padding: 0 5px;
		border-bottom: 1px solid #ddd;
	}
	li label {
		float: left;
		cursor: pointer;
	}
	li label li input {
		vertical-align: middle;
		margin-right: 6px;
		position: relative;
		top: -1px;
	}
	li button{
		float: right;
		display: none;
		margin-top: 3px;
	}
	li:before{
		content: initial;
	}
	li:last-child{
		border-bottom: none;
	}
	li:hover{
		background-color: #ddd;
	}
	li:hover button{
		display: block;
	}
</style>

MyList.vue文件:

<template>
	<ul class="todo-main">
		<!-- 使用props来传递值,父传子 -->
		<Item1 
			v-for="todoObj in todoList" 
			:key="todoObj.id" 
			:itemPro="todoObj" 
			:checkTodoObj="checkTodoObj"
			:deleteTodoObj="deleteTodoObj"
		></Item1>
	</ul>
</template>

<script>
	import Item1 from './MyItem.vue'
	export default {
		name:"MyList",
		components:{Item1},
		props:['todoList','checkTodoObj','deleteTodoObj']
	}
</script>

<style scoped>
	.todo-main{
		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>

App.vue文件:

<template>
	<div id="root">
		<div class="todo-container">
			<div class="todo-wrap">
				<Header1 :receive="receive"></Header1>
				<List1 
					:todoList="todoList" 
					:checkTodoObj="checkTodoObj"
					:deleteTodoObj="deleteTodoObj"
				></List1>
				<Footer1 :todoList="todoList" :checkAllTodoObj="checkAllTodoObj" :clearAllTodoObj="clearAllTodoObj"></Footer1>
			</div>
		</div>
	</div>
</template>

<script>
	import Header1 from "./components/MyHeader.vue"
	import Footer1 from "./components/MyFooter.vue"
	import List1 from "./components/MyList.vue"
	
	export default{
		name:'App',
		components:{
			Header1,
			List1,
			Footer1,
		},
		data(){
			return {
				todoList:[
					{id:'001',title:'吃饭',done:true},
					{id:'002',title:'睡觉',done:false},
					{id:'003',title:'敲代码',done:true},
				]
			}
		},
		methods:{
			//从MyHeader中获取数据,添加todoObj对象
			receive(todoObj){
				//这样将值传给添加到todoList末尾中。
				this.todoList.unshift(todoObj);
			},
			//勾选或者取消勾选一个todo
			checkTodoObj(id){
				this.todoList.forEach((todoObj)=>{
					if(todoObj.id == id)
						todoObj.done = !todoObj.done
				})
			},
			//删除一个TodoObj
			deleteTodoObj(id){
				//注意:过滤出来的是一个新数组,并不是改变了data中的todoList。
				//因此,要重新赋值一下。
				// console.log(id)
				this.todoList = this.todoList.filter((todoObj)=>{
					return todoObj.id !== id
				})
			},
			//全选or取消全选
			checkAllTodoObj(done){
				this.todoList.forEach((todo)=>{
					todo.done = done
				})
			},
			//清除所有已经完成的todoObj
			clearAllTodoObj(){
				this.todoList = this.todoList.filter((todo)=>{
					return !todo.done
				})
			}
		}
	}
</script>

<style>
	body{
		background-color: #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;
		margin: 0 auto;
	}
	.todo-container .todo-wrap {
		padding: 10px;
		border: 1px solid #ddd;
		border-radius: 5px;
	}
</style>

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值