webpack +vue

前 15 章 均使用 1.0 写法

1. MVC 和 MVVM

2. 前台渲染和后台渲染

前台渲染后台渲染
降低服务器负担,带宽压力小SEO、兼容性
用户体验好安全性

3. 模板渲染 {{}}

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="div1">
			姓名:{{name}} <br>
			年龄:{{age}} <br>
			年份:{{calcBirth()}}
		</div>
	</body>
	<script>
		let vm = new Vue({
			el: '#div1',
			data: {
				name: 'ly',
				age: 18
			},
			methods: {
				calcBirth(){
					return new Date('2000-01-19').getFullYear();
				}
			}
		})
	</script>
</html>

在这里插入图片描述

  • 当我们数据发生改变时,会自动同步到视图。(核心
    在这里插入图片描述

4. 指令(directive)

v-bind

  • v-bind 向HTML属性中添加值,可简写为 :,如::title="age"
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<strong v-bind:title="age">{{name}}</strong>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				name: 'ly',
    				age: 18
    			}
    
    		})
    	</script>
    </html>
    
    在这里插入图片描述
  • 可以用于任何属性,有两个属性(class,style)有另外的写法
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<!-- v-bind 指令 -->
    			<strong v-bind:title="age" :class="class_str" :style="style_str">{{name}}</strong><br>
    			<strong v-bind:title="age" :class="class_arr" :style="style_json">{{name}}</strong>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				name: 'ly',
    				age: 18,
    				class_str: 'aa bb cc',
    				class_arr: ['aaa', 'bbb', 'ccc'],
    				style_str: 'display:block;with:200px;background:yellow',
    				style_json: {
    					display: 'block',
    					background: 'green',
    					width: '200px'
    				}
    			}
    
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-model 数据绑定数据双向绑定

  • 数据绑定数据双向绑定
    • 数据和 input 是双向绑定
    • 跳过 controller——控制器 直接对话
    • 在这里插入图片描述
  • 只能用于输入组件
  • 通过 v-model 的数据都是字符串
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="text" v-model="name">
    			<p>{{name}}</p>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				name: 'ly'
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-text

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="div1">
			<div v-text='str'></div>
		</div>
	</body>
	<script>
		let vm = new Vue({
			el: '#div1',
			data: {
				str:'Hello World'
			}
		})
	</script>
</html>

在这里插入图片描述

v-html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<div id="div1">
			<div v-html='str'></div>
		</div>
	</body>
	<script>
		let vm = new Vue({
			el: '#div1',
			data: {
				str:'<p>Hello World</p><p>Hello World</p><p>Hello World</p>'
			}
		})
	</script>
</html>

在这里插入图片描述

v-on

  • 给元素进行事件绑定;可简写成@,如:@click="fn()"
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			{{a}}
    			<input type="button" value="+1" v-on:click="fn()">
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				a:12
    			},
    			methods:{
    				fn(){
    					this.a++
    				}
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-show 和 v-if

  • v-show 控制 display
  • v-if 删除这个元素
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    		<style type="text/css">
    			.box {
    				width: 200px;
    				height: 200px;
    				border: 1px solid red;
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="button" value="显示隐藏" @click="fn()">
    			<div class="box" v-show="a"></div>
    			<div class="box" v-if="a"></div>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				a: true
    			},
    			methods: {
    				fn() {
    					this.a = !this.a
    				}
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-for

  • 虚拟dom
    • 合并请求
    • 快速查询
    • 局部刷新
  • :key属性
    • key的作用主要是为了高效的更新虚拟DOM。
    • 不能重复
    • 不能改变
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<ul>
    				<li v-for="user,index in user_arr" :key="user.id">
    					{{index}}
    					用户名: {{user.name}}
    					密码: {{user.password}}
    				</li>
    				<li></li>
    				
    				<li v-for="v,k in style_json">
    					{{k}}:{{v}}
    				</li>
    				<li></li>
    				
    				<li v-for="item,index in str">
    					{{index}}:{{item}}
    				</li>
    				<li></li>
    				
    				<li v-for="i in 3">
    					{{i}}
    				</li>
    			</ul>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				user_arr: [{
    						id:'a1',
    						name: 'ly',
    						password: '123321'
    					},
    					{
    						id:'a2',
    						name: '张三',
    						password: '123321'
    					},
    					{
    						id:'a3',
    						name: '李四',
    						password: '123321'
    					}
    				],
    				style_json: {
    					color: 'red',
    					background: 'green'
    				},
    				str:"abc"
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-pre 预编译

  • 提高性能
  • 防止意外
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title>预编译</title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<div v-pre>
    				{{a}}-{{b}}
    			</div>
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

v-cloak

  • 防止vue代码意外显示出来
  • 编译完成前 v-cloak 会一直存在,完成后自动去除
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    		<style type="text/css">
    			*[v-cloak]{
    				display: none;
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<div>
    				{{a}}-{{b}}
    			</div>
    			
    			<div v-cloak>
    				{{a}}-{{b}}
    			</div>
    		</div>
    	</body>
    	<script>
    		setTimeout(()=>{
    			let vm = new Vue({
    				el: '#div1',
    				data: {
    					a:1,
    					b:2
    				}
    			})
    		},3000)
    	</script>
    </html>
    
    在这里插入图片描述

5. 原生实现 vue 数据同步

  • 源码:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="text" v-model="name" /><br>
    			姓名:{{name}} <br>
    			年龄:{{age}}
    		</div>
    	</body>
    	<script type="text/javascript">
    		let el = document.getElementById('div1');
    
    		// 保存原始 html
    		let template = el.innerHTML;
    
    		let _data = {
    			name: 'ly',
    			age: 18
    		};
    
    		let data = new Proxy(_data, {
    			set(obj, name, value) {
    				obj[name] = value;
    				console.log('数据已发生改变');
    				render();
    			},
    			get() {
    
    			}
    		});
    
    
    		function render() {
    			// 获取双花括号里面的变量
    			// 渲染
    			el.innerHTML = template.replace(/\{\{\w+\}\}/g, str => {
    				str = str.substring(2, str.length - 2);
    
    				return _data[str];
    			});
    
    			// 找所有的 v-model
    			Array.from(el.getElementsByTagName('input'))
    				.filter(ele => ele.getAttribute('v-model'))
    				.forEach(input => {
    					let name = input.getAttribute('v-model');
    
    					input.value = _data[name];
    					
    					
    					input.oninput = function() {
    						data[name] = this.value;
    					}
    				})
    		}
    		render();
    	</script>
    </html>
    
    在这里插入图片描述

-----------------------------------

6. 事件修饰符

  • stop 阻止事件冒泡
  • once 单次事件
  • prevent 阻止默认事件
  • native 原生事件(组件)
  • keycode | name 可以直接筛选按键
  • self 只处理自己的事件(冒泡的就不认)
  • capture 捕获阶段的事件

7. computed —— 计算属性

  • 带缓存,性能高 —— 当数据改变才会重新计算

  • 方便 —— 可读、可写

  • 案例一(读):

  • <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			姓:	<input type="text" v-model="familyName">
    			名:	<input type="text" v-model="givenName">
    			{{name}}
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				familyName: '张',
    				givenName: '三'
    			},
    			computed: {
    				name() {
    					return this.familyName + ' ' + this.givenName;
    				}
    			}
    		})
    	</script>
    </html>
    

    在这里插入图片描述

  • 案例二(读、写):

  • <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			姓:	<input type="text" v-model="familyName"><br>
    			名:	<input type="text" v-model="givenName"><br>
    			<input type="text" v-model="name">
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				familyName: '张',
    				givenName: '三'
    			},
    			computed: {
    				name:{
    					get(){
    						return this.familyName+this.givenName
    					},
    					set(value){
    						this.familyName=value[0];
    						this.givenName=value.substring(1);
    					}
    				}
    			}
    		})
    	</script>
    </html>
    

    在这里插入图片描述

8. watch —— 监听属性

  • 监听变量:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="text" v-model="name">
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				name:'ly'
    			},
    			watch:{
    				name(){
    					console.log('name已经改变');
    				}
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述
  • 监听对象:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="./vue.js" type="text/javascript" charset="utf-8"></script>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="text" v-model="obj.name">
    		</div>
    	</body>
    	<script>
    		let vm = new Vue({
    			el: '#div1',
    			data: {
    				obj: {
    					name: 'ly',
    					age: 18
    				}
    			},
    			watch: {
    				'obj.name': function() {
    					console.log('obj name已经改变');
    				}
    			}
    		})
    	</script>
    </html>
    
    在这里插入图片描述

9. vue-router

  • 路由容器
  • 声明路由表
  • 将路由表添加到 vue

9.1 基本使用:

  • 使用router-link 选中时 自带 router-link-exact-active router-link-active两个类名
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../vue.js" harset="utf-8"></script>
    		<script src="../vue-router.js" charset="utf-8"></script>
    		<style type="text/css">
    			.nav {
    				color: gray;
    				margin-right: 10px;
    			}
    
    			.router-link-active {
    				color: black
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<router-link class="nav" to="/a">页面a</router-link>
    			<router-link class="nav" to="/b">页面b</router-link>
    			<br>
    			文字
    			<!-- 路由容器 -->
    			<router-view></router-view>
    		</div>
    	</body>
    	<script>
    		// 路由表
    		let router = new VueRouter({
    			routes: [{
    				path: '/a',
    				component: {
    					template: '<div>/a</div>'
    				}
    			}, {
    				path: '/b',
    				component: {
    					template: '<div>/b</div>'
    				}
    			}]
    		});
    
    		let vm = new Vue({
    			el: '#div1',
    			data: {},
    			router
    
    		})
    	</script>
    </html>
    
    在这里插入图片描述

9.2 命名路由(name 可选)

  • 当路由级别比较深时方便我们找到对应的路由
  • 路由跳转时使用:to="{name:'路由对应的name'}"进行跳转,M=
    如:<router-link class="nav" :to="{name:'a'}">页面a</router-link>
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../vue.js" harset="utf-8"></script>
    		<script src="../vue-router.js" charset="utf-8"></script>
    		<style type="text/css">
    			.nav {
    				color: gray;
    				margin-right: 10px;
    			}
    
    			.router-link-active {
    				color: black
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<router-link class="nav" :to="{name:'a'}">页面a</router-link>
    			<router-link class="nav" :to="{name:'b'}">页面b</router-link>
    			<br>
    			文字
    			<!-- 路由容器 -->
    			<router-view></router-view>
    		</div>
    	</body>
    	<script>
    		// 路由表
    		let router = new VueRouter({
    			routes: [{
    				path: '/a',
    				name:'a',
    				component: {
    					template: '<div>/a</div>'
    				}
    			}, {
    				path: '/b',
    				name:'b',
    				component: {
    					template: '<div>/b</div>'
    				}
    			}]
    		});
    
    		let vm = new Vue({
    			el: '#div1',
    			data: {},
    			router
    
    		})
    	</script>
    </html>
    

9.3 路由传参

  • $route 当前路由的信息
  • 使用 $route.params可以获取到传递过来的信息
  • 可以使用以下方式进行路由的传参
    • <router-link class="nav" :to="{name:'a',params:{id:99}}">页面a</router-link>
    • <router-link class="nav" to="/b/67">页面b</router-link>
  • 案例
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../vue.js" harset="utf-8"></script>
    		<script src="../vue-router.js" charset="utf-8"></script>
    		<style type="text/css">
    			.nav {
    				color: gray;
    				margin-right: 10px;
    			}
    
    			.router-link-active {
    				color: black
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<router-link class="nav" :to="{name:'a',params:{id:99}}">页面a</router-link>
    			<router-link class="nav" to="/b/67">页面b</router-link>
    			<br>
    			文字
    			<!-- 路由容器 -->
    			<router-view></router-view>
    		</div>
    	</body>
    	<script>
    		// 路由表
    		let router = new VueRouter({
    			routes: [{
    				path: '/a',
    				name:'a',
    				component: {
    					template: '<div>/a {{$route.params.id}}</div>'
    				}
    			}, {
    				path: '/b/:id',
    				name:'b',
    				component: {
    					template: '<div>/b {{$route.params.id}}</div>'
    				}
    			}]
    		});
    
    		let vm = new Vue({
    			el: '#div1',
    			data: {},
    			router
    
    		})
    	</script>
    </html>
    
    在这里插入图片描述
    注:如果路由重复 如:path:'/a/:id'path:'/a/bbb';先匹配到谁就不会往下继续匹配

9.4 通过js控制路由跳转

  • this.$router.push() 控制跳转
    • push(string | object) 入栈
    • replace(string | object) 替换最后一个历史记录(当前)
    • go(int)
  • 可以使用 path 和 name 进行跳转
    • this.$router.push('/a/18');
    • this.$router.push({name:'b',params:{id:20}});
  • 案例:
    <!DOCTYPE html>
    <html>
    	<head>
    		<meta charset="utf-8">
    		<title></title>
    		<script src="../vue.js" harset="utf-8"></script>
    		<script src="../vue-router.js" charset="utf-8"></script>
    		<style type="text/css">
    			.nav {
    				color: gray;
    				margin-right: 10px;
    			}
    
    			.router-link-active {
    				color: black
    			}
    		</style>
    	</head>
    	<body>
    		<div id="div1">
    			<input type="button" value="页面a" @click="fn1()">
    			<input type="button" value="页面b" @click="fn2()">
    			<br>
    			文字
    			<!-- 路由容器 -->
    			<router-view></router-view>
    		</div>
    	</body>
    	<script>
    		// 路由表
    		let router = new VueRouter({
    			routes: [{
    				path: '/a/:id',
    				name:'a',
    				component: {
    					template: '<div>/a {{$route.params.id}}</div>'
    				}
    			}, {
    				path: '/b/:id',
    				name:'b',
    				component: {
    					template: '<div>/b {{$route.params.id}}</div>'
    				}
    			}]
    		});
    
    		let vm = new Vue({
    			el: '#div1',
    			data: {},
    			router,
    			methods:{
    				fn1(){
    					this.$router.push('/a/18');
    				},
    				fn2(){
    					this.$router.push({name:'b',params:{id:20}});
    				}
    			}
    
    		})
    	</script>
    </html>
    
    在这里插入图片描述

9.5 $route 和 $router

  • $route 当前路由信息
  • $router 操作路由

9.6 监视路由

  • 使用 watch —— 不推荐
    • 简单
    • 只能看不能干预
    • 案例:
      <!DOCTYPE html>
      <html>
      	<head>
      		<meta charset="utf-8">
      		<title></title>
      		<!DOCTYPE html>
      		<html>
      			<head>
      				<meta charset="utf-8">
      				<title></title>
      				<script src="../vue.js" harset="utf-8"></script>
      				<script src="../vue-router.js" charset="utf-8"></script>
      				<style type="text/css">
      					.nav {
      						color: gray;
      						margin-right: 10px;
      					}
      
      					.router-link-active {
      						color: black
      					}
      				</style>
      			</head>
      	<body>
      		<div id="div1">
      			<input type="button" value="页面a" @click="fn1()">
      			<input type="button" value="页面b" @click="fn2()">
      			<br>
      			文字
      			<!-- 路由容器 -->
      			<router-view></router-view>
      		</div>
      	</body>
      	<script>
      		// 路由表
      		let router = new VueRouter({
      			routes: [{
      				path: '/a/:id',
      				name: 'a',
      				component: {
      					template: '<div>/a {{$route.params.id}}</div>'
      				}
      			}, {
      				path: '/b/:id',
      				name: 'b',
      				component: {
      					template: '<div>/b {{$route.params.id}}</div>'
      				}
      			}]
      		});
      
      		let vm = new Vue({
      			el: '#div1',
      			data: {},
      			router,
      			methods: {
      				fn1() {
      					this.$router.push('/a/18');
      				},
      				fn2() {
      					this.$router.push({
      						name: 'b',
      						params: {
      							id: 20
      						}
      					});
      				}
      			},
      			watch: {
      				$route(value, old_value) {
      					console.log(value, old_value);
      				}
      			}
      
      		})
      	</script>
      </html>
      
      打印顺序 console.log(value, old_value); 在这里插入图片描述
  • 导航守卫
    • 监视 和控制

9.7 多视图

  • 使用 name 属性给视图起名(命名视图),如: <router-view name="header"></router-view>

  • 可以有一个不给名字,默认为 default

    • {
      	path: '/',
      	name: 'inddex',
      	components: {
      		default: indexCmp,
      		header: headerCmp,
      		footer: footerCmp
      	}
      }
      
  • 案例:

    <!DOCTYPE html>
    <html lang="zh">
    	<head>
    		<meta charset="UTF-8">
    		<title></title>
    		<script src="../vue.js" harset="utf-8"></script>
    		<script src="../vue-router.js" charset="utf-8"></script>
    
    	</head>
    	<body>
    		<div id="div1">
    			<router-link to="/">首页</router-link>
    			<router-link to="/news">新闻</router-link>
    			<router-link to="/user">用户</router-link>
    
    			<router-view name="header"></router-view>
    			<router-view></router-view>
    			<router-view name="footer"></router-view>
    		</div>
    	</body>
    	<script>
    		let indexCmp = {
    			template: '<div>首页</div>'
    		};
    		let newsCmp = {
    			template: '<div>新闻</div>'
    		};
    		let userCmo = {
    			template: '<div>用户</div>'
    		};
    		let headerCmp = {
    			template: '<div>头部</div>'
    		};
    		let footerCmp = {
    			template: '<div>底部</div>'
    		};
    
    		let router = new VueRouter({
    			routes: [{
    				path: '/',
    				name: 'inddex',
    				components: {
    					default: indexCmp,
    					header: headerCmp,
    					footer: footerCmp
    				}
    			},{
    				path: '/news',
    				name: 'inddex',
    				components: {
    					default: newsCmp,
    					header: headerCmp,
    					footer: footerCmp
    				}
    			},{
    				path: '/user',
    				name: 'inddex',
    				components: {
    					default: userCmo,
    					header: headerCmp,
    					footer: footerCmp
    				}
    			}]
    		})
    		let vm = new Vue({
    			el: '#div1',
    			data: {},
    			router
    		})
    	</script>
    </html>
    

    在这里插入图片描述

9.8 嵌套路由

  • 文件目录
    在这里插入图片描述

  • 初始化项目cnpm init -y

  • 安装环境 cnpm i vue vue-router -D

  • webpack.config.js

    const path = require('path');
    
    module.exports = {
        mode: 'development',
        entry: './src/vm.js',
        output: {
            path: path.resolve(__dirname, 'dest'),
            filename: 'bundle.min.js'
        }
    }
    
  • vm.js

    import Vue from 'vue/dist/vue.esm';
    import VueRouter from 'vue-router';
    // 引入路由表
    import router from './router';
    
    // vue-router 需要挂在到 vue
    Vue.use(VueRouter);
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        router:router
    });
    
  • router.js

    import VueRouter from 'vue-router';
    import Header from './components/headers';
    import Home from './components/home';
    import News from './components/news'
    import News1 from './components/news1'
    import News2 from './components/news2'
    
    
    export default new VueRouter({
        routes: [{
            path: '/index',
            name: '',
            components: {
                header: Header,
                default: Home
            }
        }, {
            path: '/news',
            name: 'news',
            components: {
                header: Header,
                default: News
            },
            // 子路由
            children: [
                {
                    path: '/news1',
                    name: 'news1',
                    components: {
                        default: News1
                    }
                },{
                    path: '/news2',
                    name: 'news2',
                    components: {
                        default: News2
                    }
                }
            ]
        }]
    });
    
  • header.js

    export default {
        template: `
      <div class="nav">
        <router-link class="nav-item" to="/index">首页</router-link>
        <router-link class="nav-item" to="/news">新闻</router-link>
      </div>
      `
    }
    
  • home.js

    export default {
        template:`
            <div>
                首页
            </div>
        `
    }
    
  • news.js 这里面做了路由嵌套

    export default {
        template: `
            <div>
                <router-link :to="{name:'news1'}">新闻一</router-link>
                <router-link :to="{name:'news2'}">新闻二</router-link><br>
                <h1>新闻</h1>
                <router-view></router-view>
            </div>
        `
    }
    
  • news1.js

    export default {
        template:`
            <div>
                新闻1
            </div>
        `
    }
    
  • news2.js

    export default {
        template:`
            <div>
                新闻2
            </div>
        `
    }
    
  • index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1">
            <router-view name="header"></router-view>
            <router-view></router-view>
        </div>
    </body>
    <script src="dest/bundle.min.js"></script>
    </html>
    
  • 结果
    在这里插入图片描述

10. 数据交互

  • get请求

    • vm.js
      import Vue from 'vue/dist/vue.esm';
      
      let vm = new Vue({
          el: '#div1',
          data: {
              src: '',
              loaded: false
          },
          async created() {
              let res =await fetch('http://localhost:8080/api/demo');
              let data =await res.json();
      
              console.log(data);
          },
          template: `
              <div>
                 <img :src="src" alt="" width="200"/>
              </div>
          `
      })
      
      在这里插入图片描述
  • post 请求 手动使用 FormData 添加数据

    • vm.js
      import Vue from 'vue/dist/vue.esm';
      
      let vm = new Vue({
          el: '#div1',
          data: {
              result: 0,
          },
          async created() {
              let formdata = new FormData();
              formdata.append('a', 10);
              formdata.append('b', 20);
      
              let res = await fetch('http://localhost:8080/api/post_demo', {
                  method: 'post',
                  body: formdata
              });
              let data = await res.json();
              this.result = data;
          },
          template: `
              <div>
                 {{result}}
              </div>
          `
      })
      
      在这里插入图片描述
  • post 使用表单

    • vm.js
      import Vue from 'vue/dist/vue.esm';
      
      let vm = new Vue({
          el: '#div1',
          data: {
              a: 0,
              b: 0,
              result: 0
          },
          async created() {
      
          },
          methods: {
              async fn_submit() {
                  console.log(this.$refs);
                  let form = this.$refs['form1'];
                  let formdata = new FormData(this.$refs['form1']);
      
                  let res = await fetch(form.action, {
                      method: form.method,
                      body: formdata
                  });
                  let data = await res.json();
                  this.result = data;
              }
          },
          template: `
              <div>
                  <form ref="form1" @click.prevent="fn_submit()" action="http://localhost:8080/api/post_demo" method="post">
                      <input type="text" name="a" v-model="a">
                      <input type="text" name="b" v-model="b">
                      {{result}}
                      <input type="submit" value="计算">
                  </form>
              </div>
          `
      })
      
      在这里插入图片描述

11. 组件

组件也是 vm 对象

11.1 局部组件

  • 注: 组件里面 data 是一个函数
    在这里插入图片描述

  • 文件目录
    在这里插入图片描述

  • cmp1.js

    import Vue from 'vue/dist/vue.esm';
    
    let vm = new Vue({
        el: '#div1',
        data: {},
        // 局部组件
        components: {
            cmp1: {
                data(){
                    return {
                        a:10
                    }
                },
                template: `
                    <div>{{a}}</div>
                `
            }
        },
        template:`
            <div><cmp1></cmp1></div>
        `
    })
    
  • index.html 使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1"></div>
    </body>
    <script src="dest/bundle.js"></script>
    </html>
    
  • 在这里插入图片描述在这里插入图片描述

11.2 全局组件

  • 全局组件使用 Vue.component()

  • 文件目录
    在这里插入图片描述

  • cmp1.js

    import Vue from 'vue/dist/vue.esm';
    
    // 全局组件
    Vue.component('cmp1', {
        data() {
            return {
                a: 10,
                b: 20
            }
        },
        template: `
            <div>{{a+b}}</div>
        `
    });
    
  • vm.js

    import Vue from 'vue/dist/vue.esm';
    import './cmp1';
    
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        template:`
            <div><cmp1></cmp1></div>
        `
    })
    
  • webpack.config.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    module.exports = {
        mode: 'development',
        entry: './src/vm.js',
        output: {
            path: path.resolve(__dirname, 'dest'),
            filename: 'bundle.js'
        },
        // 打包html
        plugins: [
            new HtmlWebpackPlugin({
                template: 'index.html'
            })
        ],
        // 配置 webpack-dev-server
        devServer: {
            // 新版本 webpack 不支持 contentBase 应添加下面这段话,已显示目录
            static: {
                directory: __dirname,
            },
            open: true // 是否自动打开浏览器
        }
    }
    
  • 在这里插入图片描述

11.3 组件传参

  • 需要使用 props注册参数,传递过来的数据都是字符串,可以使用:原样传递,如:
    在这里插入图片描述

  • vm.js

    import Vue from 'vue/dist/vue.esm';
    import './cmp1';
    
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        template:`
            <div><cmp1 name="张三" :age="18"></cmp1></div>
        `
    })
    
  • cmp1.js

    import Vue from 'vue/dist/vue.esm';
    
    // 全局组件
    Vue.component('cmp1', {
        props:['name','age'],
        data() {
            return {
                a: 10,
                b: 20
            }
        },
        template: `
            <div>
                姓名:{{name}}
                年龄:{{age+2}}    
            </div>
        `
    });
    

    在这里插入图片描述

11.4 使用 component占位符 动态显示需要的组件

  • vm.js
    import Vue from 'vue/dist/vue.esm';
    import './cmp1';
    
    
    let vm = new Vue({
        el:'#div1',
        data:{
            type:''
        },
        template:`
            <div>
                <input type="text" v-model="type" />
                <component :is="type" name="张三" :age="18"></component>
            </div>
        `
    })
    
    在这里插入图片描述

11.5 组件测试

将组件实例化出来但不显示在页面,可用于组件测试

  • vm.js
    import Vue from 'vue/dist/vue.esm';
    import Cmp1 from './cmp1';
    
    
    let cmp = new Cmp1({
        propsData:{
            name:"张三",
            age:18
        }
    })
    let vm = cmp.$mount();
    console.log(vm.$el);
    
  • cmp1.js
    import Vue from 'vue/dist/vue.esm';
    
    // 全局组件
    let Cmp1 = Vue.component('cmp1', {
        props:['name','age'],
        data() {
            return {
                a: 10,
                b: 20
            }
        },
        template: `
            <div>
                姓名:{{name}}
                年龄:{{age+2}}    
            </div>
        `
    });
    
    export default Cmp1;
    
    在这里插入图片描述

12 slot 插槽

插槽用于决定将所携带的内容,插入到指定的某个位置,从而使模板分块,具有模块化的特质和更大的重用性。插槽显不显示、怎样显示是由父组件来控制的,而插槽在哪里显示就由子组件来进行控制。

  • vm.js
    import Vue from 'vue/dist/vue.esm';
    import MySlot from './my-slot'
    
    let vm=new Vue({
        el:'#div1',
        data:{},
        template:`
            <div>
                <my-slot>
                    文字
                </my-slot>
            </div>
        `
    })
    
  • my-slot.js
    import Vue from 'vue/dist/vue.esm';
    
    // 全局组件
    Vue.component('my-slot', {
        data() {
            return {}
        },
        template: `
            <div>
                <slot />
            </div>
        `
    });
    
  • 在这里插入图片描述

13 命名插槽

  • vm.js
    import Vue from 'vue/dist/vue.esm';
    import MySlot from './my-slot'
    
    
    let vm=new Vue({
        el:'#div1',
        data:{},
        template:`
            <div>
                <my-slot>
                    <template slot="title">
                        <h1>标题</h1>
                    </template>
                    文字
                    <ul>
                        <li></li>
                    </ul>
                </my-slot>
            </div>
        `
    })
    
  • my-slot.js
    import Vue from 'vue/dist/vue.esm';
    
    // 全局组件
    Vue.component('my-slot', {
        data() {
            return {}
        },
        template: `
            <div>
                <slot name="title" />
                <slot />
            </div>
        `
    });
    
  • 在这里插入图片描述

14. 生命周期

在这里插入图片描述

  • created 数据操作
  • mounted 操作元素

15 组件之间的通信

15.1 父子组件之间的通信 —— 直接拿引用 (1)

优点:简单
缺点:耦合度非常高

  • 文件目录
    在这里插入图片描述
① 父级找子级

父级中,直接在子集标签上加 ref,父级可直接通过 this.$refs.ref属性值.数据/方法访问子集中的数据和方法
在这里插入图片描述

  • child.js
    import Vue from 'vue';
    
    export default Vue.component('child', {
        data() {
            return {
                num: 0
            }
        },
        methods: {
            al_a() {
                this.num++;
                console.log('子集方法');
            }
        },
        template: `
            <div>
                <h3>子集</h3>
                {{num}}
            </div>
        `
    })
    
  • parent.js
    import Vue from 'vue';
    import Child from './child';
    
    
    export default Vue.component('parent', {
        methods: {
            fn() {
                // 使用 ref 获取子组件的数据及方法
                this.$refs.c1.al_a();
                console.log(this.$refs.c1.num);
            }
        },
        template: `
            <div>
                <h1>父级 <input type="button" value="+1" @click="fn()"/></h1>
                <child ref="c1"></child>
            </div>
        `
    })
    
  • index.js
    import Vue from 'vue';
    import Parent from './components/parent';
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        components:{
            Parent
        },
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })
    
    在这里插入图片描述
② 子级找父级
  • 反向的将父类暴露给子类
  • child.js
    import Vue from 'vue';
    
    // 子 -> 父
    export default Vue.component('child', {
        props: ['parent'],
        data() {
            return {
                num: 0
            }
        },
        methods: {
            fn() {
                // 调用父类方法
                this.parent.add();
                console.log(this.parent.num);
            }
        },
        template: `
            <div>
                <h3>子集 <input type="button" value="+1" @click="fn()"/></h3>
            </div>
        `
    })
    
  • parent.js
    import Vue from 'vue';
    import Child from './child';
    
    //子 -> 父
    export default Vue.component('parent', {
        data() {
            return {}
        },
        methods:{
            add(){
                console.log("父类方法");
                this.num++
            }
        },
        template: `
            <div>
                <h1>父级 {{num}}</h1>
                <child :parent="this"></child>
            </div>
        `
    })
    
  • index.js
    import Vue from 'vue';
    import Parent from './components/parent';
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        components:{
            Parent
        },
        template:`
            <div>
                <parent></parent>
            </div>
        `
    })
    
    在这里插入图片描述

15.2 父子组件之间的通信 —— 组件事件

降低耦合度

① 父传子
  • parent.js
    import Vue from 'vue';
    import Child from './child';
    
    export default Vue.component('parent', {
        data() {
            return {}
        },
        methods: {
            fn(){
                this.$refs.c1.$emit('add_num',7);
            }
        },
        template: `
            <div>
                <h1>父级 <input type="button" value="+1" @click="fn()"/></h1>
                <child ref="c1"/>
            </div>
        `
    })
    
  • child.js
    import Vue from 'vue';
    
    export default Vue.component('child', {
        data() {
            return {
                num: 0
            }
        },
        methods: {},
        template: `
            <div>
                <h3>子集 {{num}}</h3>
            </div>
        `,
        created() {
            this.$on('add_num', function (n) {
                console.log(n);
                this.num += n;
            })
        }
    })
    
    在这里插入图片描述
② 子传父
  • parent.js
    import Vue from 'vue';
    import Child from './child';
    
    export default Vue.component('parent', {
        data() {
            return {
                num: 0
            }
        },
        methods: {
            fn() {
                this.$refs.c1.$emit('add_num', 7);
            }
        },
        template: `
            <div>
                <h1>父级 {{num}}</h1>
                <child :parent="this"/>
            </div>
        `,
        created() {
            this.$on('add_num', function (n) {
                this.num += n;
            })
        }
    })
    
  • child.js
    import Vue from 'vue';
    
    export default Vue.component('child', {
        props: ['parent'],
        data() {
            return {
                num: 0
            }
        },
        methods: {
            fn() {
                this.parent.$emit("add_num", 2);
            }
        },
        template: `
            <div>
                <h3>子集 <input type="button" value="+1" @click="fn()"/></h3>
            </div>
        `
    })
    
    在这里插入图片描述

16. webpack 打包 vue2.0

  • 文件目录
    在这里插入图片描述

  • 安装环境:cnpm i vue-loader vue-style-loader vue-html-loader vue-template-compiler -D

  • vue-loader 解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理。

  • vue-style-loader 解析 vue 内部 style;将外部 css 和 vue的css 处理到一起

  • vue-html-loader 解析 vue 内部 template

  • vue-template-compiler 编译器,将vue组件编译出来

  • webpack.config.js

    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    
    module.exports = {
        mode: 'development',
        entry: './src/index.js',
        output: {
            path: path.resolve(__dirname, 'dest'),
            filename: 'bundle.js'
        },
        module:{
            rules:[
                {test:/\.css$/i,use:['vue-style-loader','css-loader']},
                {test:/\.vue$/i,use:'vue-loader'}
            ]
        },
        resolve:{
            alias:{
                'vue':'vue/dist/vue.esm'
            }
        },
        // 打包html
        plugins: [
            new HtmlWebpackPlugin({
                template: 'index.html'
            }),
            new VueLoaderPlugin()
        ],
        // 配置 webpack-dev-server
        devServer: {
            // 新版本 webpack 不支持 contentBase 应添加下面这段话,已显示目录
            static: {
                directory: __dirname,
            },
            open: true // 是否自动打开浏览器
        }
    }
    
  • cmp1.vue

    <template>
        <div class="box">
            cmp1
        </div>
    </template>
    
    <script>
        export default {
            name: 'cmp1', // 可选;调试时候,报错的时候会报这个 name,没有就报文件名,利于vue调试工具的使用
            data() {
                return {
    
                }
            },
        }
    </script>
    // 添加 scoped 表示样式只在当前起作用
    <style lang="css" scoped>
        
        .box{
            width:200px;
            height: 200px;
            background: yellow;
        }
    </style>
    
  • index.js

    import Vue from 'vue';
    import Cmp1 from './components/cmp1.vue'
    
    let vm = new Vue({
        el:'#div1',
        data:{},
        components:{
            Cmp1
        },
        template:`
            <div>
                <Cmp1 />
            </div>
        `
    })
    

    在这里插入图片描述

17. vue-router(vue2.0)

了解 2.0 组件写法及 vue-router 基本使用

  • 文件结构
    在这里插入图片描述
  • index.js
    import Vue from 'vue';
    import App from './App.vue';
    import router from './routers'
    
    let vm = new Vue({
        el: '#div1',
        data: {},
        template: '<App />',
        router,//路由表
        components: {
            App
        }
    })
    
  • routers / index.js
    import Vue from 'vue';
    import Router from 'vue-router';
    import Index from '@/index.vue';
    import News from '@/news.vue';
    
    Vue.use(Router);
    
    export default new Router({
        routes: [{
                path: '/',
                name: 'index',
                component: Index
            },
            {
                path: '/news',
                name: 'news',
                component: News
            }
        ]
    })
    
  • app.vue
    <template>
        <div>
            <router-link to="/">首页</router-link>
            <router-link to="/news">新闻</router-link>
            <router-view></router-view>
        </div>
    </template>
    
    <script>
        export default {
            name:'app',
            data() {
                return {
                    
                }
            },
        }
    </script>
    
    <style lang="css">
    
    </style>	
    
  • webpack.config.js
    const path = require('path');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    
    module.exports = {
        mode: 'development',
        entry: './src/index.js',
        output: {
            path: path.resolve(__dirname, 'dest'),
            filename: 'bundle.js'
        },
        module:{
            rules:[
                {test:/\.css$/i,use:['vue-style-loader','css-loader']},
                {test:/\.vue$/i,use:'vue-loader'},
                {test:/\.less$/i,use:['vue-style-loader','css-loader','less-loader']}
            ]
        },
        resolve:{
            alias:{
                'vue':'vue/dist/vue.esm',
                '@':path.resolve(__dirname,'src/components/')
            }
        },
        // 打包html
        plugins: [
            new HtmlWebpackPlugin({
                template: 'index.html'
            }),
            new VueLoaderPlugin()
        ],
        // 配置 webpack-dev-server
        devServer: {
            // 新版本 webpack 不支持 contentBase 应添加下面这段话,已显示目录
            static: {
                directory: __dirname,
            },
            open: true // 是否自动打开浏览器
        }
    }
    
  • index.vue
    <template>
        <div>
            index
        </div>
    </template>
    
    <script>
    export default {
        name:"index",
        data() {
            return {
                
            }
        },
    }
    </script>
    
    <style lang="css">
        
    </style>
    
  • news.vue
    <template>
        <div>
            news
        </div>
    </template>
    
    <script>
    export default {
        name:'news',
        data() {
            return {
                
            }
        },
    }
    </script>
    
    <style lang="css">
        
    </style>
    
  • 结果
    在这里插入图片描述

18. vue-cli(启动器 / 脚手架)

  • 安装:cnpm i vue-cli -g
  • 初始化项目 vue init webpack project1
    在这里插入图片描述
  • 项目结构
    在这里插入图片描述

19. vuex

官网:Vuex

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值