小白回答:hash模式url带#号,history模式不带#号
大牛解答:hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦。
hash与history的区别:
hash | history | |
---|---|---|
url显示 | 有#,很Low | 无#,好看 |
回车刷新 | 可以加载到hash值对应页面 | 一般就是404掉了 |
支持版本 | 支持低版本浏览器和IE浏览器 | HTML5新推出的API |
hash模式
我们先来认识下这位朋友#,这个#就是hash符号,中文名哈希符或锚点,当然这在我们前端领域姑且这么称呼。
然后哈希符后面的值,我们称之为哈希值。OK,接下来我们继续分析他的原理。路由的哈希模式其实是利用了window可以监听onhashchange事件,也就是说你的url中的哈希值(#后面的值)如果有变化,前端是可以做到监听并做一些响应(搞点事情),这么一来,即使前端并没有发起http请求他也能够找到对应页面的代码块进行按需加载。
后来人们给他起了一个霸气的名字叫前端路由,成为了单页应用标配。
history模式
我们先介绍一下H5新推出的两个神器:pushState与replaceState
具体自行百度,简而言之,这两个神器的作用就是可以将url替换并且不刷新页面,好比挂羊头卖狗肉,http并没有去请求服务器该路径下的资源,一旦刷新就会暴露这个实际不存在的“羊头”,显示404。
那么如何去解决history模式下刷新报404的弊端呢,这就需要服务器端做点手脚,将不存在的路径请求重定向到入口文件(index.html),前后端联手,齐心协力做好“挂羊头卖狗肉”的完美特效。
总之,pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应。
history模式下,build之后本地 index.html 打开是无效的。
hash模式下,build之后本地 index.html 打开正常!
父组件向子组件传值:
父组件:
<template>
<div class="parentOne">
<children-item :content="item" v-for="item in list" :key="item.id"></children-item>
</div>
</template>
<script>
import ChildrenItem from "../children/ChildrenOne.vue"
export default {
name: "ParentOne",
data() {
return {
list: [
{ id: "001", title: "这是父组件第一项内容" },
{ id: "002", title: "这是父组件第二项内容" },
{ id: "003", title: "这是父组件第三项内容" }
]
}
},
components: {
"children-item": ChildrenItem
}
}
</script>
<style>
</style>
**在父组件中使用子组件,并且在子组件中添加需要传递的值
:content="item"**
子组件:
<template>
<div class="ChildrenOne">
<ul>
<li v-for="childItem in content">{{childItem}}</li>
<li>{{message}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'ChildrenOne',
props: ["content"],
data() {
return {
message: this.content.id
}
}
}
</script>
<style></style>
在子组件中添加props数组,接收从父组件中传递过来的
content
值,然后就可以在上边的template中像使用data中的数据一样使用props中的接收值,从而实现父组件向子组件的传值
子组件向父组件传值:
子组件向父组件传值这一个技术点有个专业名词,叫做“发布订阅模式”,很明显在这里子组件为发布方,而父组件为订阅方
子组件:
<template>
<div class="ChildrenTwo">
<ul>
<li v-for="childItem in content" @click="ChildrenOnclick()">{{childItem}}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'ChildrenTwo',
props: ["content", "index"],
data() {
return {
}
},
created() {
console.log(this.index);
},
methods: {
ChildrenOnclick() {
console.log(this.index);
// 发布订阅模式
this.$emit("delete", this.index)
}
}
}
</script>
<style>
</style>
在该子组件中中触发li的
click
事件,调用ChildrenOnclick
方法,在该方法中通过使用$emit
方法定义了一个delete
方法,并传递index值给父组件
父组件:
<template>
<div class="parentTwo">
<children-item
:content="item"
:index="index"
v-for="(item,index) in list"
:key="item.id"
@delete="handleParentClick"
>
</children-item>
</div>
</template>
<script>
import ChildrenItem from "../children/ChildrenTwo.vue"
export default {
name: "ParentTwo",
data() {
return {
list: [
{ id: "001", title: "这是父组件第一项内容" },
{ id: "002", title: "这是父组件第二项内容" },
{ id: "003", title: "这是父组件第三项内容" }
]
}
},
methods: {
handleParentClick(index) {
this.list.splice(index, 1);
}
},
components: {
"children-item": ChildrenItem
}
}
</script>
<style>
</style>
在父组件使用子组件时,使用子组件中自定义的
delete
方法实现接收到子组件传递过来的值@delete="handleParentClick"
,调用handleParentClick
方法将传递的值作为参数传入父组件
兄弟(或者没有关系)组件的组件传值:
兄弟组件2:
<template>
<div id="two">
<h3>小弟组件</h3>
<p>
<button @click="say">给大哥说话</button>
</p>
</div>
</template>
<script>
// 引入bus.js进来
import bus from '@/bus.js'
export default {
name: 'Two',
methods: {
// 实现给大哥传递数据的
say () {
// 让bus调用自己的事件
bus.$emit('receive', '1000元保护费')
}
}
}
</script>
<style lang="less" scoped>
#two{
width: 300px;
height: 100px;
border:1px solid greenyellow;
}
</style>
在兄弟组件2小弟组件中,通过
click
事件调用say方法,在say方法里再调用bus.$emit
,向receive
事件传递值1000元保护费
兄弟组件1:
<template>
<div id="one">
<h3>大哥组件</h3>
<span>接收小弟的礼物:{{money}}</span>
</div>
</template>
<script>
// 引入bus.js进来
import bus from '@/bus.js'
export default {
name: 'One',
// 在created中给bus绑定事件,时机最靠前,随时可以响应使用
data () {
return {
// 接收小弟来到数据
money: ''
}
},
created () {
// this:组件实例对象
// 注意:设置为箭头函数
bus.$on('receive', val => {
// val:是其他应用处给传递的数据
// 把获得的数据赋予money
this.money = val
})
}
}
</script>
<style lang="less" scoped>
#one{
width: 300px;
height: 100px;
border:1px solid red;
margin-bottom:20px;
}
</style>
在兄弟组件1大哥组件中,在created()方法里调用
bus.$on
,执行receive
方法,接收小弟组件传递过来的值(1000元保护费
),然后进行其他操作,这样就完成了兄弟组件之间的值传递提一笔:只要没有直接套用关系的组件都是兄弟
MVVM与MVC最大的区别就是:MVVM实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变
进一步理解
一、MVC
MVC允许在不改变视图的情况下改变视图对用户输入的响应方式,用户对View的操作交给了Controller处理,在Controller中响应View的事件调用Model的接口对数据进行操作,一旦Model发生变化便通知相关视图进行更新。
? 如果前端没有框架,只使用原生的html+js,MVC模式可以这样理解。将html看成view;js看成controller,负责处理用户与应用的交互,响应对view的操作(对事件的监听),调用Model对数据进行操作,完成model与view的同步(根据model的改变,通过选择器对view进行操作);将js的ajax当做Model,也就是数据层,通过ajax从服务器获取数据。
二、MVVM
MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。
这里我们拿典型的MVVM模式的代表,Vue,Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化。
整体看来,MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高代码的可重用性。
这里只是简单地说一下区别,详细的可以参考以下文章:
https://www.jianshu.com/p/b0aab1ffad93
https://blog.csdn.net/u013282174/article/details/51220199
https://www.jianshu.com/p/f07cf01056b1
啥也先别说,开局一张图:
Vue的生命周期可以分为以下八个阶段:
beforeCreate 实例创建前
created 实例创建完成
beforeMount 挂载前
mounted 挂载完成
beforeUpdate 更新前
updated 更新完成
beforeDestory 销毁前
destoryed 销毁完成
BeforeCreated:
这个钩子是new Vue()之后触发的第一个钩子,在当前阶段中data、methods、computed以及watch上的数据和方法均不能被访问。
created
这个钩子在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发updated函数。可以做一些初始数据的获取,注意请求数据不易过多,会造成白屏时间过长。在当前阶段无法与Dom进行交互,如果你非要想,可以通过vm.$nextTick来访问Dom。
Beforemounted
这个钩子发生在挂载之前,在这之前template模板已导入渲染函数编译。而当前阶段虚拟Dom已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发updated。
mounted
这个钩子在挂载完成后发生,在当前阶段,真实的Dom挂载完毕,数据完成双向绑定,可以访问到Dom节点,使用$ref
属性对Dom进行操作。也可以向后台发送请求,拿到返回数据。
BeforeUpdate
这个钩子发生在更新之前,也就是响应式数据发生更新,虚拟dom重新渲染之前被触发,你可以在当前阶段进行更改数据,不会造成重渲染。
updated
这个钩子发生在更新完成之后,当前阶段组件Dom已完成更新。要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新。
BeforeDestroy
这个钩子发生在实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器。
destroyed
这个钩子发生在实例销毁之后,这个时候只剩下了dom空壳。组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。
提一笔:
在使用生命周期时有几点注意事项需要我们牢记。
1.第一点就是上文曾提到的created阶段的ajax请求与mounted请求的区别:前者页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态。
2.除了beforeCreate和created钩子之外,其他钩子均在服务器端渲染期间不被调用。
3.上文曾提到过,在updated的时候千万不要去修改data里面赋值的数据,否则会导致死循环。
4.Vue的所有生命周期函数都是自动绑定到this的上下文上。所以,你这里使用箭头函数的话,就会出现this指向的父级作用域,就会报错。
Vue生命周期先写到这儿吧,发现需要写的东西很多,后期专门写一篇Vue生命周期的博文
全局前置守卫:
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
全局解析守卫:
你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,
区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
全局后置钩子:
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
路由独享的守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫:
你可以在路由组件内直接定义以下路由导航守卫:
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
声明式–
编程式–this.$router.push({name:‘组件名’)};
Vue-cli 项目构建工具;vue-router 路由;vuex 状态管理;axios http请求工具;webpack
这题感觉没啥意思,但目录都写好了,不想重新改了…
区别一:
1).jQuery是一个类库,提供了很多的方法,不能算框架,在过去和现在Jquery是最流行的web前端js库,可是现在无论国内还是国外,他的使用率正在渐渐被其他的js库所替代。随着浏览器厂商对H5规范统一遵循以及ECMA6在浏览器端的实现,jquery的使用率会越来越低。
2).vue的介绍:vue是一个刚兴起不久的前端框架,有一套完整的体系,是一个精简的MVVM。从技术角度讲,vue.js专注于MVVM模型的ViewModel层,通过双向数据绑定把view层和Model层连接起来,通过对数据的操作就可以完成对页面视图的渲染。
区别二:
1).jQuery是直接操作DOM的;使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作;
和原生的js区别只在于可以更方便的选取和操作DOM对象;? 数据和界面是在一起,比如获取input标签的内容
? 2)vue基于一种MVVM模式,使用数据驱动的方式,通过Vue对象将数据和View完全分离开来。
? 对数据进行操作,不在需要引用相应的DOM对象,通过vue对象,将数据和相应的DOM对象相互绑定起来。
区别三
? 1).JQuery适用的场景:JQuery侧重样式操作,比如一些H5的动画页面;需要js来操作页面样式的页面? 2).Vue适用的场景:vue侧重数据绑定,比如复杂数据操作的后台页面;表单填写页面
v-if是通过动态创建或者移除元素实现动态切换 v-show是通过控制元素的css样式display:none样式实现切换 一般来说,v-if 有更高的切换消耗 而 v-show 有更高的初始渲染消耗。 因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。
建立组件模板
通过props接收外部数据
在需要的模块中引入该组件,使用该组件,最终在网页中输出组件与数据
这个在网上没有找到比较好的文章,所以是自己根据自己为数不多的封装小组件的经验写的,如果大家有更好的更规范的流程,可以在下方评论,我及时更新
将全局引入转换为按需引入文件
在 config/index.js 文件中将productionSourceMap 的值设置为false. 不生成映射资源
路由懒加载:懒加载即组件的延迟加载,通常vue的页面在运行后进入都会有一个默认的页面,而其他页面只有在点击后才需要加载出来,使用懒加载可以将页面中的资源划分为多份,从而减少第一次加载的时候耗时
这种优化,就是将每个组件的js代码独立出来,在使用到这个组件时,才向服务器请求文件,并且请求过一次后就会缓存下来,再次使用到这个组件时,就会使用缓存,不再发送请求
压缩css和js文件
使用cdn托管(就是把原服务器上数据复制到其他服务器上,用户访问时,哪台服务器近访问到的就是哪台服务器上的数据。)
开局一张图:
先分析下原因:
1.搜索引擎的基础爬虫的原理就是抓取你的url,然后获取你的html源代码并解析。 而你的页面通常用了vue等js的数据绑定机制来展示页面数据,爬虫获取到的html是你的模型页面而不是最终数据的渲染页面,所以说用js来渲染数据对seo并不友好。
2.seo 本质是一个服务器向另一个服务器发起请求,解析请求内容。但一般来说搜索引擎是不回去执行请求到的js的。也就是说,如果一个单页应用,html在服务器端还没有渲染部分数据数据,在浏览器才渲染出数据,而搜索引擎请求到的html是没有渲染数据的。 这样就很不利于内容被搜索引擎搜索到。 所以服务端渲染就是尽量在服务器发送到浏览器前 页面上就是有数据的。
3.一般的数据逻辑操作是放在后端的。排序这个如果仅仅是几条数据,前后端排序开起来是一样的,如果是有1000条数据,前端要排序就要都请求过来。这样显然是不合理的。
常用的解决方案:
1.页面预渲染
2.服务端渲染
3.路由采用h5 history模式
大厂如何做优化的呢?
1) bilibili做了基本的seo优化,比如
(1)TDK描叙详细。
(2)提升网页加载速度:对外联css,以及js使用了延迟加载以及dns-prefetch,preload。
(3)外联较多,关键词排名高。2) 掘金网站使用了vue-meta-info 管理网站的meta,应该配合使用了prerender-spa-plugin 对SEO进行了优化
3) Element在logo上加了首页的地址,并且只有logo是放在h1标签中。
4) 有一些流量不太高的网站比如http://www.marshall.edu (Marshall University)做了seo社会化分享优化,在meta信息中出现了property=”og:title”这种新东西;https://we.dji.com/zh-CN/campus (大疆招聘)使用了Nuxt
这些网站中出现率最高的公共组件或公共方法有四个:
1) 面包屑导航
2) Icon
3) 搜索框
4) Button组件关于收录问题:
搜索引擎判断一个网站权重高低的尺度无非两个:收录和外链。因此百度收录的高低很大程度上影响着网站在百度的排名
目前百度spider抓取新链接的途径有两个:
一是主动出击发现抓取;
二就是从百度站长平台的链接提交工具中获取数据,其中通过主动推送功能“收”上来的数据最受百度spider的欢迎。
对于站长来说,如果链接很长时间不被收录,建议尝试使用主动推送功能,尤其是新网站,主动推送首页数据,有利于内页数据的抓取。
参考文章:
https://blog.csdn.net/codeliuguisheng/article/details/79634422
https://blog.csdn.net/chjj0904/article/details/79388438
博文参考文章:
https://blog.csdn.net/wang1006008051/article/details/81805932
https://blog.csdn.net/fifteen718/article/details/82529433
https://www.imooc.com/article/257885
https://juejin.im/post/5d1b464a51882579d824af5b