二、Vue常用操作

Vue常用操作

Vue常用操作: https://cn.vuejs.org/v2/api/
对Vue2的掌握,我们主要从 vue基础指令、过滤器、监听器、计算属性、全局组件、父子组件、组件注册、组件之间通信、自定义事件、插槽、路由、过渡动画、vue生命周期 开始着手。

一、Vue指令

  • 内容渲染指令

      内容渲染指令用来辅助开发者渲染DOM元素的文本内容,常用的内容渲染指令有: v-text、{{}}、v-html、v-once、v-pre、v-clock。
      v-text:向页面注入文本,相当于innerText。v-html:向页面注入元素,相当于innerHTML。v-once:只渲染元素和组件一次,v-pre:用于跳过这个元素和它子元素的编译过程,标签内怎么编写页面就展示什么。v-clock:在某些情况下(例如网络延迟等),我们浏览器可能会直接显示出未编译的插值运算符,也就是一闪而过看到{{}}这些双括号的模板,我们可以采用该命令。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
		
		<style>
			[v-clock] {
				display: none;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<!-- v-tetx相当于innerText,把username 对应的值渲染到第一个p标签中 -->
			<p v-text="username">姓名</p>
			
			<!-- {{}}插值运算把gender对应的值渲染第二个p标签中-->
			<p>性别:{{gender}}</p>
			
			<!-- v-html相当于innerHTML,把包含HTML标签的字符串渲染到页面上-->
			<p v-html="hobby">爱好</p>
			
			<hr />
			<!-- v-once元素和组件只会被渲染一次 -->
			<p v-once>原始值:{{msg}}</p>
			<p>后面值:{{msg}}</p>
			<input type="text" v-model="msg" />
			
			<!-- v-pre跳过元素和子元素的编译过程,原始展示 -->
			<p v-pre>{{msg}}}</p>
			
			<!-- 解决因为网络延迟导致的插值运算值还没有及时渲染时情况 -->
			<p v-clock>{{msg}}</p>
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
					username:'张三',
					gender:'男',
					hobby:'<font color="red">王者荣耀</font>',
					msg:'这是一条测试消息'
				}
			});
		</script>
	</body>
</html>
测试结果:
内容渲染指令使用

  • 属性绑定指令

   v-bind动态地绑定一个或多个特性。给一个标签动态绑定一个属性、样式、一些类,或者将一个对象绑定到一个标签上。鉴于v-bind使用较多,官方推荐使用简写 :属性

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
		<style>
			.active {
				background-color: orange;
			}
			.fontActive {
				font-size: 20px;
			}
		</style>
	</head>
	<body>
		<div id="app">
			<!-- 绑定一个属性 ,v-bind可以简写-->
			<img v-bind:src="imgSrc" height="100" width="100" />
			<img :src="imgSrc" height="100" width="100"/>
			<!-- 绑定一个样式 -->
			<p :style='{color:fontColor}'>我爱Vue</p>
			<!-- 绑定一个类 -->
			<p v-for="(course,index) in courses" :class='index==acticeIndex?"active":""'>
				{{course}}
			</p>
			<p :class=['active',{'fontActive':bool}]>多个样式</p>
			<!-- 绑定一个有属性的对象-->
			<p v-bind="{id:1,name:'mytext'}">绑定有属性的对象</p>
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
					//绑定属性
					imgSrc:'img/1.jpeg',
					//绑定样式
					fontColor:'red',
					bool:true,
					//绑定class
					courses:['html','css','javascript'],
					acticeIndex:2
				}
			});
		</script>
	</body>
</html>
测试结果:
v-bind指令使用




补充:vue指令中可以使用JavaScript表达式: 在 vue 提供的模板渲染语法中,除了支持绑定简单的数据值之外,还支持 Javascript 表达式的运算,例如

  • 事件绑定指令

    vue 提供了 v-on 事件绑定指令,用来辅助程序员为 DOM 元素绑定事件监听。v-on针对事件,动态绑定事件。表示形式有v-on:事件=“事件函数”或者简写@事件=“事件函数”,通过v-on绑定的事件处理函数,需要在methods节点中声明。原生DOM对象有onclikc、oninput、onkeyup等原生时间,vue相应替换分别为:v-on:click、v-on:input、v-on:keyup。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
		<style>
			.active {
				background-color: orange;
			}
			.fontActive {
				font-size: 20px;
			}
		</style>
	</head>
	<body>
		<div id="app">
 			<h3>count的值为: {{count}}</h3>
 			
 			<!-- "v-on:事件"完整写法 -->
 			<button v-on:click="addCount">+1</button>
 			
 			<!-- "v-on:事件"简写形式,把v-on:简写为 @符号 -->
 			<!-- 如果事件处理函数中的代码足够简单,只有一行代码,则可以简写到行内 -->
 			<button @click="count+=1">+1</button>
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
					count:0
				},
				methods:{
					addCount(){
						this.count+=1;
					}
				}
			});
		</script>
	</body>
</html>
测试结果:

  1.绑定事件并传参

   在使用v-on指令绑定事件时,可以使用()进行传参,示例如下:
绑定事件并传参

   2.$event

    $event是vue提供的特殊变量,用来表示原生的事件参数对象event。$event可以解决事件参数对象event被覆盖的问题,示例如 下:

$event使用

   3.事件修饰符

   在事件处理函数中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。因此,vue 提供了事件修饰符的概念,来辅助程序员更方便的对事件的触发进行控制。常用的 5 个事件修饰符如下:
事件修饰符说明
.prevent阻止默认行为(例如:阻止a链接的跳转、阻止表单的提交等)
.stop阻止事件冒泡
.capture以捕获模式触发当前的事件处理函数
.once绑定的事件只能触发一次
.self只有在event.target 是当前元素自身时触发事件处理函数

   4.按键修饰符

在监听键盘事件时,我们经常需要判断详细的按键。此时,可以为键盘相关的事件添加按键修饰符,例如:


  • 双向绑定指令

   vue 提供了 v-model 双向数据绑定指令,用来辅助开发者在不操作 DOM 的前提下,快速获取表单的数据。
为了方便对用户输入的内容进行处理,vue 为 v-model 指令提供了 3 个修饰符,分别是:
事件修饰符 说明示例
.number 自动将用户的输入值转为数值类型<input v-model.number="age" />
.trim 自动过滤用户输入的首尾空白字符<input v-model.trim="msg" />
.lazy 在“change”时而非“input”时更新<input v-model.lazy="msg" />

  • 条件渲染指令

   条件渲染指令用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:v-if(v-else-if、v-else)、v-show。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<div v-show="score<60">差</div>
			<div v-show="score>=60&&score<90">良</div>
			<div v-show="score>=90">优秀</div>
			
			<!-- v-if、v-else-if、v-else相当于if、else if、else,只会展示符合条件的元素,其他元素均移除 -->
			<div v-if="score<60">差</div>
			<div v-else-if="score>=60&&score<90">良</div>
			<div v-else>优秀</div>
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
					score:80
				}
			});
		</script>
	</body>
</html>
测试结果:
v-if和v-show区别
v-if 和 v-show 的区别:
实现原理不同:
⚫ v-if 指令会动态地创建或移除 DOM 元素,从而控制元素在页面上的显示与隐藏;
⚫ v-show 指令会动态为元素添加或移除 style="display: none;" 样式,从而控制元素的显示与隐藏;
性能消耗不同:
v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此:
⚫ 如果需要非常频繁地切换,则使用 v-show 较好
⚫ 如果在运行时条件很少改变,则使用 v-if 较好

  • 列表渲染指令

   v-for基于数据源多次渲染元素或者模板块,也可以为数组索引指定别名(或者用于创建对象的键)。v-for 指令还支持一个可选的第二个参数,即当前项的索引。语法格式为 (item, index) in items。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<!--遍历数组-->
			<p v-for="(score,index) in scores">{{index +':'+score}}</p>
			
			<!-- 遍历对象数组 -->
				<table border="1" align="center" width="300">
					<thead style="background-color: orange;">
						<tr align="center">
							<td>姓名</td>
							<td>年龄</td>
							<td>性别</td>
						</tr>
					</thead>
					<tbody>
						<tr v-for="p in persons" align="center">
							<td>{{p.name}}</td>
							<td>{{p.age}}</td>
							<td>{{p.sex}}</td>
						</tr>
					</tbody>
			</table>
			<!-- 对字符串进行遍历 -->
			<p v-for ="str in hobby">
				{{str}}
			</p> 
		</div>
		
		<script>
			const vm = new Vue({
				el: '#app',
				data: {
					scores: [100, 90, 80, 70],
					persons: [
						{ name: '张三', age: 23, sex: '男' },
						{ name: '李四', age: 24, sex: '女' },
						{ name: '王五', age: 25, sex: '男' },
						{ name: '赵六', age: 26, sex: '女' },
					],
					hobby:'篮球'
				}
			});
		</script>
	</body>
</html>
测试结果:
v-for指令使用
使用 key 维护列表的状态
当列表的数据变化时,默认情况下,vue 会尽可能的复用已存在的 DOM 元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。
为了给 vue 一个提示,以便它能跟踪每个节点的身份,从而在保证有状态的列表被正确更新的前提下,提升渲染的性能。此时,需要为每项提供一个唯一的 key 属性:
key 的注意事项
①key 的值只能是字符串或数字类型
②key 的值必须具有唯一性(即:key 的值不能重复)
③建议把数据项 id 属性的值作为 key 的值(因为 id 属性的值具有唯一性)
④使用 index 的值当作 key 的值没有任何意义(因为 index 的值不具有唯一性)
⑤建议使用 v-for 指令时一定要指定 key 的值(既提升性能、又防止列表状态紊乱)

二、过滤器

   过滤器(Filters)是 vue 为开发者提供的功能,常用于文本的格式化。过滤器可以用在两个地方:插值表达式和 v-bind 属性绑定。在创建 vue 实例期间,可以在 filters 节点中定义过滤 器。
   过滤器分为:私有过滤器(在filters节点下定义的过滤器,只能在当前vm实例所控制的el区域内使用)和全局过滤器(全局过滤器可以在多vue实例之间共享过滤器)。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 私有过滤器使用 -->
			<p>{{sex | sexFormatter}}</p>
			
			<!-- 全局过滤器使用 -->
			<p>{{str | capitalize}}</p>
			
			<!-- 连续调用多个过滤器 -->
			<p>{{message | filterA | filterB}}</p>
			
			<!-- 过滤器传参 -->
			<p>{{message | maxLength(5)}}</p>
		</div>
		<script>
			//全局过滤器 -独立于每个vm实例之外,必须定义在vm实例之前
			//Vue.filter()方法接受两个参数:
			//第一个参数,是全局过滤器的"名字"
			//第二个参数,是全局过滤器的"处理函数"
			Vue.filter('capitalize',function(value){
				return value.toUpperCase().split('').reverse().join('');
			});
			
			//全局过滤器 - 控制文本的最大长度
			Vue.filter('maxLength',function(str,len = 4){
				if(str.length<=len) return str;
				return str.slice(0,len)+'...';
			});
			
			const vm = new Vue({
				el:'#app',
				data:{
					sex:0,
					str: 'abc',
					message:'chensheng'
				},
				filters:{	//局部过滤器
					sexFormatter(sex){
						if(sex==0){
							return "男";
						}else{
							return "女";
						}
					},
					filterA(value){	//将首字母大写
						return value.charAt(0).toUpperCase()+value.slice(1);
					},
					filterB(value){	//将字符串反转
						return value.split('').reverse().join('');
					}
				}
			});
		</script>
	</body>
</html>
测试结果:
过滤器使用

三、监听器

   如果我们需要监听某个值的变化,当这个值变化是,进行一些操作,可以使用监听器。监听器的属性名称是watch,和data平级。监听器中的数据是方法,接收两个参数,分别为改变后的值和改变前的值。如果想让wath侦听器立即被调用,则需要使用immediate选项。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			firstName:<input type="text" v-model="firstName" />
			lastName:<input type="text" v-model="lastName" />
			<h2>{{fullName}}</h2>
			person:<input type="text" v-model="person.username" />
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
					firstName:'',
					lastName:'',
					fullName:'',
					person:{username:'admin'}
				},
				watch:{
					firstName(newVal,oldVal){
						//在vue中,操作data、method必须使用this
						this.fullName = this.firstName + this.lastName;
					},
					lastName(newVal,oldVal){
						this.fullName = this.firstName + this.lastName;
					},
					person:{             //监听对象内属性变化,handler是固定写法,当username值变化时,自动调用handler处理函数
						handler(newVal){
							console.info('如果监听对象内属性变化,则使用这种方式'+newVal.username);
						},
					    deep: true,		 //如果watch侦听的是一个对象,如果对象中的属性值发生了变化,则无法被监听到,需要使用deep选项才能侦听
						immediate:true   //表示页面初次渲染好之后,就立即触发当前的watch侦听器
					},
					'person.username':{
						handler(newVal){
							console.info('如果只想监听对象单个属性变化,则使用这种方式'+newVal)
						}
					}
				}
			});
		</script>
	</body>
</html>
测试结果:

watch监听器使用

四、计算属性

计算属性指的是通过一系列运算之后,最终得到一个属性值。这个动态计算出来的属性值可以被模板结构或 methods 方法使用。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<p @click='show()'>计算属性: {{reverseMsg}}</p>
		</div>
		
		<script>
			const vm = new Vue({
				el:'#app',
				data:{
				   msg: 'hello world'
				},
				computed: {
					//计算属性的getter
					reverseMsg: function() {
						//this指向vm实例
						return this.msg.split('').reverse().join('');
					}
				},
				methods:{
					show(){
						console.info(this.reverseMsg);  //在methods中调用属性
					}
				}
			});
		</script>
	</body>
</html>
测试结果:
计算属性使用

计算属性和method区别?

  •    当页面重新渲染(不是刷新)的时候,计算属性不会变化,直接读取缓存使用,适合较大量的计算和改变频率较低的属性;而method就是当页面重新渲染的时候(页面元素的data变化,页面就会重新渲染),都会重新调用method。
  •    计算属性是一个属性,而不是方法。虽然写法是方法,但是我们使用的时候是直接视为一个属性去操作的,使用方式和data一致。
  •    计算属性中使用到的data中的数据只要发生了变化,计算属性就会重新计算。如果两次获取计算属性的时候,里面使用到的属性没有发生变化,计算属性会直接使用之前缓存的值。

注意点:

  •    计算属性。在computed中,可以定义一些属性,这些属性叫做计算属性,他本质上就是一个方法,但是,我们使用的时候是当做属性来使用。计算属性使用的过程中,一定不要加(),它就是一个属性,和data里的属性用法一样。
  •    只要极速暗属性中所用到的data中的属性发生了变化,就会立即去重新计算属性的值。
  •    计算属性的结果会被缓存起来,方便下次调用,如果计算属性中用到的data都没有变化,就不会重新求值。
  •   在计算属性中,无论如何都需要return一个值,用来代表这个属性的值。

计算属性和监听器的区别:

  • Computed用法视为一个属性,并且结果会被缓存。
  • Methods表示方法,表示一个具体的操作,主要用来写业务逻辑
  • Watch是一个对象,key是需要监听的表达式,value是对应的回调函数,主要用来监听某些数据的变化,从而执行某些具体的业务逻辑。可以看做是计算属性和methods的结合体。

五、全局组件

组件是可复用的Vue实例,且带一个名字,可以复用。我们搭建的页面其实是一个个组件组装而成,可以分为局部组件和全局组件。

  • 局部组件:只属于当前Vue的实例,其他实例无法共享这个局部组件。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<my-date></my-date>
		</div>
		
		<script>
			//1、创建组件构造器
			let partialTemplate = Vue.extend({
				template:`
							<div>
								<input type='date'/>
								<p>今天天气好晴朗!</p>
							</div>
						`
			});
			const vm = new Vue({
				el: '#app',
				// 注册局部组件,只属于当前的vue实例
				components:{
					'my-date':partialTemplate
				}
			});
		</script>
	</body>
</html>

局部组件简洁写法:
			const vm = new Vue({
				el: '#app',
				// 注册局部组件,只属于当前的vue实例
				components:{
					'my-date':{
						template:`
							<div>
								<input type='date'/>
								<p>今天天气好晴朗!</p>
							</div>
							`
					}
				}
			});

测试结果:

vue注册局部组件

  • 全局组件:属于所有的Vue实例所有。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<my-date></my-date>
		</div>
		
		<script>
			//1. 创建组件构造器
			let ProFile = Vue.extend({
				//1.1 模板选项
				template:`
					<div>
						<input type="date"/>
						<p>今天天气好晴朗!</p>
					</div>
				`
			});

			//2. 注册全局组件,参数1自定义组件名称,参数2组件
			Vue.component('my-date',ProFile);
			
			const vm = new Vue({
				el: '#app'
			});
		</script>
	</body>
</html>
测试结果同上!

六、父子组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<parent></parent>
		</div>
		<script>
			// 1. 子组件构造器
			let Child1 = Vue.extend({
				template: `<img src="img/estar.ico" width="200">`
			});

			let Child2 = Vue.extend({
				template: `<p>孤独的星星!</p>`
			});

			// 2. 父组件构造器
			Vue.component('parent', {
				components: { 			  //注册子组件
					'my-child1': Child1,
					'my-child2': Child2
				},
				template: `               //组装父组件
                  <div>
                      <my-child1></my-child1>
                      <my-child2></my-child2>
                  </div>
                `
			});

			new Vue({
				el: '#app'
			});
		</script>
	</body>
</html>
测试结果:
父子组件
  • template标签和script标签注册组件
	一、使用template来注册组件【常用】
                <body>
                    <div id="app">
                        <!-- 使用父组件 -->
                        <my-div></my-div>
                    </div>
                    <template id="parent">
                        <!-- 只能有一个出口,最外层必须有标签包裹 -->
                        <div>
                            <img src="img/estar.ico" width="200">
                            <p>孤独的星星!</p>
                        </div>
                    </template>
                    <script>
                        //实例化组件
                        Vue.component('my-div', {
                            template: '#parent'
                        });

                        new Vue({
                            el: '#app'
                        });
                    </script>
                </body>
 	二、使用script来注册组件,必须声明类型type=”text/template” 【不推荐使用】
                <body>
                    <div id="app">
                        <!-- 使用父组件 -->
                        <my-div></my-div>
                    </div>
                    <script type="text/template" id="parent">
                        <!-- 只能有一个出口,最外层必须有标签包裹 -->
                        <div>
                            <img src="img/estar.ico" width="200">
                            <p>孤独的星星!</p>
                        </div>
                    </script>
                    <script>
                        //实例化组件
                        Vue.component('my-div', {
                            template: '#parent'
                        });

                        new Vue({
                            el: '#app'
                        });
                    </script>
            	</body>
  • 组件中data使用
下述在组件中直接调用data中的数据会报错,如下所示:
 为什么组件的data必须是一个方法?
  首先,如果不是一个方法,Vue直接会报错。其次,原因在于Vue让每一个组件对象都返回一个新的对象,如果是同一个对象的,组件会在多次使用后相互影响。如果我们不写成方法返回对象的话,那么就是所有组件公用一个data。

u  我们将data定义成函数,这样每个按钮点击后都会产生自己独享的变量,而不是共享的变量。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>

	<body>
		<div id="app">
			<!-- 使用组件 -->
			<my-btn></my-btn>
			<my-btn></my-btn>
			<my-btn></my-btn>
		</div>
		<template id="btn_group">
			<button @click="counter++">按钮点击次数{{counter}}</button>
		</template>
		<script>
			//实例化组件
			Vue.component('my-btn', {
				template: '#btn_group',
				data() {
					return { counter: 0 }
				}
			});

			new Vue({
				el: '#app'

			});
		</script>
	</body>
  </html>

测试结果:(描述,我们点击不同的按钮统计的counter都是自己的)

u  如果我们将counter定义到外面来

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>

	<body>
		<div id="app">
			<!-- 使用组件 -->
			<my-btn></my-btn>
			<my-btn></my-btn>
			<my-btn></my-btn>
		</div>
		<template id="btn_group">
			<button @click="counter++">按钮点击次数{{counter}}</button>
		</template>

		<script>
			//组件将共享一个countDate
			let countDate = { counter: 0 };
			Vue.component('my-btn', {
				template: '#btn_group',
				data() {
					return countDate;
				}
			});

			new Vue({
				el: '#app'
			});
		</script>
	</body>
 </html>

测试结果:(描述:我们点击其中一个按钮其他按钮点击次数也会随之改变,共享一个counter值)


七、组件通信

 父子组件之间的通信,父组件通过 prop 给子组件下发数据,子组件通过$emit触发事件给父组件发送消息,即 prop 向下传递,事件向上传递。

  • 父组件向子组件传值(简单的单层组件之间的值传递)

     首先在父组件中使用v-bind将数组绑定给子组件,再在子组件中,使用props收。

   <body>
            <div id="app">
                <my-div :msg='孤独的星星' imgsrc='img/estar.ico'></my-div>
            </div>
            <template id="my_div">
                <div>
                    <h1>{{msg}}</h1>
                    <img :src="imgsrc" width="100" height="100" />
                </div>
            </template>

            <script>
                //实例化组件
                Vue.component('my-div', {
                    template: '#my_div',
                    props:['msg','imgsrc'] //父组件通过props向子组件传递值
                });

                new Vue({
                    el: '#app'
                });
            </script>
        </body>
   
   或者使用绑定的方式将父组件的值传递给子组件:
    <body>
            <div id="app">
            	<!-- 使用绑定的方式,将父组件的数据绑定给子组件 -->
                <my-div :msg='msg' :imgsrc='imgsrc'></my-div>
            </div>
            
            <template id="my_div">
                <div>
                    <h1>{{msg}}</h1>
                    <img :src="imgsrc" width="100" height="100" />
                </div>
            </template>

            <script>
                //实例化组件
               const myCom =  Vue.component('my-div', {
				                    template: '#my_div',
				                    props:['msg','imgsrc'] //父组件通过props向子组件传递值,或者写法如下
                                   //props: {
                                   //  msg: {
                                   //   type: String,   //type支持的类型有: String、Number、Boolean、Array、Object、Date、Function、Symbol
                                   //   default: '我是默认值,父组件没有传给我msg'
                                   // }
                                   // }
				                });

                new Vue({
                    el: '#app',
                    data:{
                    	msg:'孤独的星星',
                    	imgsrc:'img/estar.ico'
                    },
                    components:{
                    	myCom
                    }
                });
            </script>
        </body>

测试结果:
父组件向子组件传值之单层组件传值
  • 父组件向子组件传值(多层组件之间的值传递)

多层组件传值示意图

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>

	<body>
		<div id="app">
			<!-- 使用父组件 -->
			<my-parent :imgtitle="title" :imgsrc="img"></my-parent>
		</div>
		<!-- 定义子组件 -->
		<template id="my_img">
			<img :src="imgsrc" width="200" />
		</template>
		<template id="my_title">
			<h2>{{title}}</h2>
		</template>
		<!-- 定义父组件 -->
		<template id="my_parent">
			<div>
				<child1 :imgsrc="imgsrc"></child1>
				<child2 :title="imgtitle"></child2>
			</div>
		</template>

		<script>
			//1.子组件的实例
			let child1 = Vue.extend({
				template: '#my_img',
				props: ['imgsrc']
			});
			let child2 = Vue.extend({
				template: '#my_title',
				props: ['title']
			});
			//2.注册父组件
			Vue.component('my-parent', {
				props: ['imgtitle', 'imgsrc'],
				components: {
					'child1': child1,
					'child2': child2
				},
				template: '#my_parent'
			});

			new Vue({
				el: '#app',
				data: {
					title: '孤独的星星',
					img: 'img/estar.ico'
				}
			});
		</script>
	</body>
 </html>

测试结果:
父组件向子组件传值之多层组件传值

  • 父组件向子组件传递事件

   我们知道父组件是使用props传递数据给子组件,但如果子组件要把数据传递回去,则应该使用自定义事件来完成!

 使用$on(eventName)监听事件,使用$emit(eventName)来触发事件,另外父组件可以在使用子组件的地方直接使用v-on来监听子组件除法的事件。

描述: 我们在父组件中自定义一个total事件,当我们触发这个total()事件的时候通过$emit('total')来触发外界定义的@total="allcounter()"中
      的具体的方法allcounter()。注意在此案例中按钮与按钮之间是相互独立的,互不影响。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
	</head>

	<body>
		<div id="app">
			<!—自定义事件-->
			<my-btn @total="allcounter()"></my-btn>
			<my-btn @total="allcounter()"></my-btn>
			<my-btn @total="allcounter()"></my-btn>
			<my-btn @total="allcounter()"></my-btn>
			<p>所有按钮一共点击了{{totalCounter}}次</p>
		</div>
		<template id="my_btn">
			<button @click="total()">点击了{{counter}}次</button>
		</template>
		<script>
			Vue.component('my-btn', {
				template: '#my_btn',
				data() {
					return {
						counter: 0
					}
				},
				methods: {
					total() {
						this.counter += 1; //不同的按钮享有不同的counter
						// 通知外界,我调用了这个方法
						this.$emit('total');
					}
				}
			});

			new Vue({
				el: '#app',
				data: {
					totalCounter: 0 //公共的数据
				},
				methods: {
					allcounter() {
						this.totalCounter += 1;
					}
				}
			});
		</script>
	</body>
 </html>

测试结果:(描述我们低级不同的按钮分别统计不同的按钮点击次数,互不影响)

父组件向子组件传递事件

  • 父组件调用子组件方法

    $refs是和ref一起使用的。通过ref给某个子组件绑定一个特定的ID,然后我们使用$refs.ID就可以访问到子组件了。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8" />
		<title></title>
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>

	</head>

	<body>
		<div id="app">
			<button @click="countAdd">点我</button>
			<!-- 第一步,给子组件绑定一个ref -->
			<my-com ref="myComp"></my-com>
		</div>

		<template id="myTemp">
			<div>
				{{count}}
			</div>
		</template>
		<script>
			let myCom = Vue.extend({
				template: '#myTemp',
				data() {
					return {
						count: 1
					}
				},
				methods: {
					addCount() {
						this.count++
					}
				}
			})
			let app = new Vue({
				el: '#app',
				methods: {
					countAdd() {
						// 第二步,在父组件中使用this.$refs.id就行了
						console.log(this.$refs.myComp.count)
						this.$refs.myComp.addCount()
					}
				},
				components: {
					myCom
				}
			})
		</script>
	</body>
</html>
测试结果:
父组件调用子组件方法

八、插槽

  Slot插槽实现内容分发,结合日常生活中的电路板,有指定插孔,我们可以插入任何电器插头(匿名插槽),也有专门针对手机的USB插头(实名插槽),无法插入其他电器插头。

  • 匿名插槽

	<body>
		<div id="app">
			<my-slot>
				<img src="img/estar.ico" width="200" alt="">
				<p>{{msg}}</p>
			</my-slot>
		</div>
		<template id="my_slot">
			<div>
				<header>插槽的头部</header>
				<!--预留一个插槽,没有则显示该插槽内容-->
				<slot>可以替换任何标签,默认显示提示的内容</slot>
				<footer>插槽的尾部</footer>
			</div>
		</template>
		<script>
			Vue.component('my-slot', {
				template: '#my_slot'
			});

			new Vue({
				el: '#app',
				data: {
					msg: '孤独的星星'
				}
			});
		</script>
	</body>

测试结果:
匿名插槽

  • 实名插槽

<body>
		<div id="app">
			<my-computer>
				<div slot="cpu">core-i7 6700HQ处理器</div>
				<div slot="memory">Kingston-32G内存条</div>
			</my-computer>
		</div>

		<template id="my_computer">
			<div>
				<slot name="cpu">默认插cpu的</slot>
				<slot name="memory">默认插内存条的</slot>
				<slot name="hard-drive">默认插硬盘的</slot>
			</div>
		</template>
		<script>
			Vue.component('my-computer', {
				template: '#my_computer'
			});

			new Vue({
				el: '#app'
			});
		</script>

测试结果:
实名插槽

九、路由

                  https://www.jianshu.com/p/2acf9e23793a
前端路由和后端路由:
  • 后端路由:对于普通的网站,所有的超链接都是url地址,所有url都对应服务器上对应的资源
  • 前端路由:对于单页面应用程序来说,主要通过url的hash(#)来实现不同页面的切换,同时hash还有一个特点HTTP请求中不会包含hash相关的内容,所以单页面程序中的页面跳转主要用hash实现
    在单页面应用程序中这种通过hash来改变页面的方式称作前端路由区别于后端路由
==>由于Vue在开发时对路由支持的不足,于是官方补充了vue-router插件。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。
  • 引入vue-router
      <script src="lib/vue-router.js"></script>  

或者: <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

  • 路由入门

    创建一个路由对象,当导入vue-router包之后,在window全局对象中就有一个路由的构造函数VueRouter
在new路由对象的时候可以传递一个配置对象,这个配置对象的route表示路由器的匹配规则
每个路由规则都是一个对象,这个规则对象身上必须有两个属性
属性1 path表示监听哪个路由链接地址
属性2 component,表示如果路由是前面匹配到的path,则展示component属性对应的组件,component属性值必须是一个组件模板对象,不能是组件的引用名称

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="lib/vue-2.6.12.js"></script>
		<script src="lib/vue-router.js"></script>
		<style>
			ul li {
				float: left;
				width: 300px;
				height: 70px;
				box-sizing: border-box;
				background-color: pink;
				list-style: none;
				line-height: 70px;
				text-align: center;
			}
			
			ul li a {
				text-decoration: none;
				font-size: 20px;
			}
			
			.content {
				clear: both;
				width: 900px;
				box-sizing: border-box;
				border: 1px solid blue;
				padding-left: 20px;
				margin-left: 40px;
			}
		</style>
	</head>
		<body>
			<div id="app">
				<!-- 使用 router-link 组件来导航. -->
				<!-- 通过传入 `to` 属性指定链接. -->
				<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
				<ul>
					<li>
						<router-link to="/h5">HTML5学院</router-link>
					</li>
					<li>
						<router-link to="/python">Python学院</router-link>
					</li>
					<li>
						<router-link to="/java">Java学院</router-link>
					</li>
				</ul>
				<div class="content">
					<!-- 路由出口 -->
					<!-- 路由匹配到的组件将渲染在这里 -->
					<router-view></router-view>
				</div>
			</div>

			<template id="h5">
				<div>
					<h2>HTML5学院</h2>
					<p>掌握面向未来的神技!</p>
				</div>
			</template>
			<template id="python">
				<div>
					<h2>Python学院</h2>
					<p>人工智能的最佳选择!</p>
				</div>
			</template>
			<template id="java">
				<div>
					<h2>Java学院</h2>
					<p>掌握面向工资编程!</p>
				</div>
			</template>
			<script>
				//1.创建组件
				const Html5 = Vue.extend({
					template: '#h5'
				});
				const Python = Vue.extend({
					template: '#python'
				});
				const Java = Vue.extend({
					template: '#java'
				});
				//2.定义路由
				const routes = [
					{ path: '/h5', component: Html5 },
					{ path: '/python', component: Python },
					{ path: '/java', component: Java },
					//配置根路由,默认显示
					{ path: '/', redirect: '/h5' }
				];
				//3.创建路由实例
				const router = new VueRouter({
					routes
				});
				//4.创建Vue实例并挂载
				new Vue({
					router
				}).$mount('#app');
			</script>
		</body>
	</body>
</html>

测试结果: (描述:我们点击不同的tab切换页能实现展示不同的内容)

vue路由使用
补充:上述代码存在一个弊端,就是<router-link to="/h5">HTML5学院</router-link>路由时我们需要将路由路径写死在页面上,建议采用动态绑定的方式会更好。下面采用给路由命名的方式来解决这个问题

<body>
		<div id="app">
			<!-- 使用 router-link 组件来导航. -->
			<!-- 通过传入 `to` 属性指定链接. -->
			<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
			<ul>
				<li><router-link :to="{name:'h5'}">HTML5学院</router-link></li>
				<li><router-link :to="{name:'python'}">Python学院</router-link></li>
				<li><router-link :to="{name:'java'}">Java学院</router-link></li>
			</ul>
			<div class="content">
				<!-- 路由出口 -->
                <!-- 路由匹配到的组件将渲染在这里 -->
                <router-view></router-view>
			</div>
		</div>

		<template id="h5">
			<div>
				<h2>HTML5学院</h2>
				<p>掌握面向未来的神技!</p>
			</div>
		</template>
		<template id="python">
			<div>
				<h2>Python学院</h2>
				<p>人工智能的最佳选择!</p>
			</div>
		</template>
		<template id="java">
			<div>
				<h2>Java学院</h2>
				<p>掌握面向工资编程!</p>
			</div>
		</template>
		<script>
			//1.创建组件
			const Html5 = Vue.extend({
				template: '#h5'
			});
			const Python = Vue.extend({
				template: '#python'
			});
			const Java = Vue.extend({
				template: '#java'
			});
			//2.定义路由
			const routes = [
				{ path: '/h5', component: Html5,name:'h5' },
				{ path: '/python', component: Python,name:'python' },
				{ path: '/java', component: Java ,name:'java'},
				//配置根路由,默认显示
				{ path: '/', redirect: '/h5' }
			];
			//3.创建路由实例
			const router = new VueRouter({
				routes
			});
			//4.创建Vue实例并挂载
			new Vue({
				router
			}).$mount('#app');
		</script>
	</body>

  • 多级子路由

    	<body>
    		<div id="app">
    			<!-- 使用 router-link 组件来导航. -->
    			<!-- 通过传入 `to` 属性指定链接. -->
    			<!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    			<ul>
    				<li><router-link to="/h5">HTML5学院</router-link></li>
    				<li><router-link to="/python">Python学院</router-link></li>
    				<li><router-link to="/java">Java学院</router-link></li>
    			</ul>
    			<div class="content">
    				<!-- 路由出口 -->
                    <!-- 路由匹配到的组件将渲染在这里 -->
                    <router-view></router-view>
    			</div>
    		</div>
    
    		<template id="h5">
    			<div>
    				<h2>HTML5学院</h2>
    				<p>掌握面向未来的神技!</p>
    			</div>
    		</template>
    		<template id="python">
    			<div>
    				<h2>Python学院</h2>
    				<p>人工智能的最佳选择!</p>
    			</div>
    		</template>
    		<template id="java">
    			<div>
    				<h2>Java学院</h2>
    				<p>掌握面向工资编程!</p>
    				<!--子组件路由-->
    				<router-link  to="/java/base">基础班</router-link>
                    <router-link  to="/java/advance">进阶班</router-link>
    				<div>
    					<!-- 子组件出口 -->
                        <router-view></router-view>
                    </div>
    			</div>
    		</template>
    		<!-- 定义Java组件下的子组件 -->
    		<template id="base">
    	        <div>
    	            <h3>Java基础班</h3>
    	            <p>快速掌握Java的三大特性!</p>
    	        </div>
    	    </template>
    
    	    <template id="advance">
    	        <div>
    	            <h3>Java进阶班</h3>
    	            <p>掌握高并发高可用的架构!</p>
    	        </div>
    	    </template>
    		<script>
    			//1.创建组件
    			const Html5 = Vue.extend({
    				template: '#h5'
    			});
    			const Python = Vue.extend({
    				template: '#python'
    			});
    			const Java = Vue.extend({
    				template: '#java'
    			});		
    			//创建Java的子组件
    			const base = Vue.extend({
    				template: '#base'
    			});	
    			const advance = Vue.extend({
    				template: '#advance'
    			});	
    			
    			//2.定义路由
    			const routes = [
    				{ path: '/h5', component: Html5 },
    				{ path: '/python', component: Python },
    				{ path: '/java', component: Java,
    				children: [  //使用children属性实现路由嵌套,子路由path前不要加/,否则永远以根路径开始请求
                        {path:'base', component: base},
                        {path:'advance', component: advance},
                        // 配置Java组件的根路由,默认显示
                        {path:'/', redirect: 'base'}
                    ]
    				},
    				//配置根路由,默认显示
    				{ path: '/', redirect: '/h5' }
    			];
    			//3.创建路由实例
    			const router = new VueRouter({
    				routes
    			});
    			//4.创建Vue实例并挂载
    			new Vue({
    				router
    			}).$mount('#app');
    		</script>
    	</body>

测试结果:

vue多级子路由使用

  • 路由传参

  1. 如果使用查询字符串 给路由传递参数则不需要修改路由规则的path属性,直接在组件当中使用{$route.query.字段名}}即可获取值。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="lib/vue-2.6.12.js"></script>
		<script src="lib/vue-router.js"></script>
	</head>
	<body>
		<div id="app">
			<!-- 路由入口 -->
			<router-link to="/login?username=zs&password=123">登录</router-link>

			<div>
				<!-- 路由出口 -->
				<router-view></router-view>
			</div>
		</div>
        
		<template id="userInfo">
			<div>
				用户:{{$route.query.username}},密码:{{$route.query.password}}
			</div>
		</template>
		<script>
			//1.创建组件
			const userInfo = Vue.extend({
				template: '#userInfo'
			});

			//2.定义路由
			const routes = [
				{ path: '/login', component: userInfo },
				//配置根路由,默认显示
				{ path: '/', redirect: 'login' }
			];
			//3.创建路由实例
			const router = new VueRouter({
				routes
			});
			//4.创建Vue实例并挂载
			new Vue({
				router
			}).$mount('#app');
		</script>
	</body>
</html>
测试结果:
2. 通过params方式传递路由参数,login后面会被解析为id的值
    <router-link to="/login/zs">登录</router-link>

    { path: '/login/:username', component: userInfo }

    <template id="userInfo">
        <div>
            用户:{{$route.params.username}}
        </div>
    </template>

测试结果:

十、过渡动画

Vue中为我们提供了简单的过渡动画效果,只需要按照vue提供的标准去写一套固定的CSS即可。

  <style>
    /* v-enter 这个是一个时间点,表示动画进入之前,元素的起始状态,此时还没有进入 */
    /* v-leave-to 这是一个时间点,是动画离开之后,元素的终止状态,此时,元素动画已经结束了 */
    .v-enter,
    .v-leave-to {
      opacity: 0;
      transform: translateX(50px);
    }
    
    /* v-enter-active 表示入场动画的时间段 */
    /* v-leave-active 表示离场动画的时间段 */
    .v-enter-active,
    .v-leave-active {
      transition: all 0.8s ease;
    }
  </style>

<body>
  <div id="app">
    <button @click="flag = !flag">点击</button>
    <transition>
      <div v-show="flag">这个是第一个div</div>
    </transition>
  </div>
</body>
<script>
  let app = new Vue({
    el: '#app',
    data: {
      flag: true
    },
    methods: {
    }
  })
</script>
测试结果:
此时如果我们想要让div1消失后,div2进来,div2消失后div1进来,应该怎么办?只需要写两套动画即可
    <transition>
      <div v-show="flag">这个是第一个div</div>
    </transition>
    <transition>
      <div v-show="!flag">这个是第二个div</div>
    </transition>

如果div1和div2不想公用一套动画,应该怎么办?这时候我们可以给transition命名,使用name属性即可。定义了name之后,两个transition则使用自己独立的动画效果。定义了name之后,动画的相关class,要以name开头,不能以v开头。

    <transition name="div1">
      <div v-show="flag">这个是第一个div</div>
    </transition>
    <transition name="div2">
      <div v-show="!flag">这个是第二个div</div>
    </transition>
  <style>
    /* v-enter 这个是一个时间点,表示动画进入之前,元素的起始状态,此时还没有进入 */
    /* v-leave-to 这是一个时间点,是动画离开之后,元素的终止状态,此时,元素动画已经结束了 */
    .div1-enter,
    .div1-leave-to {
      opacity: 0;
      transform: translateX(50px);
    }
    
    /* v-enter-active 表示入场动画的时间段 */
    /* v-leave-active 表示离场动画的时间段 */
    .div1-enter-active,
    .div1-leave-active {
      transition: all 0.8s ease;
    }
    /* v-enter 这个是一个时间点,表示动画进入之前,元素的起始状态,此时还没有进入 */
    /* v-leave-to 这是一个时间点,是动画离开之后,元素的终止状态,此时,元素动画已经结束了 */
    .div2-enter,
    .div2-leave-to {
      opacity: 0;
      transform: translateX(50px);
    }
    
    /* v-enter-active 表示入场动画的时间段 */
    /* v-leave-active 表示离场动画的时间段 */
    .div2-enter-active,
    .div2-leave-active {
      transition: all 0.2s ease;
    }
  </style>

十一、生命周期

vue生命周期
vue生命周期示意图
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<script src="lib/vue-2.6.12.js"></script>
	</head>
	<body>
		<div id="app">
			<div id="divId">页面还没有渲染 --- {{msg}}</div>
		</div>
	</body>
	<script>
		var vue = new Vue({
			el: '#app',
			data: {
				msg: '页面渲染完毕'
			},
			methods: {},
			filters: {},
			beforeCreate() {
				// 这是我们第一个遇到的生命周期函数,实例被创建出来,还没有data、methods等时,会执行它
				let content = document.getElementById('divId')
				console.log('beforeCreate:', content.innerText)
				// 在js中,null和undefined是不同的含义。null表示有这个对象,但是这个对象的值是null。undefined表示压根就没有这个对象
				console.log('beforeCreate', this.msg)
			},
			created() {
				// Vue实例创建完毕,methods、data、filters等已经挂载到vue实例上。如果需要调用methods,使用data,最早只能在这里操作
				let content = document.getElementById('divId')
				console.log('created', content.innerText)
				console.log('created', this.msg)
			},
			beforeMount() {
				// Vue实例创建完毕,页面尚未重新渲染
				let content = document.getElementById('divId')
				console.log('beforeMounte', content.innerText)
				console.log('beforeMounte', this.msg)
			},
			mounted() {
				// 页面渲染完毕
				let content = document.getElementById('divId')
				console.log('mounted', content.innerText)
				console.log('mounted', this.msg)
			}
		})
	</script>
</html>

十二、实战演练

案例一: 本地模拟员工信息的增删改查功能。  源码:  
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<!-- 引入layui样式 -->
		<link rel="stylesheet" href="lib/layui/css/layui.css" />
		<!--引入vue.js-->
		<script src="lib/vue-2.6.12.js"></script>
		<!-- 引入layui.js -->
		<script src="lib/layui/layui.all.js"></script>
	</head>

	<body>
		<div id="app">
			<fieldset class="layui-elem-field layui-field-title" style="margin-top: 20px;">
				<legend>员工管理</legend>
			</fieldset>
			<!-- 搜索栏 -->
			<form class="layui-form">
				<div class="layui-form-item">
					<div class="layui-inline">
						<label class="layui-form-label">姓 名:</label>
						<div class="layui-input-inline">
							<input type="text" v-model="searchName" placeholder="请输入姓名" class="layui-input">
						</div>
					</div>
					<div class="layui-inline">
						<button type="button" class="layui-btn layui-btn-normal  layui-icon layui-icon-search" @click="searchUser">查询</button>
						<button type="reset" class="layui-btn layui-btn-warm  layui-icon layui-icon-refresh">重置</button>
						<button type="button" class="layui-btn layui-btn layui-icon layui-icon-addition" @click="saveOrUpdateDiv()">添加</button>
					</div>
				</div>
			</form>

			<!-- 数据表格 -->
			<table class="layui-table">
				<thead>
					<tr>
						<th>编号</th>
						<th>姓名</th>
						<th>年龄</th>
						<th>性别</th>
						<th>备注</th>
						<th>操作</th>
					</tr>
				</thead>
				<tbody>
					<tr v-for="item in userList" :key="item.id">
						<td>{{item.id}}</td>
						<td>{{item.name}}</td>
						<td>{{item.gender | handlerGender}}</td>
						<td>{{item.remark}}</td>
						<td>
							<button type="button" class="layui-btn layui-btn-normal" @click="saveOrUpdateDiv(item)">编辑</button>
							<button type="button" class="layui-btn layui-btn-danger" @click="delUser(item.id)">删除</button>
						</td>
					</tr>
				</tbody>
			</table>

			<!-- 添加和修改的弹出层开始 -->
			<div style="display: none;padding: 20px" id="saveOrUpdateDiv">
				<form class="layui-form">
					<div class="layui-form-item">
						<div class="layui-inline">
							<label class="layui-form-label">用户id</label>
							<div class="layui-input-inline">
								<input type="text" v-model="user.id" placeholder="输入用户id" class="layui-input" readonly>
							</div>
							<label class="layui-form-label">用户姓名</label>
							<div class="layui-input-inline">
								<input type="text" v-model="user.name" placeholder="请输入姓名" class="layui-input">
							</div>
						</div>
					</div>
					<div class="layui-form-item">
						<div class="layui-inline">
							<label class="layui-form-label">性别</label>
							<div class="layui-input-inline">
								<input type="text" v-model="user.gender" placeholder="请输入性别" class="layui-input">
							</div>
							<label class="layui-form-label">备注</label>
							<div class="layui-input-inline">
								<input type="text" v-model="user.remark" placeholder="请输入备注" class="layui-input">
							</div>
						</div>
					</div>
					<div class="layui-form-item" style="text-align: center;">
						<div class="layui-input-block">
							<button type="button" class="layui-btn layui-btn-normal layui-btn-sm layui-icon layui-icon-release" v-if="!user.id" @click="addUser">新增</button>
							<button type="button" class="layui-btn layui-btn-normal layui-btn-sm layui-icon layui-icon-release" v-else @click="editUser(user)">修改</button>
							<button type="reset" class="layui-btn layui-btn-warm layui-btn-sm layui-icon layui-icon-refresh">重置</button>
						</div>
					</div>
				</form>
			</div>
			<!-- 添加和修改的弹出层结束 -->
		</div>
	</body>

	<script>
		var mainIndex;
		const vm = new Vue({
			el: '#app',
			data: {
				userList: [], //用户列表
				data: [ //数据库,存放用户数据
					{ id: 1, name: '张三', gender: 1, remark: '姓张名三' },
					{ id: 2, name: '李四', gender: 2, remark: '姓李名四' },
					{ id: 3, name: '王五', gender: 1, remark: '姓王名五' },
					{ id: 4, name: '赵六', gender: 2, remark: '姓赵名六' }
				],
				user: {},
				searchName: '' //搜索用的名称
			},
			filters: {
				handlerGender(gender) {
					if(gender == 1) {
						return '男'
					} else {
						return '女'
					}
				}
			},
			methods: {
				saveOrUpdateDiv(user) { //打开新增或者修改的弹出层
					if(!user) {
						title = '添加用户';
						//清空新增弹出层数据
						this.user = {};
					} else {
						title = '编辑'+user.name+'信息';
						//回显编辑的数据,注意不能直接 this.user = user;
						this.user = { ...user };
						//等价于this.user = {id: user.id, name: user.name,gender: user.gender,remark: user.remark}
					}
					mainIndex = layui.layer.open({
						type: 1,
						title: title,
						content: layui.jquery("#saveOrUpdateDiv"),
						area: ['700px', '250px'],
						maxmin: true
					});
				},
				getUserList(name) { //加载用户数据
					if(!name) {
						name = '';
					}
					const dataList = this.data.filter(e => e.name.indexOf(name) >= 0);
					this.userList = dataList;
				},
				addUser() { //添加用户
					const user = { ...this.user };
					//等价于 const user = {id: this.user.id, name: this.user.name,gender: this.user.gender,remark: this.user.remark};
					//随机生成id,范围在1-100之间
					user.id = Math.round(Math.random() * (100 - 1) + 1)
					//添加到数据库里
					this.data.push(user);
					//关闭弹出层
					layui.layer.close(mainIndex);
					//重新加载数据
					this.getUserList();
				},
				delUser(id) {
					// 查到指定id所在数组索引下标
					const index = this.userList.findIndex(e => e.id === id)
					// 删除指定索引位置的数据
					this.data.splice(index, 1)
					// 删除成功后,重新家在数据
					this.getUserList()
				},
				editUser(user){ //修改用户 
					const index = this.data.findIndex(e => e.id === user.id);
					this.data[index] = user;
					//关闭弹出层
					layui.layer.close(mainIndex);
					//重新加载数据
					this.getUserList();
				},
				searchUser() { // 搜索用户
					// 遍历用户,找到所有复合条件的用户
					this.getUserList(this.searchName)
				}
			},
			created() {
				// 进入页面,组件创建之后,获取数据
				this.getUserList()
			}
		})
	</script>
</html>
测试结果:
vue+layui增删改查
案例二: 本地模拟品牌管理的增删改查功能。   源码: 
<!DOCTYPE html>
<html lang="en">

	<head>
		<meta charset="UTF-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>品牌列表案例</title>
		<!-- 引入bootstrap样式-->
		<link rel="stylesheet" href="lib/bootstrap.css">
		<style>
			body {
				padding: 15px;
				user-select: none;
			}
		</style>
	</head>
	<body>

		<div id="app">
			<!-- 卡片区域 -->
			<div class="card">
				<div class="card-header">
					添加品牌
				</div>
				<div class="card-body">
					<!-- 添加品牌的表单区域 -->
					<!-- form 表单元素有 submit 事件 -->
					<form @submit.prevent="add">
						<div class="form-row align-items-center">
							<div class="col-auto">
								<div class="input-group mb-2">
									<div class="input-group-prepend">
										<div class="input-group-text">品牌名称</div>
									</div>
									<input type="text" class="form-control" placeholder="请输入品牌名称" v-model.trim="brand">
								</div>
							</div>
							<div class="col-auto">
								<button type="submit" class="btn btn-primary mb-2">添加</button>
							</div>
						</div>
					</form>
				</div>
			</div>

			<!-- 表格区域 -->
			<table class="table table-bordered table-hover table-striped">
				<thead>
					<tr>
						<th scope="col">#</th>
						<th scope="col">品牌名称</th>
						<th scope="col">状态</th>
						<th scope="col">创建时间</th>
						<th scope="col">操作</th>
					</tr>
				</thead>
				<tbody>
					<tr v-for="item in list" :key="item.id">
						<td>{{ item.id }}</td>
						<td>{{ item.name }}</td>
						<td>
							<div class="custom-control custom-switch">
								<!-- 使用 v-model 实现双向数据绑定 -->
								<input type="checkbox" class="custom-control-input" :id="'cb' + item.id" v-model="item.status">
								<!-- 使用 v-if 结合 v-else 实现按需渲染 -->
								<label class="custom-control-label" :for="'cb' + item.id" v-if="item.status">已启用</label>
								<label class="custom-control-label" :for="'cb' + item.id" v-else>已禁用</label>
							</div>
						</td>
						<td>{{ item.time | dateFormat }}</td>
						<td>
							<a href="javascript:;" @click="remove(item.id)">删除</a>
						</td>
					</tr>
				</tbody>
			</table>
		</div>

		<!-- 只要导入了 dayjs 的库文件,在 window 全局,就可以使用 dayjs() 方法了 -->
		<script src="./lib/dayjs.min.js"></script>
		<script src="./lib/vue-2.6.12.js"></script>
		<script>
			// 声明格式化时间的全局过滤器
			Vue.filter('dateFormat', function(time) {
				// 1. 对 time 进行格式化处理,得到 YYYY-MM-DD HH:mm:ss
				// 2. 把 格式化的结果,return 出去

				// 直接调用 dayjs() 得到的是当前时间
				// dayjs(给定的日期时间) 得到指定的日期
				const dtStr = dayjs(time).format('YYYY-MM-DD HH:mm:ss')
				return dtStr
			})

			const vm = new Vue({
				el: '#app',
				data: {
					// 用户输入的品牌名称
					brand: '',
					// nextId 是下一个,可用的 id
					nextId: 4,
					// 品牌的列表数据
					list: [
						{ id: 1, name: '宝马', status: true, time: new Date() },
						{ id: 2, name: '奔驰', status: false, time: new Date() },
						{ id: 3, name: '奥迪', status: true, time: new Date() },
					],
				},
				methods: {
					show(item){
						console.info(item)
					},
					// 点击链接,删除对应的品牌信息
					remove(id) {
						this.list = this.list.filter(item => item.id !== id)
					},
					// 阻止表单的默认提交行为之后,触发 add 方法
					add() {
						// 如果判断到 brand 的值为空字符串,则 return 出去
						if(this.brand === '') return alert('必须填写品牌名称!')

						// 如果没有被 return 出去,应该执行添加的逻辑
						// 1. 先把要添加的品牌对象,整理出来
						const obj = {
							id: this.nextId,
							name: this.brand,
							status: true,
							time: new Date()
						}
						// 2. 往 this.list 数组中 push 步骤 1 中得到的对象
						this.list.push(obj)
						// 3. 清空 this.brand;让 this.nextId 自增 +1
						this.brand = ''
						this.nextId++
					}
				},
			})
		</script>
	</body>
</html>
测试结果:
vue+bootstrap增删改查

附件列表

     

    posted @ 2021-09-06 09:41  孤独的星星  Views(279)  Comments(0Edit  收藏  举报