《尤雨溪教你写vue》课程笔记

1. 响应性

工作原理:

  • 使用ES5的Object.definePropery,重写啦所有属性的getter和setter方法
  • 实际上就是依赖跟踪的基本形式
    简易getter和setter
const obj = { foo: 123}
convert(obj)
function convert(obj) {
	Object.keys(obj).forEach(key =>{
		let internalValue = obj[key]
		Object.defineProperty(obj,key,{
			get(){
				return internalValue
			}
			set(newValue){
				internalValue = newValue
			}
		})
	})
}

依赖收集

window.Dep = class Dep{
	constructor(){
		this.subscribers = new Set()
		
	}
	depend(){
		if(activeUpdate){
			this.subscribers.add(activeUpdate)
		}
	}
	notify(){
		this.subscribers.forEach(sub =>{
			sub()
		})
	}
}
let activeUpdate

function autorun (update){
	function wrappedUpdate(){
		activeUpdate = wrappedUpdate
		update()
		activeUpdate = null
	}
}

const dep = new Dep()
autorun(()=>{
	dep.depend(){
		console.log('updated')
	}
})
dep.notify()

迷你观察者

//依赖收集
class Dep(){
	constructor(){
		this.subscribers = new Set()
	}
	depend(){
		if(updatevalue){
			this.subscribers.add(updatevalue)
		}
	}
	notify(){
		this.subscribers.forEach(sub => {
			sub()
		})
	}
}

let updatevalue
// 订阅信息
function autorun(update){
	function wrappedUpdate(){
		updatevalue = wrappedUpdate
		update()
		updatevalue = null
	}
	
}
//新建依赖
let dep = new Dep()
//监听变化
function observe(obj) {
	Object.keys(obj).forEach(key => {
		let value = obj[key]
		Object.defineProperty(obj,key,{
			get(){
				return value
			}
			set(newValue){
				value = newValue
				dep.notify()
			}
		})
	})
}

const state = {
	count : 0
}

observe(state)

autorun(()=>{
	dep.depend(()={
		console.log('update')
		//渲染
	})
})

state.count ++
2. 插件
  • vue.mixin
const myPlugin  = >{
	install(Vue){
		Vue.mixin({
			created(){
				if(this.$options.rules){
					Object.keys(this.$options.rules).forEach(key=>{
						const rule = this.$options.rules[key]
						this.$watch[key,(newValue)=>{
							const result = rule.validate(newValue)
							if(!result){
								console.log(rule.message)
							}
						}]
					})
				}
			}
		})
	}
}

Vue.use(myPlugin)
const vm = new Vue({
	data: {foo: 10},
	rules:{
		validate: value => value > 1,
		message: 'foo must be greater than one'
	}
})
3. 渲染
  • 修改原生dom复杂,产生啦虚拟dom
  • 虚拟dom并不会更快,只是原生dom的局限性的一个方法
  • 它提供啦以声明方式构成你想要的dom的结构
  • 渲染逻辑从真实的dom中分离出来半截取消对真实dom来说等于没有执行
    在这里插入图片描述
    jsx和template区别
  • tempalte更静态有约束力,jsx更动态
  • 渲染api h(‘div’,{class: ‘foo’},‘some text’)
export default {
	render (h) {
		return h('div',{},[...])
	}
}
  • 动态渲染标签组件
<div id="app">
	<foo>
	<example :tag="['h1','h2','h3']">
		<div>foo</div>
	</example>
	</foo>
</div>

<script>
	Vue.Component('example', {
		props: ['tags'],
		functional: true,
		render(h,{props: {tags}}) {
			return h('div',context.props.tags.map((tag,i) => h(tag,i)))
		}
	})
	new Vue({el:'#app'})
</script>
<div id="app">
	<example :ok="ok"></example>
	<button @click="ok = !ok">toggle</button>
</div>

<script>
const Foo = {
	render: h => h('div','foo')
}
const Bar = {
	render: h => h('div','bar')
}
Vue.component('example', {
	props: ['ok'],
	render(h) {
		return this.ok ? h(Foo) : h(Bar)
	}
})

new Vue({
	el: '#app',
	data: {ok: true}
})
</script>
3. 高阶组件
  • 高阶组件对简单组件进行扩展,增强组件功能又不改变组件原来的功能
<div id="#app">
	<smart-avatar username="vuejs" id="foo"></smart-avatar>
</app>

function fetchURL (username,cb){
	setTimeout(()=>{
		cb('https:avatar.githubusercontent.com/u/68342343?v=4&s=200')
	},500)
}
const Avatar = {
	props: ['src'],
	template: '<img :src = "src">'
}
function withAvatarURL(InnerComponent,fetchURL){
	return {
		props: ['username'],
		data(){
			url: 'http://via.placeholder.com/200*200'
		},
		created(){
			fetchUrl(this.username,url=> {
				this.url = url
			})
		},
		render(h) {
			return h(InnerComponent,{
				props: {
					src: this.url,
					attrs: this.$attrs
				}
			},this.$slots.default)
		}
	}
}
const SmartAvatar = withAvatarURL(Avatar)

new Vue({
	el: '#app',
	components: {SmartAvatar}
})
4. 状态管理
  • 父组件传子组件用props
  • props有限制,当父组件需要传递的值改变时,props传到子组件的值并不会改变
  • 共享对象
const state = {
	count: 0
}

const Counter = {
	data(){
		return state
	},
	render(h){
		return h('div',this.count)
	}
}

new Vue({
	el: '#app',
	components: {Counter},
	methods: {
		inc() {
			this.count++
		}
	}
})
const state = new Vue({
	data: {
		count: 0
	},
	methods: {
		inc() {
			this.count++
		}
	}
})

const Counter = {
	render: h => h('div',state.count)
}

new vue({
	el:'#app',
	components: {
		Counter
	},
	methods: {
		inc(){
			state.inc()
		}
	}
})
  • mutations
function createStore ({state,mutations}) {
	return new Vue({
		data: { state },
		methods: {
			commit(mutationType){
				mutations[mutationType](this.state)
			}
		}
	})
}
const store = createStore({
	state: {count: 0},
	mutations: {
		inc (state){
			state.count++
		}
	}
})
const Counter = {
	render (h) {
		return h('div',store.state.count)
	}
}
new Vue({
	el:'#app',
	components: { Counter},
	methods: {
		inc() {
			store.commit('inc')
		}
	}
})
5.路由
  • 我们需要在应用中将URL保存为响应式状态,为啦我们应用能够响应它的变化
<div id="app">
	<component :is="url"></component>
	<a href="#foo">foo</a>
	<a href="#bar">bar</a>
</app>
window.location.hash
window.addEventListener('hashchange',() => {
	app.url = window.location.hash.slice(1)
})
const app = new Vue({
	el: '#app',
	data: {
		url: window.location.hash.slice(1)
	},
	components: {
		foo: {template: '<div>foo</div>'},
		bar: {template: '<div>bar</div>'}
	}
})

路由表

const Bar = {template: '<div>bar</div>'}
const NotFound = {template: '<div>not Found!</div>'}

const routeTable = {
	'foo': Foo,
	'bar': Bar
}
window.addEventListener('hashchange',()=>{
	app.url = window.location.hash.slice(1)
})

const app = new Vue({
	el: '#app',
	data: {
		url: window.location.hash.slice(1)
	},
	render (h) {
		return h('div',{
			h(routeTable(this.url) || NotFound),
			h('a',{attrs:{href: '#foo'}}, 'foo'),
			h('a',{attrs:{href: '#bar'}}, 'bar'),
		})
	}
})

正则表达式

  • 动态路径通过正则表达式实现
  • 我们需要一个转换器去利用正则表达式转换
  • 这可以帮助我们在运行时进行解析
  • path-to-regexp 这个库就是一个转换器
'/user/:username'
'/user/123?foo=bar'
{
	path: '/user/123',
	params: { username: '123' },
	query: { foo:'bar' }
}
// keys 填充动态部分
var keys = []
var re = pathToRegexp('/foo/:bar',key)
// re = /^\foo\/([^\/] + ?)\/?$/i
// keys = [{name:'bar',prefix:'/',delimiter:'/',optional: false,repeat: false}]
const keys = []
const regex = pathToRegex('foo/:bar',keys)
const result = regex.exec('/foo/123')
// ['123']
// [{name; 'bar'}]
// {bar:'123'}

动态路由

const Foo = {
	props: ['id'],
	template: `<div>foo with id: {{id}}</div>`
}
// /foo/123
const Bar = {template: `<div>bar</div>`}
cosnt NotFound= {template: `<div>not found!</div>`}
const routeTable = {
	'foo/:id': Foo,
	'bar': bar
	
}
window.addEventListener('hashchange',()=>{
	
})

let compiledRoutes = []
Object.keys(routeTable).forEach(key => {
	// 正则匹配
	var keys = []
	var re = pathToRegexp(path,key)
	const component = routerTable[path]
	compiledRoutes.push({
		component,
		re,
		key
	})
})
compiledRoutes.some(route => {
	const match = route.re.exec(path)
	if(match){
		componentToRender = route.component
		route.key.resuce((segment,index)=>{
			props[segment.name] = match[index + 1]
		})
	}
})
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值