Vue学习第五天

238 阅读1分钟

自定义指令

  • 之前所学的比如v-model、v-for、v-html...这些都属于内置指令
  • 而像v-focus、v-loading、v-lazy...则属于自定义指令

定义

自定义指令: 自己定义的指令,可以 封装一些dom操作,扩展额外功能


需求: 当页面加载时,让元素获得焦点

之前的话,我们会直接这样写

<input ref="inp" type="text">
 mounted () {
    this.$refs.inp.focus()
  }

但是这样写的话,只能在当前页面使用,如果你再跳转到别的页面,就需要再重新写

所以这时候就需要自定义指令了(自定义指令又分为全局和局部)

  • 全局
    • 全局注册指令,需要在main.js文件里写
<input v-focus type="text">
// 1. 全局注册指令
Vue.directive('focus'指令名, {
  // inserted 会在 指令所在的元素,被添加到页面中时自动调用
  "inserted" (el) {
    // el 就是指令所绑定的元素,可以对el标签扩展额外功能
    // console.log(el);
    el.focus()
  }
})
  • 局部
    • 在当前组件里定义
// 2. 局部注册指令
  directives: {
    // 指令名:指令的配置项
    focus指令名: {
      inserted (el) {
      // el 就是指令所绑定的元素,可以对el标签扩展额外功能
        el.focus()
      }
    }
  }
}

上面是定义指令的操作,然后你要使用的时候,直接在页面对应部分 v-指令名 即可


指令的值

需求:实现一个color指令——传入不同的颜色,给标签设置文字颜色

语法:在绑定指令时,可以通过“等号”的形式为指令绑定具体的不同的参数值

而通过binding.value就可以拿到指令值,指令值修改会触发update函数

<template>
  <div>
    <h1 v-color="color1">指令的值1测试</h1>
    <h1 v-color="color2">指令的值2测试</h1>
  </div>
</template>

<script>
export default {
  data () {
    return {
      color1: 'red',
      color2: 'orange'
    }
  },
  directives: {
    color: {
      // 1. inserted 提供的是元素被添加到页面中时的逻辑
      inserted (el, binding) {
        // console.log(el, binding.value);
        // binding.value 就是指令的值
        el.style.color = binding.value
      },
      // 2. update 指令的值修改的时候触发,提供值变化后,dom更新的逻辑
      //不写这个的话,当指令的值被修改时,视图没有响应!!!!!!!!!!!!!
      update (el, binding) {
        console.log('指令的值修改了');
        el.style.color = binding.value
      }
    }
  }
}
</script>

v-loading指令封装

实际开发中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 => 用户体验不好

分析:

  • 本质loading效果就是一个蒙层,盖在了盒子上
  • 数据请求中,开启loading状态,添加蒙层
  • 数据请求完毕,关闭loading状态,移除蒙层

插槽

TIP:插槽只有两个分类:默认插槽和具名插槽

默认插槽(一个定制位置)

作用:让组件内部的一些 结构 支持 自定义

需求:要在页面中显示一个对话框,封装成一个组件

问题:组件的内容部分,不希望写死,希望能使用的时候自定义

基本语法

  1. 组件内需要定制的结构部分,改用<slot></slot>
  2. 使用组件时,<MyDialog></MyDialog>标签内部,传入结构替换slot

后备内容(默认值)

通过插槽完成了内容的定制,传什么显示什么,但如果不传,则是空白

插槽后备内容: 封装组件时,可以为预留的<slot>插槽提供后备内容(默认内容)

语法:在<slot>我是默认内容</slot>标签内,放置内容,作为默认显示内容(当<MyDialog></MyDialog>里无内容时)

具名插槽

需求:一个组件内有多处结构,需要外部传入标签,进行定制

  • 与刚刚默认插槽不同的是,默认插槽只有一个定制位置,具名插槽有多个
  • 一旦插槽起了名字,它就是具名插槽,只支持定向分发 ​

语法

    1. 多个slot使用name属性区分名字
    1. template配合v-slot:名字来分发对应标签
    • 多个template外是用<MyDialog></MyDialog>包起来的
    • 需要通过template标签包裹需要分发的结构,包成一个整体,才能更好的进行分发
    1. v-slot:插槽名可以简化成#插槽名

作用域插槽(插槽的一个传参语法)

作用域插槽:定义slot插槽的同时,是可以传值的。给插槽上可以绑定数据,将来使用组件时可以使用

基本使用步骤

  1. 给slot标签,以 添加属性的方式 传值(传递数据)
 <slot id="item.id" msg="测试文本"></slot>
  1. 所有添加的属性,都会被收集到一个对象中
{id:3,msg:'测试文本'}
  1. 在template中,具名通过#插槽名="obj"接收,默认插槽用#default="obj",然后在template里就可以通过obj.id使用了
<template #default="obj">
//也可以这样写,直接对obj结构,比如row就是obj里面的一个对象
<template #default="{ row }">

组件封装案例——商品列表

单独写在外面了

单页应用程序 & 路由介绍

单页应用程序:SPA-Single Page Application

  • 单页面应用(SPA):所有功能在一个html页面上实现
  • 开发效率高,性能好,用户体验高
  • 而有这些优点是因为:页面按需更新

要按需更新,首先就要明确:访问路径和组件的对应关系👇

路由: 可以确定访问路径组件的对应关系

  • Vue中的路由:是路径和组件的映射关系
  • VueRouter插件
    • 修改地址栏路径时,切换显示匹配的组件

VueRouter的使用(5+2)

五个基础步骤(固定),在main.js里写

  1. 下载VueRouter模块到当前工程,版本3.6.5
yarn add vue-router@3.6.5
npm install vue-router@3.6.5
  1. 引入
import VueRouter from 'vue-router'
  1. 安装注册
Vue.use(VueRouter)
  1. 创建路由对象(这里面之后会写路由规则)
const router = new VueRouter()
  1. 注入,将路由对象注入到new Vue实例中,建立关联
new Vue({
    render:h => h(App),
    router
}).$mount('#app')

两个核心步骤

  1. 创建需要的组件(views目录),配置路由规则routes
    • route 一条路由规则 { path: 地址栏路径, component: 组件 }
import Find from './views/Find'
import My from './views/My'
import Friend from './views/Friend'
import VueRouter from 'vue-router'

const router = new VueRouter({
  // routes 路由规则们
  // route  一条路由规则 { path: 路径, component: 组件 }
  //数组包对象
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend },
  ]
})
  1. 配置导航,配置路由出口(路径匹配的组件显示的位置<router-view>
    <div class="footer_wrap">
      <a href="#/find">发现音乐</a>
      <a href="#/my">我的音乐</a>
      <a href="#/friend">朋友</a>
    </div>
    <div class="top">
      <!-- 路由出口 → 匹配的组件所展示的位置 -->
      <router-view></router-view>
    </div>