前端学习笔记------------vue2(下)

VUE2

动态组件

动态组件指的是 动态切换组件的显示与隐藏 。
vue提供了一个内置的 <component> 组件, 专门用来实现动态组件的渲染 。

<button @click="comName = 'Left'">展示 Left</button>
<button @click="comName = 'Right'">展示 Right</button>

<div class="box">
  <!-- 渲染 Left 组件和 Right 组件 -->
  <!-- 1. component 标签是 vue 内置的,作用:组件的占位符 -->
  <!-- 2. is 属性的值,表示要渲染的组件的名字 -->
  <!-- 3. is 属性的值,应该是组件在 components 节点下的注册名称 -->

  <!-- keep-alive 会把内部的组件进行缓存,而不是销毁组件 -->
  <!-- 在使用 keep-alive 的时候,可以通过 include 指定哪些组件需要被缓存; -->
  <!-- 或者,通过 exclude 属性指定哪些组件不需要被缓存;但是:不要同时使用 include 和 exclude 这两个属性 -->
  <keep-alive exclude="MyRight">
    <component :is="comName"></component>
  </keep-alive>
</div>

export default {
  data() {
    return {
      // comName 表示要展示的组件的名字
      comName: 'Left'
    }
  },
  components: {
    // 如果在“声明组件”的时候,没有为组件指定 name 名称,则组件的名称默认就是“注册时候的名称”
    Left,
    Right
  }
}

keep-alive

默认情况下,切换动态组件时无法保持组件的状态 。此时可以使用 vue 内置的 <keep keep-alive>组 件保持动态件的状态。

keep-alive 对应的生命周期函数

  • 当组件 被缓存 时,会自动触发组件的 deactivated 生命周期函数。
  • 当组件 被激活 时,会自动触发组件的 activated生命周期函数。
  • 当组件第一次被创建的时候,既会执行 created 生命周期,也会执行 activated 生命周期
  • 当组件被激活的时候,只会触发 activated 生命周期,不再触发 created。因为组件没有被重新创建

keep-alive 的 include 属性

include属性用来指定只有名称匹配的组件会被缓存。多个组件名之间使用英文的逗号分隔
include 使该标签作用于所有name属性的值跟此标签 include的属性值一致的vue页面

 <!-- 在使用 keep-alive 的时候,可以通过 include 指定哪些组件需要被缓存; -->
 <!-- 或者,通过 exclude 属性指定哪些组件不需要被缓存;但是:不要同时使用 include 和 exclude 这两个属性 -->
<keep-alive exclude="MyLeft">
  <component :is="comName"></component>
</keep-alive>

...
export default {
  name: 'MyLeft',

当提供了 name 属性之后,组件的名称,就是 name 属性的值

  1. 组件的 “注册名称” 的主要应用场景是:以标签的形式,把注册好的组件,渲染和使用到页面结构之中
  2. 组件声明时候的 “name” 名称的主要应用场景:结合 <keep-alive> 标签实现组件缓存功能;以及在调试工具中看到组件的 name 名称

插槽

插槽 (SlotSlot)是 vue 为组件的封装者 提供的能力。允许开发者在封装组件时,把不确定的 、希望由用户指定的部分定义为插槽。

在这里插入图片描述

可以把插槽认为是组件封装期间,为用户预留的

在封装组件时,可以通过<slot>元素 定义插槽 ,从而 为用户预留内容占位符 。
如果在封装组件时 没有预留任何 <slot> 插槽 ,则用户提供的任何 自定义内容 都会被丢弃


    <div class="header-box">
      <slot name="title"></slot>
    </div>


v-slot简写形式是#

后备内容

封装组件时,可以为预留的<slot> 插槽提供 后备内容 (默认内容)。如果组件的使用者没有为插槽提供任何内容,则后备内容会生效。

<!-- 声明一个插槽区域 -->
<!-- vue 官方规定:每一个 slot 插槽,都要有一个 name 名称 -->
<!-- 如果省略了 slot 的 name 属性,则有一个默认名称叫做 default -->
<slot name="default">
  <h6>这是 default 插槽的后备内容</h6>
</slot>

具名插槽

如果在封装组件时 需要预留多个插槽节点 ,则需要为每个 <slot> 插槽指定 具体的 name 名称 。这种带有具体名称的插槽叫做“具名插槽”。

<template #author>
  <div>作者</div>
</template>

作用域插槽

在封装组件的过程中,可以为预留的<slot> 插槽绑定 props 数据,这种 带有 props 数据的 <slot> 叫做“ 作用 域插槽 ”。
可以使用 v-slot: 的形式,接收作用域插槽对外提供的数据。

<!-- 文章的内容 -->
<div class="content-box">
  <!-- 在封装组件时,为预留的 <slot> 提供属性对应的值,这种用法,叫做 “作用域插槽” -->
  <slot name="content" msg="hello vue.js" :user="userinfo"></slot>
</div>

...
<template #content="{ msg, user }">
  <div>
    <p>啊,大海,全是水。</p>
    <p>啊,蜈蚣,全是腿。</p>
    <p>啊,辣椒,净辣嘴。</p>
    <p>{{ msg }}</p>
    <p>{{ user.name }}</p>
  </div>
</template>

解构插槽Prop

作用域插槽对外提供的数据对象,可以使用解构赋值 简化数据的接收过程。

自定义指令

vue官方提供了 v-text 、v-for 、v-model 、v-if 等常用的指令。除此之外 vue 还允许开发者自定义指令。

vue中的自定义指令分为两类,分别是:

  • 私有 自定义指令
  • 全局 自定义指令
  // 私有自定义指令的节点
  directives: {
    // 定义名为 color 的指令,指向一个配置对象
    /* color: {
      // 当指令第一次被绑定到元素上的时候,会立即触发 bind 函数
      // 形参中的 el 表示当前指令所绑定到的那个 DOM 对象
      bind(el, binding) {
        console.log('触发了 v-color 的 bind 函数')
        el.style.color = binding.value
      },
      // 在 DOM 更新的时候,会触发 update 函数
      update(el, binding) {
        console.log('触发了 v-color 的 update 函数')
        el.style.color = binding.value
      }
    } */
    color(el, binding) {
      el.style.color = binding.value
    }
  }

私有自定义指令

在每个 vue 组件中,可以在 directives 节点下声明 私有自定义指令。
在使用自定义指令时,需要加上v-前缀。

动态绑定参数值

在 template 结构中 使用自定义指令 时,可以通过等号(=)的方式,为当前指令 动态绑定参数值

通过 binding 获取指令的参数值

在声明自定义指令时,可以通过形参中的第二个参数 ,来接收指令的参数值

update函数

bind函数 只调用 1 次:当指令第一次绑定到元素时调用 当 DOM 更新 时 bind 函数不会被触发 。 update 函 数会在 每次 DOM 更新 时被调用。

函数简写

如果 insert 和update 函数中的 逻辑完全相同 ,则对象格式 的自定义指令可以 简写 成函数格式 :

全局自定义指令

全局共享的自定义指令需要通过 “Vue.directive() directive()”进行声明

// 全局自定义指令
 Vue.directive('color', {
  bind(el, binding) {
    el.style.color = binding.value
  },
  update(el, binding) {
    el.style.color = binding.value
  }
}) 

axios的使用

// 全局配置 axios 的请求根路径
axios.defaults.baseURL = 'http://www.liulongbin.top:3006'
// 把 axios 挂载到 Vue.prototype 上,供每个 .vue 组件的实例直接使用
Vue.prototype.$http = axios

// 今后,在每个 .vue 组件中要发起请求,直接调用 this.$http.xxx
// 但是,把 axios 挂载到 Vue 原型上,有一个缺点:不利于 API 接口的复用!!!

路由

路由(英文: router)就是 对应关系

前端路由

SPA

SPA指的是一个 web 网站只有唯一的个 HTML 页面, 所有组件的展示与切换 都在这唯一的一个页面内完成。此时,不同组件之间的切换 需要通过 前端路由 来实现。

结论:在 SPA 项目中,不同功能之间的切换 ,要依赖于前端路由 来完成!

工作方式

① 用户 点击了 页面上的 路由链接
② 导致了 URL 地址栏 中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前 端路由把当Hash 地址对应的组件 渲染都浏览器中

Hash 地址与组件之间的对应关系

实现

created() {
  // 只要当前的 App 组件一被创建,就立即监听 window 对象的 onhashchange 事件
  window.onhashchange = () => {
    console.log('监听到了 hash 地址的变化', location.hash)
    switch (location.hash) {
      case '#/home':
        this.comName = 'Home'
        break
      case '#/movie':
        this.comName = 'Movie'
        break
      case '#/about':
        this.comName = 'About'
        break
    }
  }
}

vue-router

vue-router是vue.js 官方给出的 路由解决方案。它只能结合vue项目进行使用,能够轻松的管理 SPA 项目中组件的切换 。

安装和配置

① 安装 vue -router 包
npm i vue-router@3.5.2 -S
② 创建路由模块
// 1.导入Vue和VueRouter的包
import Vue from 'vue'
import VueRouter from 'vue-router'

// 2.把 VueRouter 安装为 Vue 项目的插件,Vue.use() 函数的作用,就是来安装插件的
Vue.use(VueRouter)

// 3.创建实例对象
const router = new VueRouter()

// 4.向外导出实例对象
export default router
③ 导入并挂载路由模块
// 导入路由模块,目的:拿到路由的实例对象
// 在进行模块化导入的时候,如果给定的是文件夹,则默认导入这个文件夹下,名字叫做 index.js 的文件
import router from '@/router'

new Vue({
  render: h => h(App),
  // 在 Vue 项目中,要想把路由用起来,必须把路由实例对象,通过下面的方式进行挂载
  // router: 路由的实例对象
  router
}).$mount('#app')
④ 声明路由链接和占位符
// 导入需要的组件
import Home from '@/components/Home.vue'
import Movie from '@/components/Movie.vue'
import About from '@/components/About.vue'

import Tab1 from '@/components/tabs/Tab1.vue'
import Tab2 from '@/components/tabs/Tab2.vue'

import Login from '@/components/Login.vue'
import Main from '@/components/Main.vue'

// 创建路由的实例对象
const router = new VueRouter({
  // routes 是一个数组,作用:定义 “hash 地址” 与 “组件” 之间的对应关系
  routes: [
    // 重定向的路由规则
    { path: '/', redirect: '/home' },
    // 路由规则
    { path: '/home', component: Home },
    // 需求:在 Movie 组件中,希望根据 id 的值,展示对应电影的详情信息
    // 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
    { path: '/movie/:mid', component: Movie, props: true },
    {
      path: '/about',
      component: About,
      // redirect: '/about/tab1',
      children: [
        // 子路由规则
        // 默认子路由:如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做“默认子路由”
        { path: '', component: Tab1 },
        { path: 'tab2', component: Tab2 }
      ]
    },
    { path: '/login', component: Login },
    { path: '/main', component: Main }
  ]
})

//=======================================App.vue

<!-- 当安装和配置了 vue-router 后,就可以使用 router-link 来替代普通的 a 链接了 -->
<!-- <a href="#/home">首页</a> -->
<router-link to="/home">首页</router-link>
<!-- 注意1:在 hash 地址中, / 后面的参数项,叫做“路径参数” -->
<!-- 在路由“参数对象”中,需要使用 this.$route.params 来访问路径参数 -->

<!-- 注意2:在 hash 地址中,? 后面的参数项,叫做“查询参数” -->
<!-- 在路由“参数对象”中,需要使用 this.$route.query 来访问查询参数 -->

<!-- 注意3:在 this.$route 中,path 只是路径部分;fullPath 是完整的地址 -->
<!-- 例如: -->
<!-- /movie/2?name=zs&age=20 是 fullPath 的值 -->
<!-- /movie/2 是 path 的值 -->
<router-link to="/movie/1">洛基</router-link>
<router-link to="/movie/2?name=zs&age=20">雷神</router-link>
<router-link to="/movie/3">复联</router-link>
<router-link to="/about">关于</router-link>
<!-- 只要在项目中安装和配置了 vue-router,就可以使用 router-view 这个组件了 -->
<!-- 它的作用很单纯:占位符 -->
<router-view></router-view>

常见用法

路由重定向

路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址C 从而展示特定的组件页面。通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向

// 重定向的路由规则
{ path: '/', redirect: '/home' },
// 路由规则
{ path: '/home', component: Home },

嵌套路由

声明子路由链接和子路由占位符
    <!-- 子级路由链接 -->
    <router-link to="/about">tab1</router-link>
    <router-link to="/about/tab2">tab2</router-link>

    <hr />

    <!-- 子级路由占位符 -->
    <router-view></router-view>
通过children属性声明子路由规则
{
  path: '/about',
  component: About,
  // redirect: '/about/tab1',
  children: [
    // 子路由规则
    // 默认子路由:如果 children 数组中,某个路由规则的 path 值为空字符串,则这条路由规则,叫做“默认子路由”
    { path: '', component: Tab1 },
    { path: 'tab2', component: Tab2 }
  ]
}

动态路由匹配

动态路由指的是:把 Hash 地址中 可变的部分 定义为 参数项 ,从而 提高路由规则的复用性 。在 vue-router 中使用 英文的冒号 (:)来定义路由的参数项。

$route.params参数对象
// 需求:在 Movie 组件中,希望根据 id 的值,展示对应电影的详情信息
// 可以为路由规则开启 props 传参,从而方便的拿到动态参数的值
{ path: '/movie/:mid', component: Movie, props: true },

//=======================================
<h3>Movie 组件 --- {{ $route.params.mid }} --- {{ mid }}</h3>

在动态路由 渲染 出来的组件中,可以使用this.$route.params 对象访问到 动态匹配的参数值 。

使用 props 接收路由参数

为了简化路由参数的获取形式,vuevue-router 允许在路由规则中开启 props 传参。

{ path: '/movie/:mid', component: Movie, props: true },

path只是路径部分;fullpath是完整的地址

声明式导航 & 编程式导航

在浏览器中,点击链接实现导航的方式,叫做声明式导航 。例如:
普通网页中点击<a>链接 、vue 项目中点击<router router-link>都属于声明式 导航
在浏览器中,调用 API 方法 实现 导航的方式,叫做编程式导航。例如:
普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航

vue-router 中的编程式导航 API

vue-router 提供了许多编程式导航的 APIAPI,其中最常用 的导航 API 分别是:
this.$router.push ('hash 地址 ')
跳转到指定 hash 地址,并增加一条历史记录

gotoLk() {
  // 通过编程式导航 API,导航跳转到指定的页面
  this.$router.push('/movie/1')
},

this.$router.replace ('hash 地址 ')
跳转到指定的 hash 地址,并替换掉当前的历史记录

    gotoLk2() {
      this.$router.replace('/movie/1')
    }

this.$router.go (数值 n)
实现导航历史前进、后退

    goback() {
      // go(-1) 表示后退一层
      // 如果后退的层数超过上限,则原地不动
      this.$router.go(-1)
    }

在实际开发中,一般只会前进和后退一层页面。因此
vue-router 提供了如下两个便捷方法:
① $ back()
在历史记录中, 后退 到上一个页面
② $ forward()
在历史记录中, 前进 到下一个页面

导航守卫

导航守卫 可以 控制路由的访问权限 。示意图如下:
在这里插入图片描述

全局前置守卫

每次发生路由的导航跳转时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行访问权限的控制

// 为 router 实例对象,声明全局前置导航守卫
// 只要发生了路由的跳转,必然会触发 beforeEach 指定的 function 回调函数
router.beforeEach(function(to, from, next) {
守卫方法的3个形参

全局前置守卫的回调函数中接收 3 个

  • to 表示将要访问的路由的信息对象
  • from 表示将要离开的路由的信息对象
  • next() 函数表示放行的意思
next 函数的 3 种调用方式

当前用户拥有后台主页的访问权限,直接放行:next()
当前用户没有后台主页的访问权限, 强制其跳转到登录页面 :next(‘/login’)
当前用户没有后台主页的访问权限, 不允许跳转到后台主页 :next(false)
在这里插入图片描述

router.beforeEach(function(to, from, next) {
  // to 表示将要访问的路由的信息对象
  // from 表示将要离开的路由的信息对象
  // next() 函数表示放行的意思
  // 分析:
  // 1. 要拿到用户将要访问的 hash 地址
  // 2. 判断 hash 地址是否等于 /main。
  // 2.1 如果等于 /main,证明需要登录之后,才能访问成功
  // 2.2 如果不等于 /main,则不需要登录,直接放行  next()
  // 3. 如果访问的地址是 /main。则需要读取 localStorage 中的 token 值
  // 3.1 如果有 token,则放行
  // 3.2 如果没有 token,则强制跳转到 /login 登录页
  if (to.path === '/main') {
    // 要访问后台主页,需要判断是否有 token
    const token = localStorage.getItem('token')
    if (token) {
      next()
    } else {
      // 没有登录,强制跳转到登录页
      next('/login')
    }
  } else {
    next()
  }
})
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值