Vue听课笔记(Vue2~Vue3)-3
一、指令
1.1、指令写法
指令:对于底层DOM操作的一种封装
封装在指令里面可以进行复用
<div id="box">
<div v-hello=" 'red' "></div>
<div>
<script>
//自定义指令
//inserted第一个参数得到的就是这个元素,第二个参数是元素对象
Vue.directive("hello",{
//指令的生命周期
inserted(el,binding){
//第一次插入到父节点是触发
el.style.background =binding。value
},
update(){
}
})
new Vue ({
el="box"
})
</script>
- 自定义指令使用
Vue.directive("指令名",{})
在定义
1.2、指令应用
指令
在dom创建好之后就会触发- 有时数据引入我们的文件中时,难以判断dom创建的时间
- 我们可以通过给引入数据的元素上加上自定义指令
- 当某一个数据引入,dom节点创造好了以后就可以执行某一段行为
1.3、指令补充&nextTick
简写指令
Vue.directive("hello",(el,binding)=>{
el.style.background=binding.value
})
指令生命周期:
bind
:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。inserted
∶被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中)。upiate
:所在组件的VNode更新时调用,但是可能发生在其子VNode更新之前。指令的值
能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新(详
的钩子函数参数见下)。componentUpdated
∶指令所在组件的VNode及其子VNode全部更新后调用。unbind
(销毁) :只调用一次,指令与元素解绑时调用。
在Vue3中,指令的生命周期发生变化
- Vue3中的生命周期与组件生命周期大致相同,仅仅没有了beforeCreate
nextTick
- 比
updated
执行的都完,只执行一次 - 不能复用只能独自使用
this.$nextTick(()=>{
},2000)
二、Vue-cli
2.1、Vue-cli创建项目
在原来的文件中写Vue
- 全局定义 (Global definitions) 强制要求每个 component 中的命名不得重复
- 字符串模板 (String templates) 缺乏语法高亮,在 HTML 有多行的时候,需要用到丑陋的 \
- 不支持 CSS (No CSS support) 意味着当 HTML 和 JavaScript 组件化时,CSS 明显被遗漏
- 没有构建步骤 (No build step) 限制只能使用 HTML 和 ES5 JavaScript,而不能使用预处理器,如 Pug (formerly Jade) 和 Babel
可以使用.vue
文件
文件扩展名为 .vue 的 single-file components (单文件组件) 为以上所有问题提供了解决方法,并且还可以使用 webpack 或 Browserify 等构建工具。
- 不过
.vue
文件,浏览器不认识
有了 .vue
组件,我们就进入了高级 JavaScript 应用领域。如果你没有准备好的话,意味着还需要学会使用一些附加的工具:
-
Node Package Manager (NPM):阅读 Getting Started guide 中关于如何从注册地 (registry) 获取包的章节。
-
Modern JavaScript with ES2015/16:阅读 Babel 的 Learn ES2015 guide。你不需要立刻记住每一个方法,但是你可以保留这个页面以便后期参考。
在你花一天时间了解这些资源之后,我们建议你参考 Vue CLI 3。只要遵循指示,你就能很快地运行一个带有 .vue
组件、ES2015
、webpack
和热重载 (hot-reloading)
的 Vue 项目!
2.2、启动流程&入口文件
- 可以在
packgae.json
文件中直接运行脚本 - 或者在
packgae.json
文件的集成终端直接运行- 使用
npm run serve
或着npm start
来启动
- 使用
- 通过
App.vue
文件进入
2.3、eslint修复
- 在使用CLI时,语法规则非常苛刻,因此会出现许多错误
解决方案:
- 在集成终端使用
npm run lint
- 被赋值但没使用这种错误,这个方法无法修复
- vscode自动修复eslint
- 安装eslint插件,并启用
- 有时这个插件用不了,可以先将其关闭,最后写完代码在启用,修复文件
- 先将其关闭,最后写完代码在启用,修复文件
- 在
vue.config.js
文件中添加以下代码
module.export = { lintOnSave: false//暂时关闭代码格式检测 }
- 在写完代码以后在集成终端使用
npm run lint
- 在
2.4、单文件组件-注册
- 内容写在
template
标签下 - 不能有两个相同的元素 兄弟标签
- js部分必须使用ES6导出规范
export default{}
- data使用函数式的写法
- 可以使用
style
标签写css,不需要写道行内 - 如果还需要在文件里引入子组件
- 先在外面创建一个
.vue
文件在里面写组件的内容 - 在将这个组件 通过
import 子组件名 from '子组件文件的地址'
引入 - 全局写法:
- 还需要再父文件中注册组件
Vue.component('子组件名' , 子组件文件名)
- 再需要使用
import Vue from 'vue'
来引入一次
- 还需要再父文件中注册组件
- 局部写法:
- 写
components:{ 子组件名 }
- 写
- 先在外面创建一个
2.5、单文件组件-通信
- 父子通信和以前的写法相同
- 插槽也能使用
- 子组件的样式会被父组件的影响,插入样式时,先封装子组件的样式再封装父组件的样式,后封装的会影响前封装的
- 只需要在子组件的
style
标签中加scoped
就可以防止被覆盖
- 只需要在子组件的
style
加上long:"scss"
就能使用scss
的写法
2.6、单文件组件-生命周期
- 与以前得生命周期一样
- 也可以从其他文件从在生命周期得阶段引入到文件
- 也可以引入axios文件来使用axios方法
- 需要在终端写
npm i --save axios
- 需要在终端写
2.7、单文件组件-指令与过滤器
-
指令
- 先引入
import Vue from 'vue'
- 接着指令的方法与原来相同
- 先引入
-
过滤器
- 先在文件中使用
Vue.filter("过滤器名称",()=>{需要修改的操作})
声明即可用
- 先在文件中使用
2.8、反向代理&别名
反向代理需要在vue.config.js文件中加入一段代码
devServer: {
port : 8000,//随便改端口号
proxy : {
'/api' : {
target: 'https ://*.*.com' ,//需要代理的网站
host: '*.*.com ' ,
changeOrigin :true,
pathRewrite:{
'自定义接口的名字':''//将自定义接口的名字转为空字符串
}
}
}
}
- 在接口前端自定义一个名字是为了防止引入多个网址时
'/api'
相同
在vue文件中 @
为别名,永远指向src绝对路径
,在src下面引入文件时,只需要加@
就能引入里面文件的绝对路径
三、路由
3.1、spa&路由引入
SPA概念
单页面应用(SinglePage Web Application ,SPA) | 多页面应用(MultiPage Application, MPA) | |
---|---|---|
组成 | 一个外壳页面和多个页面片段组成 | 多个完整页面构成 |
资源公共(css js) | 公用,只需要在外壳部分加载 | 不共用,每个页面都需要加载 |
刷新方式 | ||
url模式 | a.com/#/pageone a.com/#/pagetwo | a.com/pageone.html a.com/pagetwo.html |
用户体验 | 页面片段间的切换快,用户体验良好 | 页面切换加载缓慢,流畅度不够,用户体验比较差 |
转场动画 | 容易实现 | 无法实现 |
数据传递 | 容易 | 依赖url传参、或者cookie .localStorage等 |
搜索引擎优化(SEO) | 需要单独方案,实现比较困难,不利于SEO检索 可利用服务器端渲染(SSR)优化 | 实现方法简易 |
试用范围 | 高要求的体验度,追求界面流畅的应用 | 适用于追求高度支持搜索引擎的应用 |
开发成本 | 较高,常常需要借助专业的框架 | 较低,但页面重复代码多 |
维护成本 | 相对容易 | 相对复杂 |
vue-router
- 根据不同的路径加载到不同的页面
3.2、一级路由
-
在
main.js
先引入router文件,并且将给文件渲染 -
再创建几个组件
-
在路由文件(index.js)中引入组件
import 组件名称 from '组件相对地址' Vue.ues(VueRouter)//注册路由插件,两个全局router-view router-link const routes =[ { path:'/组件名', component:组件名称 }//有几个组件就写几次 ] const router =new VueRouter({ routes }) export default router
-
在根文件中加上
router-view
标签相当于slot
标签
3.3、重定向
- 就是希望打开页面是就会指向我们希望出现的组件页面
const routes =[
{
path:'/组件名',
component:组件名称
},
{
path:'/',
redirection:'/组件名'
}
]
这样操作即可
- 如果想在输入一个未定义的组件,依旧是跳转到我们希望出现的组件页面
const routes =[
{
path:'*',
component:组件名称
},
{
path:'*',
redirection:'/组件名'
}
]
3.4、声明式导航
-
第一种方法
- 使用
<router-link>
标签进行跳转组件(使用to="组件绝对地址")
时,会自动给跳转的组件加上class,可以通过给这个class加上高亮属性,来使得点击某个图标跳转之后可以使得该图标保持高亮 - 并且可以在这个标签中自定义class属性,通过
active-class="class名称"
的方式添加
- 使用
-
第二种方法
- 使用插槽的方式使用
<router-link>
标签进行跳转组件(使用to="组件绝对地址")
,在这个标片中间再加一个<li>
标签,在存放组件 - 在
<router-link>
标签中加custom v-slot="{navigate,isActive}"
属性 - 在
<li>
标签上@事件="navigate"
属性 isActive
是判断是否在当前组件上,是的话就是true,否则是false,可以通过这一特性,添加动态class:class="isActive?自定义属性:''"
- 使用插槽的方式使用
3.5、嵌套路由
- 在父组件中再嵌套一个路由的方法
import 组件名称 from '组件相对地址'
import 子组件名称 from '子组件相对地址'
Vue.ues(VueRouter)//注册路由插件,两个全局router-view router-link
const routes =[
{
path:'/组件名',
component:组件名称,
children:[
{
path:'/组件名/子组件名',
component:子组件名称,
}
]
}
]
- 重定向使其跳转到子组件
const routes =[
{
path:'/组件名',
component:组件名称,
children:[
{
path:'/组件名/子组件名',
component:子组件名称,
}
{
path:'*',
redirect:'/组件名/子组件名'
}
]
}
]
- 有些路径上时二级关系,但实际上是兄弟关系
3.6、编程式导航
- 给值赋上事件,通过执行某个函数触发
location.href = '#/组件名'
,使其跳转到那个组件页面 - 给值赋上事件,通过执行某个函数触发
this.$router.push('/组件名')
,使其跳转到那个组件页面
3.7、动态路由
-
在路由文件中设置一个动态路由
const routes =[ { path:'/组件名/:id',//通过id来获取组件 component:组件名称 } ]
-
在改组件中设置
this.$route.params.id
来获取id值,发送请求到后端 -
在根组件中设置点击事件后,设置一个函数,参数就是
id
,通过this.$router.push(/组件名称/${id})
的方式,使得创建一个组件
3.8、路由命名
- 给路由组件加一个
name
属性
const routes =[
{
name:'asd'
path:'/组件名/:id',//通过id来获取组件
component:组件名称
}
]
- 然后通过name进行跳转
函数名(参数){
this.$router.push({
name:'asd',
params:{
id:参数
}
})
}
3.9、路由模式
- 如果不想要地址出现
#
,可以使用history模式- 在分享时有些网站会加上
#
,使用这种模式不影响 - 加入
mode:'history'
即可
- 在分享时有些网站会加上
const router =new VueRouter({
mode:'history'
routes
})
-
弊端
- 不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问
http: //oursite.com/user/id
就会返回404,这就不好看了。
- 不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问
-
如果出现了问题,就使用
npm run build
生成了dist文件夹,仍给后端
3.10、全局路由拦截
-
在一些页面不授权不给进入
-
可以给路由加上一个
meta
属性,在里面自定义一个属性,自定义属性值为true
meta:{
isASD:true
}
router.beforeEach((to,from,next)=>{
if(某几个需要授权的路由/*to.meta.isASD==>通过判断这个值是不是true来进行判断是否通过*/){
//判断本地储存中是否有token字段
if(localStorage.getItem('token')/*授权通过*/){
next()
}else{
next('/login')
}
}else{
next()
}
})
- to:Route:即将要进入的目标路由对象
- from:Route:当前导航正要离开的路由
3.11、局部路由拦截
router.beforeEach((to,from,next)=>{
if(某几个需要授权的路由/*to.meta.isASD==>通过判断这个值是不是true来进行判断是否通过*/){
//判断本地储存中是否有token字段
if(localStorage.getItem('token')/*授权通过*/){
next()
}else{
next('/login')
}
}else{
next({
path:'/login',
query:{redirect:to.fullPath}
})
}
})
跳转路由的代码
this.$router.push(this.$route.query.redirect)
- 路由独享的守卫
- 将以下代码写道路由里面
beforeEach((to,from,next)=>{}
- 组件内的守卫
- 将以下代码写到组件内
// 路由生命周期
beforeRouteEach((to,from,next)=>{
//在渲染该组件的对应路由被·confirm·前调用·
//不!能!获取组件实例`this`
//因为当守卫执行前,组件实例还没被创建
}
3.12、局部懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
- 删除原先导入的路由组件 即
import 组件名称 from '组件相对地址'
再在组件内部替换一条语句
{
path:'/组件名',
component:()=>import('组件相对地址')//懒加载
}