vue访问url执行流程
index.html -> app.js -> App.vue -> router(index.js) -> components
1、index.html
浏览器访问项目,最先访问的是index.html文件。
其中<div id="app"></div> 表示自动挂载
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>后台管理系统</title>
<link href="//xxx.com/static/css/vue.css" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<!-- 打包构建的文件 -->
<script type="text/javascript" src="//xxx.com/static/js/manifest.js"></script>
<script type="text/javascript" src="//xxx.com/static/js/vue.js"></script>
<script type="text/javascript" src="//xxx.com/static/js/router.js"></script>
<script type="text/javascript" src="//xxx.com/static/js/vendor.js"></script>
<script type="text/javascript" src="//xxx.com/static/js/app.js"></script>
</body>
</html>
2、app.js
app.js作为项目的入口文件,在运行中会找到实例需要挂载的位置,即index.html中id="app"。
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app', <!-- 在index.html中找到挂载点 -->
router,
components: { App }, <!-- 表示挂载的局部组件为App.vue -->
template: '<App/>'
})
3、App.vue
vue组件由html、js、css组成,App.vue为根组件,通过router-view加载其他组件。
<template> <!-- html -->
<div id="app">
<img src="./assets/logo.png">
<router-view/>
</div>
</template>
<script> <!-- js -->
export default {
name: 'App'
}
</script>
<style> <!-- css -->
#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>
4、router/index.js
配合router-view使用,会根据访问的url去加载对应的vue组件。
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'helloWorld',
component: helloWorld
},
{
path: '/query',
name: 'query',
component: query
}
]
})
问:App.vue中router-view是如何根据url中的路径如https://xxx.com/query去访问指定的路由/query的?
VueRouter的history属性实例化的时候会添加popstate或hashchange事件监听。
HTML5History
window.addEventListener('popstate', function (e) {
var current = this$1.current;
// Avoiding first `popstate` event dispatched in some browsers but first
// history route not updated since async guard at the same time.
var location = getLocation(this$1.base);
if (this$1.current === START && location === initLocation) {
return
}
this$1.transitionTo(location, function (route) {
if (expectScroll) {
handleScroll(router, route, current, true);
}
});
});
HashHistory
window.addEventListener(supportsPushState ? 'popstate' : 'hashchange', function () {
var current = this$1.current;
if (!ensureSlash()) {
return
}
this$1.transitionTo(getHash(), function (route) {
if (supportsScroll) {
handleScroll(this$1.router, route, current, true);
}
if (!supportsPushState) {
replaceHash(route.fullPath);
}
});
});
vue底层原理
编译器+运行时
**
**
编译器
编译器其实是一段程序,用来将源代码翻译成目标代码。
对于vue.js模板编译器来说,源代码就是组件的模板,而目标代码是能够在浏览器平台上运行的JavaScript代码,或其他拥有JavaScript运行时的平台代码,Vue.js模板编译器的目标代码其实就是渲染函数。
详细来说,Vue.js模板编译器会首先对模板进行词法分析和语法分析,得到模板AST。接着,将模板AST转换为JavaScript AST。最后,根据JavaScript AST生成JavaScript代码,即渲染函数代码。
1、解析:通过封装parse函数来完成对模板的词法分析和语法分析,得到模板AST, parse函数接收字符串模板作为参数,并将解析后得到的AST作为返回值返回。 在语义分析的基础上,我们即可得到模板 AST。
2、转换和优化:因为Vuejs 模板编译器的最终目标是生成渲染函数,而渲染函数本质上是JavaScript代码,所以我们需要将模板AST转换成用于描述渲染函数的JavaScript AST 。可以封装transform函数来完成模板AST到JavaScriptAST的转换工作 。
3、生成渲染函数:有了JavaScrpt AST后,我们就可以根据它生成渲染函数了,这一步可以通过封装generate函数来完成。generate函数会将渲染函数的代码以字符串的形式返回,并存储在code的常量中。
const templateAST = parse(template)
const jsAST = transform(templateAST)
const code = generate(jsAST)
运行时
1、依赖收集
依赖收集准备阶段——Observer、Dep的实例化。
依赖收集触发阶段——Wather实例化、访问数据、触发依赖收集。
2、派发更新
对象属性修改触发set,派发更新。
数组调用方法,派发更新。
computed依赖收集
**
**
computed派发更新
派发相对来说比较简单了~跟响应式的派发更新基本一致。
user Watcher依赖收集
参考:
总结vue的6大高级特性——及浅谈一下nextTickkeep-alive的原理
学完即用之Vue.extend+$mount改造dialog实践
computed监听Vuex中state对象中的对象属性时,监听不生效的问题