Vue-Router和Vue.js响应式原理

1,428 阅读1分钟

vue-router使用步骤

前提:npm install vue-router 或者 vue add router

  1. 在router/index.js中通过Vue.use()方法注册vue-router组件(如果这个组件是一个方法,那么直接调用这个函数来注册插件,如果是一个对象,那么会调用该对象的install方法来注册插件)
  2. 创建router对象(根据路由规则)
  3. 在main.js中先导入创建好的router对象,然后通过new Vue({router}) 来注册router对象
  4. 在App.vue中创建路由组件的占位符,然后通过创建一些链接

动态路由

场景:在写路由规则的时候,会在路由地址后面加参数,比如/:id,常常伴随路由懒加载一起使用来提升性能(路由懒加载:点击商品链接跳转到商品详情的时候,在点击之前不加载详情的内容,点击后才会加载详情内容)

动态路由传参的方式:

方式一: 通过当前路由规则,获取数据$route.params.id

数据响应式

  • 数据模型仅仅是普通的JavaScript对象,而当我们修改数据时,视图会进行更新,避免了繁琐的DOM操作,提高开发效率
  • vue2中的响应式原理是通过Object.defineProperty来实现的,vue3中的响应式原理是通过Proxy来实现的
  • vue的响应式机制中使用了观察者模式

双向绑定

  • 数据改变,视图改变;视图改变,数据也随之改变
  • 我们可以使用v-model在表单元素上创建双向数据绑定

数据驱动是vue最独特的特性之一

  • 开发过程中仅需要关注数据本身,不需要关心数据是如何渲染到视图

数据劫持(Object.defineProperty)

  • 当访问或设置vm中的成员的时候,做一些干预操作

Object.defineProperty和new Proxy

  • Object.defineProperty 浏览器兼容ie8以上(不兼容ie8)
<!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>file-loader</title>
</head>
<body>
	<div id="app">hello</div>
  <script>
  	let data = {
  		msg: 'hello',
  		count: 10
  	}
  	let vm = {}

	proxyData(data)
  	function proxyData(data) {
  		Object.keys(data).forEach(key => {
  			Object.defineProperty(vm, key, {
			  		enumberable: true,
			  		configurable: true,
			  		get() {
			  			console.log('get:', data[key])
			  			return data.msg
			  		},
			  		set(newValue) {
			  			console.log('set:', newValue)
			  			if(newValue === data[key]) return
			  			data[key] = newValue
			  			document.querySelector("#app").textContent = data[key]
			  		}
			  	})
  		})
  	}
  	
  </script>
</body>
</html>

Proxy

  • 直接监听对象,而非属性
  • ES6中新增,IE不支持,性能由浏览器优化
<!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>file-loader</title>
</head>
<body>
	<div id="app">hello</div>
  <script>
  	let data = {
  		msg: 'hello',
  		count: 10
  	}
  	let vm = new Proxy(data, {
  		get(target, key) {
  			console.log('get:', target, target[key])
  			return target[key]
  		},
  		set(target, key, newValue) {
  			console.log('set:', key, newValue)
  			if(target[key] === newValue) return
  			target[key] = newValue
  			document.querySelector("#app").textContent = target[key]
  		}
  	})
  	
  </script>
</body>
</html>

创建对象的方式

  • let a = {}
  • let a = Object.create(null)
    • 小括号里的值是用来设置对象的原型,可以把对象的原型设置为null,表示这个对象没有原型属性,因此在不需要原型属性的情况下这么写提升了性能

发布订阅模式

  • $on: 订阅
  • $emit: 订阅
  • 自定义事件,以下代码模拟自定义事件的实现机制
<script>
  	class EventEmitter {
  		constructor() {
  			this.subs = Object.create(null)
  		}

  		$on(eventType, handler) {
  			this.subs[eventType] = this.subs[eventType] || []
  			this.subs[eventType].push(handler)
  		}

  		$emit(eventType) {
  			if(this.subs[eventType]) {
  				this.subs[eventType].forEach(handler => {
  					handler()
  				})
  			}
  		}
  	}
  	let em = new EventEmitter()
  	em.$on('click', () => {
  		console.log(1111)
  	})
  	em.$on('click', () => {
  		console.log(22222)
  	})

  	em.$emit('click')
  </script>

观察者模式

观察者模式是没有事件中心的,他的订阅者与发布者之间是相互依赖的。而发布订阅模式是由统一调度中心调用,因此发布者和订阅者不需要知道对方的存在,不会互相依赖