Vue-3

自定义指令

全局注册指令

  • 文件路径:src/main.js
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

// 全局注册指令
Vue.directive('myFocus', {
  // inserted 会在指令所在的元素,被插入到页面中时触发
  inserted(el) {
    el.focus()  // el 就是指令所绑定的元素
  }
})

new Vue({
  render: c => c(App)
}).$mount('#app')
  • 文件路径:src/App.vue
<template>
  <div>
    <h1>自定义指令</h1>
    <input v-myFocus type="text" />
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>

局部注册指令

<template>
  <div>
    <h1>自定义指令</h1>
    <input v-myFocus type="text" />
  </div>
</template>

<script>
export default {
  // 局部注册指令
  directives: {
    // 指令名称: 指令的配置项
    myFocus: {
      inserted(el) {
        el.focus();
      },
    },
  },
};
</script>

<style>
</style>

指令的值

<template>
  <div>
    <h1 v-myColor="color1">指令的值</h1>
    <h1 v-myColor="color2">指令的值</h1>
  </div>
</template>

<script>
export default {
  directives: {
    // 指令名称 : 指令的配置项
    myColor: {
      // 1. inserted 提供的是元素被添加到页面中时的逻辑
      inserted(el, binding) {
        // binding.value 即可获取"指令的值"
        el.style.color = binding.value;
      },
      // 2. update 指令的值修改的时候触发,提供的值变化后,dom 更新的逻辑
      update(el, binding) {
        el.style.color = binding.value;
      },
    },
  },
  data() {
    return {
      color1: "red",
      color2: "blue",
    };
  },
};
</script>

<style>
</style>

实现加载效果

目的:实现自定义指令——v-loading 指令封装

实现

  1. 准备一个 loading 类,通过伪元素定位,设置宽高,实现蒙层
  2. 开启关闭 loading 状态(添加移除蒙层),本质只需要添加移除类即可
  3. 结合自定义指令的语法进行封装复用

代码

<template>
  <div v-loading="isLoading">
    <ul v-for="item in list" :key="item.id">
      <hr />
      <li><img :src="item.img" alt="" /></li>
      <li>{{ item.title }}</li>
      <li>{{ item.source }}</li>
      <li>{{ item.time }}</li>
    </ul>
    <hr />
  </div>
</template>

<script>
import axios from "axios";
export default {
  data() {
    return {
      list: [],
      isLoading: true,
    };
  },
  async created() {
    // 1. 发送请求,获取数据
    const res = await axios.get("http://hmajax.itheima.net/api/news");
    setTimeout(() => {
      // 2. 更新到list中,用于页面渲染
      this.list = res.data.data;

      // 3. 移除loading效果
      this.isLoading = false;
    }, 3000); // 定时3秒,模拟网速慢
  },
  directives: {
    loading: {
      inserted(el, binding) {
        binding.value ? el.classList.add("loading") : el.classList.remove("loading");
      },
      update(el, binding) {
        binding.value ? el.classList.add("loading") : el.classList.remove("loading");
      },
    },
  },
};
</script>

<style>
.loading:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: #fff
    url("https://pic4.zhimg.com/80/v2-d048608d543b55df997675195552f887_720w.webp")
    no-repeat center;
}
</style>

插槽

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

默认插槽

默认插槽组件内定制一处结构

  • 文件路径:src/components/MyDialog.vue
<template>
  <div>
    <hr />
    <h3>温馨提示</h3>
    <p>
      <!-- 1. 在需要定制的地方,使用 slot 占位 -->
      <slot>我是后备内容</slot>
    </p>
    <hr />
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>
  • 文件路径:src/App.vue
<template>
  <div>
    <!-- 2. 使用组件时,组件标签内填入内容 -->
    <MyDialog>你确认要取消收藏吗?</MyDialog>
    <MyDialog>你确认要注销账户吗?</MyDialog>
  </div>
</template>

<script>
import MyDialog from "./components/MyDialog.vue";
export default {
  components: {
    MyDialog,
  },
};
</script>

<style>
</style>

具名插槽

具名插槽组件内定制多处结构

注意v-slot:插槽名 可以简化为 #插槽名

  • 文件路径:src/components/MyDialog.vue
<template>
  <!-- 1. 在需要定制的地方,使用 slot 占位 -->
  <div>
    <hr />
    <slot name="title">我是后备内容</slot>
    <p><slot name="content">我是后备内容</slot></p>
    <hr />
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>
  • 文件路径:src/App.vue
<template>
  <div>
    <!-- 2. 使用组件时,组件标签内填入内容 -->
    <MyDialog>
      <template v-slot:title>
        <h3>友情提示</h3>
      </template>
      <template #content>
        <span>>你确认要取消收藏吗?</span>
      </template>
    </MyDialog>
  </div>
</template>

<script>
import MyDialog from "./components/MyDialog.vue";
export default {
  components: {
    MyDialog,
  },
};
</script>

<style>
</style>

作用域插槽

功能:给插槽绑定数据,将来使用组件时可以用

具体演示:

  • 文件路径:src/App.vue
<template>
  <div>
    <MyTable :data="list1">
      <!-- 3. 通过template #插槽名=变量名 接收对象 -->
      <template #default="obj">
        <button @click="del(obj.row.id)">删除</button>
      </template>
    </MyTable>

    <MyTable :data="list2">
      <template #default="obj">
        <button @click="show(obj.row)">查看</button>
      </template>
    </MyTable>
  </div>
</template>

<script>
import MyTable from "./components/MyTable.vue";
export default {
  data() {
    return {
      list1: [
        { id: 1, name: "李小萌", age: 16 },
        { id: 2, name: "王非明", age: 37 },
        { id: 3, name: "任天风", age: 22 },
      ],
      list2: [
        { id: 1, name: "江海燕", age: 28 },
        { id: 2, name: "楼王嘿", age: 35 },
        { id: 3, name: "疆梦中", age: 41 },
      ],
    };
  },
  methods: {
    del(id) {
      this.list1 = this.list1.filter((item) => item.id !== id);
    },
    show(row) {
      alert(`姓名: ${row.name}; 年龄: ${row.age}`);
    },
  },
  components: {
    MyTable,
  },
};
</script>

<style>
</style>
  • 文件路径:src/components/MyTable.vue
<template>
  <table class="my-table">
    <thead>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年龄</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="item in data" :key="item.id">
        <td>{{ item.id }}</td>
        <td>{{ item.name }}</td>
        <td>{{ item.age }}</td>
        <td>
          <!-- 1. 给slot标签,添加属性的形式进行传值 -->
          <slot :row="item" msg="测试文本"></slot>
          <!-- 2. 它底层会自动将所有的属性,添加到一个对象中 -->
          <!-- 
              {
                row: { id: 2, name: '王非明', age: 27},
                msg: '测试文本'
              }
           -->
        </td>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  props: {
    data: Array,
  },
};
</script>

<style>
.my-table {
  width: 450px;
  text-align: center;
  border: 1px solid #ccc;
  font-size: 24px;
  margin: 30px auto;
}
.my-table head {
  background-color: #1f74ff;
  color: #fff;
}
</style>

单页应用程序

基本概念

  • 单页应用程序:SPA(Single Page Application)

  • 单页面应用——所有功能在一个 html 页面上实现

优点与缺点

在这里插入图片描述

单页面应用:系统类网站 || 内部网站 || 文档类网站 || 移动端站点

多页面应用:公司官网 || 电商类网站

VueRouter

基本认识

VueRouter:它是一个 Vue.js 官方提供的路由管理插件

官网:https://v3.router.vuejs.org/zh/

使用步骤

基本步骤:

  1. 下载 npm i vue-router@3.6.5
  2. 引入 import VueRouter from 'vue-router'
  3. 安装注册 Vue.use(VueRouter)
  4. 创建路由对象 const router = new VueRouter()
  5. 建立关联 new Vue({ render:h => h(App), router }).$mount('#app')
  • 文件路径:src/main.js
// 1. 下载插件
// 在终端运行命令:  npm i vue-router@3.6.5

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'  // 2. 导入插件

Vue.config.productionTip = false
Vue.use(VueRouter)  // 3. 插件初始化

const myRouter = new VueRouter()  // 4. 创建一个路由对象

new Vue({
  render: h => h(App),
  router: myRouter  // 5. 建立关联
}).$mount('#app')

核心步骤:

  1. 创建需要的组件(建议放到 views 目录下)并配置路由规则
  2. 配置导航,配置路由出口(路由匹配的组件显示的位置)
  • 文件路径:src/main.js
// 1. 下载插件
// 在终端运行命令:  npm i vue-router@3.6.5

import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'  // 2. 导入插件

Vue.config.productionTip = false
Vue.use(VueRouter)  // 3. 插件初始化

// 6.1 导入资源
import Find from './views/Find.vue'
import My from './views/My.vue'
import Friend from './views/Friend.vue'

// 4. 创建一个路由对象
const myRouter = new VueRouter({
  // 6.2 配置 router 路由规则
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend },
  ]
})

new Vue({
  render: h => h(App),
  router: myRouter  // 5. 建立关联
}).$mount('#app')
  • 文件路径:src/App.vue
<template>
  <div>
    <div>
      <a href="#/find">发现音乐</a><br />
      <a href="#/find">我的音乐</a><br />
      <a href="#/find">我的朋友</a><br />
    </div>
    <div>
      <!-- 路由出口=>匹配的组件所展示的位置 -->
      <router-view></router-view>
    </div>
  </div>
</template>

<script>
export default {};
</script>

<style>
</style>
  • 文件路径:src/views/Find.vue
<template>
  <div>
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
  </div>
</template>

<script>
export default {
  name: "FindMusic",
};
</script>

<style>
</style>
  • 文件路径:src/views/My.vue
<template>
  <div>
    <p>我的音乐</p>
    <p>我的音乐</p>
    <p>我的音乐</p>
  </div>
</template>

<script>
export default {
  name: "MyMusic",
};
</script>

<style>
</style>
  • 文件路径:src/views/Friend.vue
<template>
  <div>
    <p>我的朋友</p>
    <p>我的朋友</p>
    <p>我的朋友</p>
  </div>
</template>

<script>
export default {
  name: "MyFriend",
};
</script>

<style>
</style>

路由模块封装

  • 文件路径:src/router/index.js
// 导入模块
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入资源
import Find from '../views/Find.vue'
import My from '../views/My.vue'
import Friend from '../views/Friend.vue'

// 初始化
Vue.use(VueRouter)

// 创建路由对象
const myRouter = new VueRouter({
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend },
  ]
})

// 导出路由对象
export default myRouter
  • 文件路径:src/main.js
import Vue from 'vue'
import App from './App.vue'
import myRouter from "./router/index.js";
Vue.config.productionTip = false


new Vue({
  render: h => h(App),
  router: myRouter  // 建立关联
}).$mount('#app')

声明式导航

router-link

需求:实现导航高亮效果

**vue-router 模块 **提供了一个全局组件 router-link 取代了 a 标签,它有两个功能

  • 能跳转(它本质还是 a 标签)
  • 能高亮(配置颜色样式即可)

原来的 a 标签

    <div>
      <a href="#/find">发现音乐</a> <br />
      <a href="#/my">我的音乐</a> <br />
      <a href="#/friend">我的朋友</a> <br />
    </div>

现在的 router-link 标签

    <div>
      <router-link to="/find">发现音乐</router-link> <br />
      <router-link to="/find">我的音乐</router-link> <br />
      <router-link to="/find">我的朋友</router-link> <br />
    </div>

自定义匹配类名

const myRouter = new VueRouter({
  routes: [
    { path: '/find', component: Find },
    { path: '/my', component: My },
    { path: '/friend', component: Friend },
  ],
  // link自定义高亮
  linkActiveClass: 'active', // 配置模糊匹配的类名
  linkExactActiveClass: 'exact-active',  // 配置精确匹配的类名
})

跳转传参

  • 查询参数传参
<router-link to="/find?name=for you">发现音乐</router-link>
<template>
  <div>
    <!-- 查询参数传参,获取命令:$route.query.参数名 -->
    <p>音乐名: {{ $route.query.name }}</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
  </div>
</template>

<script>
export default {
  name: "FindMusic",
  created(){
    // 在created中,通过下面命令获取路由参数
    // this.$route.query.参数名
  alert(this.$route.query.name)
  }
};
</script>

<style>
</style>
  • 动态路由传参
<router-link to="/find/什么是音乐">发现音乐</router-link> <br />
// 导入模块
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入资源
import Find from '../views/Find.vue'
import My from '../views/My.vue'
import Friend from '../views/Friend.vue'

// 初始化
Vue.use(VueRouter)

// 创建路由对象
const myRouter = new VueRouter({
  routes: [
    { path: '/find/:words', component: Find },		// "发现音乐"部分
    { path: '/my/:words', component: My },
    { path: '/friend/:words?', component: Friend },	// :words? 与 :words 的区别是加了问号后可以不传参
  ],
})

// 导出路由对象
export default myRouter
<template>
  <div>
    <!-- 动态路由参数,获取命令:$route.params.参数名 -->
    <p>音乐名: {{ $route.params.words }}</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
    <p>发现音乐</p>
  </div>
</template>

<script>
export default {
  name: "FindMusic",
  created(){
    // 在created中,通过下面命令获取"动态路由参数"
    // this.$route.params.参数名
  alert(this.$route.params.words)
  }
};
</script>

<style>
</style>

重定向与404

// 导入模块
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入资源
import Find from '../views/Find.vue'
import My from '../views/My.vue'
import Friend from '../views/Friend.vue'
import NotFind from '../views/NotFind.vue'

// 初始化
Vue.use(VueRouter)

// 创建路由对象
const myRouter = new VueRouter({
  routes: [
    { path: '/', redirect: '/my' },   		// 路由重定向
    { path: '/find', component: Find },
    { path: '/my/:words', component: My },
    { path: '/friend/:words', component: Friend },
    { path: '*', component: NotFind },  	// 404页面
  ]
})

// 导出路由对象
export default myRouter

路由模式设置

路由模式默认是采用"hash路由",有个#号,看起来不好看,如何解决?

  • hash 路由---------(默认) 例如:http://127.0.0.1:8080/#/home
  • history 路由----- (常用) 例如:http://127.0.0.1:8080/home
// 导入模块
import Vue from 'vue'
import VueRouter from 'vue-router'

// 导入资源
import Find from '../views/Find.vue'
import My from '../views/My.vue'
import Friend from '../views/Friend.vue'
import NotFind from '../views/NotFind.vue'

// 初始化
Vue.use(VueRouter)

// 创建路由对象
const myRouter = new VueRouter({
  routes: [
    { path: '/', redirect: '/my' },   	// 路由重定向
    { path: '/find', component: Find },
    { path: '/my/:words', component: My },
    { path: '/friend/:words', component: Friend },
    { path: '*', component: NotFind },  // 404页面
  ],
  mode: 'history'	// 路由模式设置为'history'
})

// 导出路由对象
export default myRouter

编程式导航

概念简诉

所谓的编程式导航,就是指用 JS 代码来进行跳转

跳转与路由参数

  • path 路径跳转与路由参数
this.$router.push('路由路径')

this.$router.push({
  path: '路由路径'
})
<template>
  <div>
    <button @click="gotoFriend">我的朋友</button>
    <p>发现音乐</p>
    <p>发现音乐</p>
  </div>
</template>

<script>
export default {
  name: "FindMusic",
  methods: {
    // (1) 简单写法
    // gotoFriend(){
    //   this.$router.push('/friend?key=123456')
    // }

    // (2) 普通写法
    gotoFriend() {
      this.$router.push({
        path: "/friend",
        query: {
          key: 123456
        },
      });
    },
  },
};
</script>

<style>
</style>
  • name 命名路由跳转与路由参数
const myRouter = new VueRouter({
  routes: [
    { path: '/find/:words?', component: Find },
    { path: '/my/:words?', component: My },
    { name: 'friend', path: '/friend/:words?', component: Friend },
  ],
  mode: 'history'
})
<template>
  <div>
    <button @click="gotoFriend">我的朋友</button>
    <p>发现音乐</p>
    <p>发现音乐</p>
  </div>
</template>

<script>
export default {
  name: "FindMusic",
  methods: {
    gotoFriend() {
      this.$router.push({
        name: 'friend',
        // query: {
        //   key: 123456
        // },
        params: {
          words: 123456
        },
      })
    },
  },
};
</script>

<style>
</style>

二级路由

const myRouter = new VueRouter({
  routes: [
    { path: '/', component: Layout, children: [ { path: '/article', component: Article } ] },	// 通过 children 配置项,可以嵌套子路由
    { path: '/my/:words?', component: My }
  ],
  mode: 'history'
})

组件缓存

keep-alive 是什么

  • keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
  • keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中

keep-alive 的优点

  • 在组件切换过程中,把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性

keep-alive 的三个属性

include : 组件名数组,只有匹配的组件会被缓存
exclude : 组件名数组,匹配成功的组件都不会被缓存,而除此之外的组件都缓存
max		: 最多可以缓存多少组件实例
<script>
export default {
    // 组件名:如果没有配置 name,才会找文件名作为组件名
    name: 'LayoutPage'
}
</script>
<template>
  <div>
      <!--
	    只希望 Layout 被缓存,include 需要配置成 :include="组件名数组"
	  -->
      <keep-alive :include=['LayoutPage']>
          <router-view></router-view>
      </keep-alive>
  </div>
</template>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值