vue的router简单实现和vuex简单实现(学习笔记,有点乱,基于vue-cli脚手架)

1 篇文章 0 订阅
1 篇文章 0 订阅

项目的结构
上面是项目结构!!!
kvue-router.js文件是简单实现vue-router
kvuex.js文件是简单实现vuex
里面有各种注释,学习时候弄的,比较乱,凑合看吧!!!
main.js

import Vue from 'vue'
import App from './App.vue'
// import VueRouter from 'vue-router'
// import Vuex from 'vuex'

import KvueRouter from './kvue-router/kvue-router.js'
import Kvuex from './kvuex/kvuex.js'

import HelloWorld from './views/HelloWorld.vue' //这里一个点,需要引入绝对路径,不能是相对路径
import Home from './views/Home.vue' //注意大小写

// Vue.use(VueRouter);
// Vue.use(Vuex);

//vuex:状态管理模式
//集中管理所有组件的状态
//可预测的状态变化

Vue.use(KvueRouter)
Vue.use(Kvuex)
//vue.use() 传入点必须是函数或者是对象
//如果是对象,对象里面必须有install方法
//vue.use()会把vue对象传入函数或者install方法中
//vue.use()的原理:
//判断传入的是不是对象或者是函数
//判断vue是否注册过这个插件
//判断是否有install方法,如果有直接调用install方法,
// 如果没有,直接把整个plugin当install方法执行

Vue.config.productionTip = false

const routes = [{
		path: '/HelloWorld',
		name: 'HelloWorld',
		component: HelloWorld,
		children: [{
			path: '/info',
			component: {
				render(h) {
					return h('div', "我是info")
				}
			}
		}]
	},
	{
		path: '/Home',
		name: 'Home',
		component: Home
	}
]

const router = new KvueRouter({
	routes
});

const store = new Kvuex.Store({ //单一状态树:一个store实例
	state: { //state:数据源(各种状态)
		count: 1
	},
	getters: { //getters:store的计算属性
		number(state) { //接收一个参数state
			return state.count * 2;
		}
	},
	mutations: { //唯一改变state状态的方法,必须是同步函数
		addcount(state, payLoad) { //接收参数state,payLoad支持对象写法,也可以是一个值
			// console.log(state);
			state.count = state.count + payLoad;
		},
		reducecount(state, payLoad) {
			state.count = state.count - payLoad;
		}
	},
	actions: { //类似mutation,但是可以执行异步函数
		reducecount(context, payLoad) { //接收参数context,payLoad支持对象写法,也可以是一个值
			//也可以直接接收  { commit,dispatch,state,getters }
			// console.log(context, payLoad); //context是一个对象,里面有state,getters,commit,dispatch,rootState,rootGetters

			setTimeout(() => {
				context.commit('reducecount', payLoad)
			}, 1000);
		}
	}

});

new Vue({
	router, //将router实例挂载到vue实例中,可以在插件安装时,注册实例
	store, //将store注入到new Vue({ store }) 中,各个组件中可以直接使用
	//this.$store
	render: h => h(App),
}).$mount('#app')

app.vue

<template>
	<div id="app">
		<router-link to="/HelloWorld">HelloWorld</router-link>
		|
		<router-link to="/Home">Home</router-link>
		|
		<router-link to="/HelloWorld/info">info</router-link>
		<router-view />
		<p>22222222</p>
	</div>
</template>

<script>
	/* eslint-disable */
	export default {
		data() {
			return {
				o: null,
				count: 0
			}
		},
		methods: {


		},
		created() {


		}
		/*
		1、promise的用法
		2、async :事件之前用,会让事件返回一个promise对象,后面可以直接用 .then()  
		   await  :和 async 一起用,在async事件里面用,可以获取promise对象里面的resolve或者reject函数里面的东西  的用法
		3、watch  : immediate:true 侦听开始之后立即调用
					handler:函数,方法名
					deep: true 深层遍历
		*/
	}
</script>

<style>
	#app {
		font-family: Avenir, Helvetica, Arial, sans-serif;
		-webkit-font-smoothing: antialiased;
		-moz-osx-font-smoothing: grayscale;
		text-align: center;
		color: #2c3e50;
		margin-top: 60px;
	}
</style>

home.vue

<template>
	<div>
		我是Home
		<h1>我是count:{{ count }}</h1>
		<button @click="add">增加10</button>
		<button @click="reduce">减少</button>
		<h1>{{ $store.getters.number }}</h1>
		<!-- <router-view></router-view> -->
	</div>
</template>

<script>
	/* eslint-disable */
	export default {
		data() {
			return {

			}
		},
		methods: {
			add() {
				this.$store.commit('addcount', 10);
				//对象风格提交方式
				//this.$store.commit({
				// type:'addcount',
				// amount:10 
				//});
			},
			reduce() {
				this.$store.dispatch('reducecount', 1);
				/*
				this.$store.dispatch({
					type:'reducecount',
					amount:2
				});
				*/
			}
		},
		computed: {
			count() {
				// console.log(this);
				return this.$store.state.count
			}
		},
		mounted() {
			//普通函数的this指向:指向调用他的对象,谁离得近就指向谁
			//构造函数下,指向被创建的对象
			//DOM事件,指向被触发事件的元素
			// 箭头函数的this指向:定义箭头函数的所在的上下文的this,即指向定义函数的对象


		}
	}
</script>

<style>
</style>

hellowWorld.vue

<template>
	<div class="hello">
		我是HelloWorld
		<router-view />
	</div>
</template>

<script>
	/* eslint-disable */
	export default {
		data() {
			return {
				// count:0
			}
		},
		methods: {

		}
	}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
	h3 {
		margin: 40px 0 0;
	}

	ul {
		list-style-type: none;
		padding: 0;
	}

	li {
		display: inline-block;
		margin: 0 10px;
	}

	a {
		color: #42b983;
	}
</style>

kvuex.js

let Vue;
//实现一个store类
class Store {
	constructor(options) { //options是创建实例时传进来的选项
		// console.log(options,111)
		this.$options = options;
		//把state 做响应式处理
		// this.state = new Vue({//Vue初始化的时候会把data里的数据进行初始化,并且代理data里的数据到Vue实例上
		// 	data:{
		// 		state:this.$options.state
		// 	}
		// });
		let computed = {};
		this.getters = {}
		let store = this;
		for (let item in this.$options.getters) {
			let fn = this.$options.getters[item];
			computed[item] = function() {
				// console.log(this)//这里的this是vue对象,因为下面把这个computed放进了vue中
				return fn(store.$options.state);
			}

			//直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
			Object.defineProperty(this.getters, item, {
				//这里把getters里的item定义成都是可读的
				get() {
					// console.log(this)//这里到this指向的是this.getters
					return store._vm[item] //由于_vm里的代理机制,所以可以直接访问到item ,computed里到数据被代理到vue对象上里
				}
			})
		}
		//隐藏state
		this._vm = new Vue({ //存到_vm中
			data: {
				$$state: this.$options.state //$$state 不会被代理
			},
			computed //computed 是一个对象
			// computed:{
			// 	number(){

			// 	}
			// }
		});
		// console.log(this._vm);
		// console.log(this._vm._data.$$state); //this.state 指的时Vue实例,里面有个_data里面的数据是响应式的 _ob_  观察者模式

		//在构造函数里就绑定上下文了
		this.commit.call(this);
		this.dispatch.call(this);
	}
	get state() { //当外面访问this.$store.state 的时候,返回值
		return this._vm._data.$$state
	}
	set state(v) {
		console.error('请使用replaceState()重置')
	}
	//commit事件
	commit(type, payLoad) {
		//获取mutations里面对应的type事件,把payLoad传进去,执行该函数
		let fn = this.$options.mutations[type];
		if (!fn) {
			console.log('mutations不存在')
			return
		}
		fn(this.state, payLoad); //call的作用是:把this改成当前的this,即vuex类
		// fn.call(this,this.state,payLoad)
		//这里试过不加call,没有报错
		//call(this指向,payLoad1,payLoad2,...)
		//apply(this的指向,[payLoad1,payLoad2,...])
		//bind(this的指向,payLoad1,payLoad2,...)()
	}
	//dispatch事件
	dispatch(type, payLoad) {
		//获取mutations里面对应的type事件,把payLoad传进去,执行该函数
		let fn = this.$options.actions[type];
		if (!fn) {
			console.log('mutations不存在')
			return
		}
		fn(this, payLoad);
		//视频里这里报错了,但是我这里没有报错啊,不知道为啥
		// fn.call(this,this,payLoad);//call的作用是:把this改成当前的this,即vuex类
		//这里试过不加call,没有报错
		//call(this指向,payLoad1,payLoad2,...)
		//apply(this的指向,[payLoad1,payLoad2,...])
		//bind(this的指向,payLoad1,payLoad2,...)()
	}
}

function install(Vue_) {
	Vue = Vue_;
	//挂载$store 到Vue实例上,为了可以使用this.$store
	Vue.mixin({
		beforeCreate() {
			//这里到this指向的是组件实例,$options指的是选项
			// console.log(this);
			if (this.$options.store) {
				Vue.prototype.$store = this.$options.store;
			}

		}
	})
}
export default {
	Store,
	install
}

kvue-router.js

/* eslint-disable */
let Vue
//实现一个类
class KvueRouter {
	constructor(options) {
		// console.log(this);//这里对this指的是KvueRouter
		// console.log(options);//这里是指传入Kvuerouter的选项
		this.$options = options;
		// let initPath = window.location.hash.slice(1);
		// Vue.util.defineReactive(this, 'current', initPath);//响应式current
		this.current = window.location.hash.slice(1) || '/';
		Vue.util.defineReactive(this, 'matched', []);
		this.match();
		//监听url的变化,hashchange
		let this_ = this;
		window.addEventListener('hashchange', function() {
			//获取当前的path
			this_.current = window.location.hash.slice(1);
			this_.matched = [];
			this_.match();
		}, false)
	}
	//match方法可以递归遍历路由表,获得匹配的路由关系
	match(routes) {
		routes = routes || this.$options.routes;
		//for ... of  遍历数组 
		//for ... in 遍历对象
		for (let route of routes) {
			if (route.path === '/' && this.current === '/') {
				this.matched.push(routes);
				return;
			}
			if (route.path !== '/' && this.current.indexOf(route.path) != -1) {
				this.matched.push(route);
				if (route.children) {
					this.match(route.children);
				}
				return;
			}
		}
		console.log(this.matched);
	}
}

//挂载一个install方法,在vue.use()的时候调用
KvueRouter.install = function(Vue_) {
	Vue = Vue_;
	// Vue.prototype.$router = router 这里到router应该是router实例,
	// 而router实例挂载到了new vue()里
	//将Vue里的router实例挂载到vue原型上
	//用的时候this.$router
	//但是vue.use()在new Vue()之前执行
	//所以需要  全局混入minix()  把这里到挂载原型执行到时间移到  new vue()  后面
	//才能拿到new vue()里到router实例
	Vue.mixin({
		beforeCreate() {
			// Vue.prototype.$router = this.
			// console.log(this);
			//这里到this指的是组件实例,组件实例指的是:vue根实例,#app的div实例,两个router-link实例
			if (this.$options.router) {
				Vue.prototype.$router = this.$options.router;
			}
			//$options是各种选项,里面有很多东西
		}
	})

	//实现两个组件:router-link  router-view
	Vue.component('router-link', {
		props: {
			to: {
				type: String,
				required: true
			}
		},
		//浏览器中进行大量的DOM操作会让性能很差,所以虚拟DOM产生
		//使用render函数描述虚拟DOM时,
		// 提供一个函数createElement,用来构建虚拟DOM,
		//所以render返回的是VNode(虚拟节点)
		// 后面用diff算法进行比较,更新发生变化的DOM,diff算法只会比较同一层级的DOM元素,不会跨层级比较(比较的是DOM树)
		//没有发生变化的DOM不会进行操作
		//不是全部重绘,所以渲染性能提高,
		//官网上给他起了个名字叫 createElement。
		// 还有约定的简写叫 h, 
		// vm中有一个方法 _c, 也是这个函数的别名
		render(h) {
			//render函数接受两个参数,第一个是创建Vnode,第二个是接受上下文信息
			//h接收参数:
			//第一个是标签名字
			//第二个是标签内容
			//第三个是子节点
			return h(
				'a', {
					attrs: { //attrs:HTML标签的特性
						href: '#' + this.to
					}
				},
				this.$slots.default); //这里取的是组件的插槽值: <router-link to="/a">XXX</router-link>
		}
	})
	Vue.component('router-view', {
		render(h) {
			// let component = {render(createElement){return createElement('h1','balabala')}};
			//render(createElement){return createElement('h1','balabala')}
			//这里返回的是一个VNode,节点描述对象
			//函数没有function,需要写在对象里
			//h()的参数可以是String,Object,还能传sync函数,但是没有成功理解
			//这里的component,是个描述节点的对象

			// console.log(this.$router);
			//this指的是当前组件


			//$router之前被挂载到Vue的原型上了,所以组件继承了Vue,也有$router
			//拿到的this.$router是Kvuerouter实例,再拿$options
			let current = this.$router.current;
			let component = null;
			// let router = this.$router.$options.routes.find(item => item.path === current)

			//find函数
			//返回成功匹配的第一个元素
			//没有就返回undefined
			//不改变原始数组值
			//find((currentValue,index,arr)=>{  })
			this.$vnode.data.routerView = true; //标记每个router-view是routerView = true
			let depth = 0;
			let parent = this.$parent; //获取当前vnode的父级
			// console.log(this)//这里指向Proxy,猜测是指的当前的vnode
			while (parent) {
				const vnodeData = parent.$vnode && parent.$vnode.data;
				if (vnodeData && vnodeData.routerView) {
					depth++;
				}
				// console.log(this);
				parent = parent.$parent;
			}
			let route = this.$router.matched[depth];
			if (route) {
				component = route.component;
			}
			// console.log(router, component);
			return h(component)

		}
	})
}
export default KvueRouter
//嵌套路由思想:
//首先确定当前的深度,作为router-view
//做一个响应式的matched数组,里面是当前路径和routes匹配的关系
//例如: home/info
//info是第一层,前面有一个home,是第零层
//在match方法里根据当前路径对路由表进行递归遍历(matched是响应式数组,虽然current不是响应式数据)
//有children的,进行递归match
// 然后把匹配到当前的路径的对象push到matched数组里
//匹配home/info的路径有数组里有两个值:一个是home一个是info,然后去拿相应的depth的数组的component
//进行渲染就好了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值