funnycoderstar的个人主页
funnycoderstar / vue-demo Goto Github PK
View Code? Open in Web Editor NEW1.vue源码解析 2.从0开始实现一个vue
License: MIT License
1.vue源码解析 2.从0开始实现一个vue
License: MIT License
hash模式(vue-router默认hash模式)就是看到路由上面会有一个 #
号, 例如http://localhost:8800/#/
; javascript通过hashChange事件来监听url的变化
history模式,就是直接匹配的/
, 这种模式充分利用 history.pushState
API来完成URL跳转而无需重新加载页面
const router = new VueRouter({
// 使用HTML5的History路由模式
mode: 'history',
routes: [...]
})
history模式, 需要后端配置支持, 因为我们的应用是单页应用, 后端如果没有配置, 访问 http://localhost:8800/home
就是404;
后端需要配置在接收到所有的请求后, 都会指向同一个index.html
beforeEach和afterEach
router.beforeEach((to, from, next) => {
window.document.title = to.meta.title;
next();
})
function addELementToBody(el) {
if (document.body) {
document.body.appendChild(el);
} else {
window.onload = function () {
document.body.appendChild(el);
};
}
}
function setTitle(title = '') {
if (title) {
window.document.title = title;
// 兼容IOS下的微信
if (/ip(hone|od|ad)/i.test(navigator.userAgent)) {
const i = document.createElement('iframe');
i.src = '/favicon.ico';
i.style.display = 'none';
i.onload = function () {
setTimeout(() => {
i.remove();
}, 9);
};
addELementToBody(i);
}
return Promise.resolve();
}
return Promise.reject('请传递title参数');
};
export default setTitle;
router.afterEach((to, from, next) => {
window.scrollTo(0, 0);
})
router.beforeEach((to, from, next) => {
if(window.localStorage.getItem('token')) {
next();
} else {
next('/login');
}
})
next参数为false时, 可以取消导航, 设置为具体的路径可以导航到指定的页面;
正确的使用好导航钩子可以实现一些全局性的功能, 而且便于维护
如果使用babel, 则需要添加 syntax-dynamic-import
该插件
const Foo = () => import('./Foo.vue')
使用了异步路由之后, 编译出来的每个页面的js都叫做chunk(块),默认的chunk都是以0, 1, 2, 3 ... 来命名的, 这样开发的时候不太方便看出具体是哪个模块的chunk, 我们可以给每个chunk都进行命名;
在webapck配置的出口output里通过设置chunkFilename字段修改chunk命名:
{
output: {
publicPath: '/dist/',
// [hash:8] 修改为8位数的hash值
filename: '[name].[hash:8].js',
chunkFilename: '[name].[hash:8].chunk.js'
},
}
有了chunk后, 在每个页面(.vue文件)里写的样式也需要配置后才会打包进main.css, 否则仍然会通过JavaScript动态创建<style>标签的形式写入.配置插件
plugins: [
new ExtractTextPlugin({
filename: '[name].[hash:8].css',
allChunks: true
}),
]
使用命名chunk, 一个特殊的注释语法来提供chunk name
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
命名相同的webapck会打包到同一个chunk下;
.babelrc的配置
{
"presets": ["stage-3", "env"],
"plugins": ["transform-runtime", "syntax-dynamic-import"],
// "comments": false,
"env": {
"production": {
"plugins": [
["transform-remove-console"]
]
}
}
}
"comments": false, 该项一定不要保留,因为会把注释的部分去掉, 但是命名chunk规则是根据注释来判断的;
在路由列表的最下面加上如下代码
new Router({
routes: [{
// 此处省略N个路由
{
name: '404',
path: '/404',
component: () => import('./notFound.vue')
},
{
path: '*', // 此处需特别注意至于最底部
redirect: '/404'
}
}]
})
vue初始化主要干了几件事情
hash模式就是 带有 # 值, #后面的路径服务器端并不会收到, 因为这是前端路由, a.com/#/about, 后端收到的只是a.com/
history模式就是没有#值, history模式下url都是路径的一部分, a.com/about, 后端收到的就是a.com/about
举例说明:
单页应用的入口是index.html, 对应a.com
点击页面的某个按钮跳转到about页面, 对应a.com/about这个路由
单纯只跳转页面而不刷新, 因为不会重新请求后端, 不会出现任何问题, 但是我在 a.com/about这个路由对应的页面下刷新页面, 页面会报404, 因为刷新页面会重新请求服务器上的资源, 而在服务器上找不到 a.com/about对应的资源, 所以会报404, 找不到该资源
我们需要在服务器上配置, a.com/xxx 资源都重定向到index.html页面(即单页应用的入口), 就是斜杠后面所有的资源都重定向到首页;
webpack中的devServer.historyApiFallback选项就可以配置history模式下页面都指向哪些页面, 使用webpack在本地起的服务可以考虑使用, 具体怎么用如何用还要看具体需求如何
遇到的一些问题:
<router-view></router-view>
而没有其他内容时,打开页面为空白(建议一定要在路由中加一个404的路由配置, 不然页面空白, 没有任何报错, 一开始遇到可能得排查一下才能定位到是路由没有匹配上)path: '/'
对应不上const routes = [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/tickets-info',
name: 'tickets-info',
component: TicketsInfo
},
...
];
// 处理history模式下的地址正常
function dealRoutes (arr) {
for (let i = 0; i < arr.length; i++) {
const fullPath = window.location.pathname + arr[i].path.replace(/\//, '');
arr[i].path = fullPath;
}
return arr;
}
export default new Router({
mode: process.env.NODE_ENV === 'development' ? 'hash' : 'history',
routes: process.env.NODE_ENV === 'development' ? routes : dealRoutes(routes)
});
采用 Rewrite + proxy_pass的方式解决
proxy_pass只转发路由, Rewrite去处理后面具体的路径
server {
listen 80;
server_name b.com;
location / {
try_files $uri $uri/ /pc.html;
alias /Users/wangyaxing/test/dist/;
index pc.html;
}
}
try_files的含义是 尝试去匹配文件 $uri $uri/, 如果 匹配不上, 则走最后配置的匹配规则
server {
listen 80;
server_name b.com;
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
rewrite ^(.*) /app/test/pc.html break;
proxy_pass https://a.com;
}
location /m/ {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-NginX-Proxy true;
rewrite ^(.*) /app/test/m.html break;
proxy_pass https://a.com
}
}
在全局中注册
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus();
}
});
在组件中注册
export default {
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus();
}
}
}
};
钩子函数
钩子函数参数
{foo: true, bar: true}
<template>
<div>
<input type="text" v-focus>
<div v-test:msg.a.b="message"></div>
</div>
</template>
<script>
export default {
data () {
return {
message: 'some text'
};
},
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus();
}
},
test: {
bind: function (el, binding, vnode) {
var s = JSON.stringify;
el.innerHTML =
'name: ' + s(binding.name) + '<br>' +
'value: ' + s(binding.value) + '<br>' +
'expression: ' + s(binding.expression) + '<br>' +
'argument: ' + s(binding.arg) + '<br>' +
'modifiers: ' + s(binding.modifiers) + '<br>' +
'vnode keys: ' + Object.keys(vnode).join(', ');
}
}
}
};
</script>
在大多数使用场景, 我们会在bind钩子里绑定一些事件, 比如在document上用addEventListener绑定, 在unbind里用removeEventListener解绑
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.