VUE学习 ++

前言

基础知识请查阅 vue学习 +

补充内容
v-once

介绍

用于将元素或组件的内容只渲染一次,而不会随着数据的变化而重新渲染。这在某些情况下可以提高性能,因为不需要在数据更新时重新渲染这部分内容

当使用 v-once 指令时,Vue.js 会将该元素或组件的内容标记为静态内容,不会再根据数据的变化重新计算和更新。这意味着即使数据发生变化,被 v-once 标记的内容也不会重新渲染

JavaScript
<template>
  <div>
    <div v-once @click="setMsg">只生效一次:{{sayHi}}</div>
  <div>持续变化:{{sayHi}}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      sayHi: "HELLO WORLD"
    };
  },
  methods:{
    setMsg(){
      alert('hello')
      this.sayHi = "学 HTML 死路一条"
    }
  }
};
</script>
具名插槽传参

父级通过使用 #插槽名 = “行参” 来接收参数

父级
<template>
  <div>
    <test>
       <template #title="row">
        <p>无名喵站</p>
      </template>
    <test>
  </div>
</template>
<script>
import Pannel from './插槽.vue';
export default {
  components: {
    test,
  }
}
</script>
子组件
<template>
  <div>
     <p>子组件</p>
    <slot name="title" :row="arr"></slot>
  </div>
</template>
组件双向绑定

当子组件想直接修改父组件通过 props 传入的值时。会抛出一个报错提示:

%title插图%num

这个Vue报错提示是因为你在子组件中直接修改了一个父组件传递给它的prop值。这是不推荐的做法,
因为父组件在重新渲染时会覆盖子组件中的修改。

Vue
<template>
  <div class="switch">
    <p>子级组件</p>
    <div>
      <p>{{type}}</p>
      <div @click="changeFn" class="swDiv">
        <div :class="{circle:true, off:type}"></div>
      </div>
      <button @click="changeFn">改变状态</button>
    </div>
  </div>
</template>
    
<script>
export default {
  props: ["type"],
  methods: {
    changeFn() {
      this.type = !this.type
    }
  }
};
</script>

效果展示

%title插图%num

因此,一般情况下,子组件只作为展示的工作,不提供数据操作的能力。若非要操作父级页面的数据,
可以通过事件传递方式实现。如果需要实现操作数据能力,也是通过事件的方式委派给父级操作

子组件
<template>
  <div class="switch">
    <p>子级组件</p>
    <div>
      <p>{{type}}</p>
      <div @click="changeFn" class="swDiv">
        <div :class="{circle:true, off:type}"></div>
      </div>
      <button @click="changeFn">改变状态</button>
    </div>
  </div>
</template>
    
<script>
export default {
  props: ["type"],
  methods: {
    changeFn() {
      this.$emit("updateType", !this.type);
    }
  }
};
</script>
父组件
<template>
  <div class="app">
    <demo :type="type" @updateType="fn"></demo>
    <p>父级状态</p>
    <div class="swDiv">
      <div :class="{circle:true, off:type}"></div>
    </div>
  </div>
</template>

<script>
import demo from "./components/demo.vue";
export default {
  components: {
    demo
  },
  data() {
    return {
      type: true
    };
  },
  methods: {
    fn(e) {
      this.type = e;
    }
  }
};
</script>

效果展示

%title插图%num

sync

官方提供了一种双向绑定的方案。通过 sync 修饰符,即可实现上述操作。其原理实际与上方相似;

父级界面
<template>
  <div class="app">
    <demo :type.sync="type"></demo>
    <p>父级状态</p>
    <div class="swDiv">
      <div :class="{circle:true, off:type}"></div>
    </div>
  </div>
</template>

<script>
import demo from "./components/demo.vue";
export default {
  components: {
    demo
  },
  data() {
    return {
      type: true
    };
  }
};
</script>
子级组件
<template>
  <div class="switch">
    <p>子级组件</p>
    <div>
      <p>{{type}}</p>
      <div @click="changeFn" class="swDiv">
        <div :class="{circle:true, off:type}"></div>
      </div>
      <button @click="changeFn">改变状态</button>
    </div>
  </div>
</template>
    
<script>
export default {
  props: ["type"],
  methods: {
    changeFn() {
      this.$emit("update:type", !this.type);
    }
  }
};
</script>

效果展示

%title插图%num
子组件操作 v-model 值

在 Vue 2 中,父组件可以通过使用 v-model 指令将一个变量的值传递给子组件,并实现双向绑定。
下面是一种常见的方法:

Vue
<input type="text" v-model="text" />

解析 v-mode 的原理,实际上是进行了一个如下的操作:

Vue
<input type="text" :value="text" @input="text = $event" />

若要自定义子组件实现父组件所谓的 v-model 的双向绑定,则需要如下操作

在父组件中,使用 v-model 指令将一个变量绑定到子组件上。假设你要将变量 parentValue 传递给子组件,并实现双向绑定,可以这样写:

界面
<template>
  <div>
    <child-component v-model="parentValue"></child-component>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  data() {
    return {
      parentValue: ''
    };
  }
};
</script>

在子组件中,需要声明一个名为 value 的 prop,并在组件内部使用 model 选项将其绑定到子组件的一个内部变量上。

然后,通过在适当的时候触发 input 事件来更新该值。子组件的代码如下所示:

子组件
<template>
  <div>
    <input type="text" :value="value" @input="$emit('input', $event.target.value)">
  </div>
</template>

<script>
export default {
  props: {
    value: {
      type: String,
      required: true
    }
  }
};
</script>

父组件和子组件之间就建立了双向绑定,当子组件的值发生变化时,父组件的 parentValue 也会相应地更新

效果展示

%title插图%num
ESLint 自动修正代码规范

ESLint 会检查代码语法中是否符合 [ESLint语法规范],如若违反规范会抛出一些错误。

配置自动修正

基于 vscode 插件 ESLint 高亮错误,通过修改 vscode 配置项自动帮助修复错误。

%title插图%num

写入对应配置,完成保存时自动修正代码规范的操作。

JSON
{
  // 当保存的时候,eslint 自动帮我们修复错误
  "editor.codeActionsOnSave": {
      "source.fixAll": true
  },
  // 保存代码 不自动格式化
  "editor.formatOnSave": false
}

效果展示

%title插图%num
Vue 自定指令
简介

Vue可通过 全局注册 或者 局部注册 来 定义自定义指令

当 vue 内置指令满足不了业务需求时,我们可以使用 directive 方法或对象成员来实现

描述

  • 全局指令 需在 main.js 入口文件 使用 Vue.directive() 注册
  • 局部指令 需在 export default 中定义成员 directive 中注册
  • 使用全局指令时,只需要在标签中 v-自定义指令名 即可,会执行自定义指令的方法
全局注册

在 main.js 入口文件中使用 Vue.directive() 方法注册

声明在全局的指令,其他 vue单文件 都可以直接使用

语法介绍

  • 此声明方式 作用于全局Vue项目
  • Vue.directive( ‘自定义指令名’ , { inserted( Dom对象 , 标签传入的参数 ){ … } }
  • inserted 是一个回调函数,指的是自定义指令所在的标签插入到页面时 触发 (仅响应一次)

注册全局自定义指令

  • 演示自定义指令 使 表单组件 自动聚焦
JavaScript
// 全局自定义指令 自动对焦
Vue.directive('focus', {
  inserted(el) {
    el.focus();
  }
})
Vue
<template>
  <div>
    <input v-if="isopen" type="text" v-focus />
    <button v-else @click="isopen=true">打开输入框</button>
  </div>
</template>
<script>
export default {
   data(){
    return{
      isopen:false,
    }
   }
}
</script>

效果演示

%title插图%num
局部注册

在单 .vue 文件中的 export default 中声明的 directives 成员中注册

声明在单文件的自定义指令,仅可在该文件下使用

语法介绍

  • 此声明方式 作用于单 vue文件内
  • directive: { 自定义指令名 : { inserted(el) { … } } }
  • inserted 是一个回调函数,指的是自定义指令所在的标签插入到页面时 触发 (仅响应一次)

注册局部自定义指令

  • 演示自定义指令 使 表单组件 自动聚焦
Vue
<template>
  <div>
    <input v-if="isopen" type="text" v-focus />
    <button v-else @click="isopen = true">打开输入框</button>
  </div>
</template>
<script>

export default {
  directives: {
    focus: {
      inserted(el) {
        el.focus();
      }
    }
  },
  data() {
    return {
      isopen: false,
    }
  }
}

效果演示

%title插图%num
指令传参

标签在 v-自定义指令名=”值” 的方式传值,自定义指令在函数中 第二个参数中接收 值

无论在全局自定义指令或是在局部自定义指令中,都可以对自定义组件在不同场合时 传值

语法介绍

  • 事件回调的参数1为 引用指令的dom对象,参数2为标签传入的值 例如 ( inserted( el,val ){ … } )
  • 传入的参数被包裹在对象中,需要使用 对象的方式 取到实际的值

接收的参数成员

打印 接收的参数 val,可以看到如下对象信息

%title插图%num

下面是对各个成员存值的描述

参数成员 描述
{def} 配置对象
{expression} 传入值的完整结构
{modifiers}
{name} 自定义指令的名字
{rawName} 自定义指令的全名
{value} 被传入指令的值

演示传值

  • 通过 data中的 myColor 传入 ‘red’ 参数到自定义指令中,自定义指令通过 val.value 取到实际的值
  • update() 会在指令对应的 值/标签 更新时触发,并在下方演示中重复执行一轮新的操作,样式得到同步更新
Vue
<template>
  <div>
    <div v-myColor="colorStr"></div>
    <button @click=" colorStr = 'blue'">打开输入框</button>
  </div>
</template>
<script>

export default {
  directives: {
    myColor: {
      inserted(el, val) {
        console.log(val);
        el.style.backgroundColor = val.value;
      },
      update(el, val) {
        el.style.backgroundColor = val.value;
      }
    }
  },
  data() {
    return {
      colorStr: 'red',
    }
  }
}
</script>

效果演示

%title插图%num
指令事件

自定义指令 通过 事件驱动方法,并可在事件时传值 来实现各种操作

  • 被绑定的标签使用 v-自定义指令名=”值” 来传递参数 (例如 <p v-color=”red”>我是红色</p>)
  • 自定义指令使用 参数1 接收 dom对象 ,参数2 接收 传入的值 (例如 color: { inserted:(el,val){ el.style.color=val.value } })
回调函数 描述
inserted 指令所在标签插入到网页上
update 指令所在标签对应数据/标签发生更新
Vue 路由
介绍

路由指的是一种 映射关系

例如 node.js 中 接口 与 业务 的映射关系,设备 和 ip 的映射关系

%title插图%num

通过路由的方式,可以关联两个 项目 的业务,也可说是种 一对一 的绑定关系

路由可以制作 单页面应用(SPA)

单页面应用指的是所有功能在一个html页面上实现,使用路由的方式进行业务场景切换

%title插图%num

优点

  • 整体不刷新页面,用户体验更好
  • 数据传递容易,开发效率高

缺点

  • 开发成本较高(需要学习专门知识)
  • 首次加载会比较缓慢,不利于seo

组件可分为 页面组件复用组件

页面组件一般为构成页面展示的组件,复用组件一般为重复使用和展示数据组件,例如商品列表中的小项

%title插图%num

说明

  • vue文件本质无区别,为方便学习和理解,分解成两种类型的组件
  • 页面组件 一般放在 src/views 文件夹下,配合路由切换使用
  • 复用组件 一般放在 src/components 文件夹下,嵌套在页面组件中。重复渲染结构一样的标签

Vue 路由通过 哈希值 来实现 组件的切换

通过 网站地址/#/哈希值,可在特定标签中自由切换到对应的组件内容

%title插图%num
安装路由

vue-router 本质上是一个第三方包

%title插图%num

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

模块包优势

  • 它和 Vue.js 深度集成
  • 可以定义 – 视图表(映射规则)
  • 符合模块化开发理念
  • 提供两个内置全局组件
  • 声明式导航自定激活的 CSS class 的链接
  • … 更多优势

下载包

注意:最新版本的 vue-router 包存在兼容性问题,需要进行包的降级操作 相关资料

  •  Vue CLI 4.5以下,对应的是Vue2
  •  Vue CLI 4.5及以上,对应的是Vue3,也可以手动选择Vue2 vue
  •  3.0以下兼容的是element-ui前端组件库;
  •  vue 3.0兼容的是element-plus前端组件库.
  •  vue2搭配vue-router3
  •  vue3搭配vue-router4
ShellScript
# npm 下载
npm install vue-router@3.6.5
# yarn 下载
yarn add vue-router@3.6.5
全局配置

配置 vue-router 到 Vue实例 并在 App.vue 使用

  • 引入 vue-router包 到 main.js 中
  • 使用 Vue.use() 注册 vue-router 到全局组件
  • 定义变量 routes 撰写路由规则 { part,component }
  • 实例化 VueRouter 至变量 router 并导入 routes 路由规则
  • 将完成配置的路由对象 router 注入到 vue实例中

配置路由

JavaScript
// @ 是 vue 目录中 src 的绝对路径
import Find from '@/view/Find.vue';
import My from '@/view/My.vue';
import Part from '@/view/Part.vue';

// 1. 引入 vue-router 包
import VueRouter from 'vue-router'

// 2. 注册全局组件
Vue.use(VueRouter);

// 3. 撰写 规则数组 引入组件
const routes = [
  {
    path: '/find',
    component: Find,
  },
  {
    path: '/my',
    component: My,
  },
  {
    path: '/part',
    component: Part,
  }
]

// 4. 生成路由对象
const router = new VueRouter({
  // 与上方数组名字相同 ES6语法允许简写
  routes,
});

// 5. 路由对象注入到 vue实例 中,this可以访问 $route 和 $router
new Vue({
  router,
  // 准备渲染到 APP
  render: h => h(App),
})
  // 渲染到 index.html 文件中 id 叫 app 的标签上
  .$mount('#app');

路由配置参数

在上方代码演示中 routes 路由配置项的每一个对象,常用属性和描述

成员 类型 描述
path String 路由的路径 根路由的路径需要加 ‘/’
name String 路由的名称,方便路由传值
component value 路由对应的组件
redirect String 路由响应后 执行重定向的路径
children Arrary 嵌套的子组件
beforeEnter Arrary | function 路由独享的守卫,可传入多个函数(不加括号)
使用路由

VueRouter 类导入的 routes 配置项,可使用 /#/路由名 渲染到指定位置

跳转到对应的路由,会直接在挂载点 <router-view></router-view> 中替换内容

使用方式

  • 在对应的 <a>标签中 href 属性设置路由规则上的哈希值 例如 #/find
  • 设置挂载点,用 <router-view></router-view> 挂载
  • 当url的 hash值 路径切换时,在 router-view 标签中会显示路由规则中的内容

案例模拟

  • main.js 使用上个案例的 路由配置
  • 实现效果:路由的基础配置和切换
App.vue
<template>
  <div>
     <div class="footer_wrap">
      <a href="#/find">发现音乐</a>
      <a href="#/my">我的音乐</a>
      <a href="#/part">朋友</a>
     </div>
     <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
     </div>
  </div>
</template>
<script>

export default {}

</script>
<style scoped>
.footer_wrap{
  position: fixed;
  left: 0;
  right: 0;
  display: flex;
  width: 100%;
  text-align: center;
  background-color: #333;
  color:#ccc;
 }
 .footer_wrap a{
  flex:1;
  text-decoration: none;
  padding: 20px 0;
  line-height: 20px;
  background-color: #333;
  color:#ccc;
  border:1px solid black;
 }
 .footer_wrap a:hover{
  background-color: #555;
 }
 .top{
  padding-top: 62px;
 }
</style>
Find.vue
<template>
  <div>
    <li>推荐</li>
    <li>排行榜</li>
    <li>歌单</li>
  </div>
</template>
My.vue
<template>
  <div>
    <li>我的收藏</li>
    <li>我的历史</li>
  </div>
</template>
Part.vue
<template>
  <div>
    <li>关注明星</li>
    <li>发现精彩</li>
    <li>寻找伙伴</li>
    <li>加入我们</li>
  </div>
</template>

效果展示

%title插图%num
声明式 – 基础使用

使用 <router-link> 替代 <a> 标签执行跳转会在选中时自动添加对应类名

router-link 会使用户执行跳转路由时,会给自身增加类样式,方便用于CSS实现选中时候的作 高亮判断,

说明

  • vue-router 提供了一个全局组件 <router-link>
  • router-link 实际上最终会渲染成 <a> 标签,它的 to 属性等价于 href 属性 (to无需 # )
  • <router-link> 自带高亮的类名(选中时的类名): router-link-exact-active、router-link-active

实际操作

  • 使用 <router-link> 特性,替换所有 <a> 标签,href属性 改为 to属性,(路径前面省略 #)
  • 修饰高亮状态 router-link-exact-active 类的样式,vue其他内容复用上一个演示代码

案例模拟

  • 实现效果:使用 router-link-exact-active 类为激活的路由呈现自定义的效果
CSS
  /* 选中时触发 注意类的权重 */
 .footer_wrap .router-link-active{
  color: white;
  background: black;
 }
Vue
<template>
  <div>
     <div class="footer_wrap">
      <router-link to="/find">发现音乐</router-link>
      <router-link to="/my">我的音乐</router-link>
      <router-link to="/part">朋友</router-link>
     </div>
     <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
     </div>
  </div>
</template>

效果演示

%title插图%num
声明式 – 跳转传参

router-link 可在 跳转路由时,给路由 对应的组件内传值

%title插图%num

在 <router-link> 上的 to 属性中路径后面以 ?参数名=值 方式传值

说明

  • 普通传值:在 router-link 上的 to 属传值,语法如下:
    • /path?参数名=值 方式传值
  • 普通接收:对应路由中接收的 页面组件
    • 使用 $route.query.参数名 获取传递的值
  • 动态传值:在 router-link 上的 to 属传值,语法如下:
    • /path/值 (需要路由对象提前配置 path:”/path/参数名” 可传递多个)
  • 动态接收:对应路由中接收的 页面组件
    • 使用 $route.params.参数名 获取传递的值

普通传值

  • <router-link> 使用 /path?参数名=值 方式 传值
  • 路由对应的组件 使用 $route.query.参数名 接收
  • vue其他内容复用上一个演示代码
  • 实现效果:为每一个路由交互 query参数
App.vue
<template>
  <div>
     <div class="footer_wrap">
      <router-link to="/find?name=菊花台">发现音乐</router-link>
      <router-link to="/my?name=七里香">我的音乐</router-link>
      <router-link to="/part?name=隔壁老王">朋友</router-link>
     </div>
     <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
     </div>
  </div>
</template>
Find.vue
<template>
  <div>
    <li>推荐</li>
    <li>排行榜</li>
    <li>歌单</li>
    <li>推荐:{{$route.query.name}}</li>
  </div>
</template>
My.vue
<template>
  <div>
    <li>我的收藏</li>
    <li>我的历史</li>
    <li>我喜欢的:{{$route.query.name}}</li>
  </div>
</template>
Part.vue
<template>
  <div>
    <li>关注明星</li>
    <li>发现精彩</li>
    <li>寻找伙伴</li>
    <li>加入我们</li>
    <li>有人关注你:{{$route.query.name}}</li>
  </div>
</template>

效果演示

%title插图%num

动态传值

  • 在 main.js 中的 路由配置项里修饰,path:”/:变量名/” 书写的内容会被当成 动态参数
  • 在 <router-link> 的 to 属性中 以 /路径/参数 的方式 进行传值
  • 接收方以 $route.params.变量名 获取值。vue其他内容复用上一个演示代码
  • 实现效果:为每一个路由交互 params 动态参数
main.js
const routes=[
  {
    path:'/find/:music',
    component:Find,
  },
  {
    path:'/my/:music',
    component:My,
  },
  {
    path:'/part/:user/:id',
    component:Part,
  },
];
App.vue
<template>
  <div>
     <div class="footer_wrap">
      <router-link to="/find/菊花台">发现音乐</router-link>
      <router-link to="/my/七里香">我的音乐</router-link>
      <router-link to="/part/夜夜酱/10032">朋友</router-link>
     </div>
     <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
     </div>
  </div>
</template>
Find.vue
<template>
  <div>
    <li>推荐</li>
    <li>排行榜</li>
    <li>歌单</li>
    <li>推荐:{{$route.params.music}}</li>
  </div>
</template>
My.vue
<template>
  <div>
    <li>我的收藏</li>
    <li>我的历史</li>
    <li>我喜欢的:{{$route.params.music}}</li>
  </div>
</template>
Part.vue
<template>
  <div>
    <li>关注明星</li>
    <li>发现精彩</li>
    <li>寻找伙伴</li>
    <li>加入我们</li>
    <li>你关注的人:[ID {{ $route.params.id }}] {{ $route.params.user }}</li>
  </div>
</template>

效果展示

%title插图%num
重定向

在路由配置中 “/”默认路径,加载页面时候 <router-view> 首先匹配该路径

网页打开 url 默认的 hash 值是 / 路径

%title插图%num

redirect 属性可以设置 路由响应后 需要 重定向 到哪个路由路径

在路由配置的每项路由中,redirect 需要传入一个字符串值的路由,且该传入的路由在 路由配置 中 已经声明

案例模拟

  • 实现效果:设置一个网站打开默认转向的路由
JavaScript
const routes = [
    {
    // 默认路由
    path: '/',
    // 路由响应后 执行重定向
    redirect: '/find',
  },
  ...
  {
    path: '/find',
    component: Find,
  },
];

效果演示

%title插图%num
配置 404路由

在路由配置中 “*”匹配任意路由常用于匹配 无对应路由 所显示的 404页面

该路由一般 放置在路由配置对象的末尾,用于 返回路径无命中任意路由 最后返回的 提示页面

%title插图%num

案例模拟

  • 在 main.js 中的路由配置对象 中,最末端添加 ” * ” 路由配置
  • ” * ” 路由绑定的组件为 404页面组件
  • 实现效果:当路由无任何命中时,跳转到 404页面 组件
main.js
// 引入 404页面组件
import NotFound from '@/views/NotFound.vue';

const routes = [
  {
    // 默认路由
    path: '/',
    redirect: '/find',
  },
 ...
  {
    // 任意路由
    path:'*',
    component:NotFound,
  }
];
App.vue
<template>
  <div>
     <div class="footer_wrap">
      <router-link to="/find/菊花台">发现音乐</router-link>
      <router-link to="/my/七里香">我的音乐</router-link> 
      <!-- 该路径未在路由声明 -->
      <router-link to="/play">游戏</router-link>
     </div>
     <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
     </div>
  </div>
</template>
NotFound.vue
<template>
  <img src="../assets/404.png" alt="">
</template>

效果演示

%title插图%num
路由模式修改

Vue路由有两种模式,分别为 hash路由history路由

使用 hash路由时,路径后面的 # 显得有些突兀,如若为了解决这个问题,可尝试在路由配置中切换模式

区别

  • hash 路由:http://localhost:8080/#/home
  • history 路由:http://localhost:8080/home (需要服务器端支持,否则这样的写法只是寻找域名下的文件夹)

切换路由

  • 在全局配置中,找到 路由实例化的配置项中,修改 mode 的默认值
  • 路由配置项的 mode 的值默认为 hash,修改完成后,url路径中去掉了 # 号占位

案例模拟

  • 实现效果:使用 history路由 的方式,去掉 url 中的 # 号
main.js
const router = new VueRouter({
  routes,
  mode:'history',
})

效果展示

%title插图%num
编程式 – 基础使用

使用 JavaScript代码 来 控制路由 的跳转,叫编程式导航

不使用 <a> 标签的 href 来进行路由的切换,而是使用 JS 的 this.$router.push({}) 进行路由的切换。
需传入 path name 对应参数

说明

  • 使用 编程式导航时,目标路由 需已在 路由配置 中已经声明
JavaScript
this.$router.push({
   // path 或者 name 任选一个
   path: '路由路径',
   name: '路由名'
 })

案例模拟 – 使用 path

  • 使用 span 标签绑定对应菜单,并给每个 span 绑定点击事件
  • 给每个绑定的点击事件传入对应 路由url参数
  • 在 methods 中定义 编程式导航 方法 this.$router.push() ,并使用传入的参数
  • 实现效果 在 this.$router.push({}) 方式跳转路由时,依据 path路径 跳转
Vue
<template>
  <div>
    <div class="footer_wrap">
      <span @click="btn('/find')">发现音乐</span>
      <span @click="btn('/my')">我的音乐</span>
      <span @click="btn('/part')">游戏</span>
    </div>
    <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
    </div>
  </div>
</template>
<script>

export default {
  methods: {
    btn(targrtPath) {
      this.$router.push({
        path: targrtPath
      });
    }
  }
}

</script>

效果展示

%title插图%num

案例模拟 – 使用 name

  • 在 mian.js 入口文件中,为路由配置中每一个路由设置 name 的值,作为跳转的索引
  • 使用 span 标签绑定对应菜单,并给每个 span 绑定点击事件
  • 给每个绑定的点击事件传入对应 路由的 name 值
  • 在 methods 中定义 编程式导航 方法 this.$router.push() ,并使用传入的参数
  • 实现效果 在 this.$router.push({}) 方式跳转路由时,依据 name路由名 跳转
main.js
const routes = [
  {
    path: '/find',
    name:'Find',
    component: Find,
  },
  {
    path: '/my',
    name:'My',
    component: My,
  },
  {
    path: '/part',
    name:'Part',
    component: Part,
  },
];
Vue
<template>
  <div>
    <div class="footer_wrap">
      <span @click="btn('Find')">发现音乐</span>
      <span @click="btn('My')">我的音乐</span>
      <span @click="btn('Part')">朋友</span>
    </div>
    <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
    </div>
  </div>
</template>
<script>

export default {
  methods: {
    btn(targrtPath) {
      this.$router.push({
        name: targrtPath
      });
    }
  }
}

</script>

效果展示

%title插图%num

# name 方法跳转适用于组内的规范,因为 path 是会在 url中看到,但是 name 在 url 中无法查看 #

直观的说就是:
name 可以随便命名,
path 的命名会影响显示的 url,
因此 name 可以统一 路由组的风格

编程式 – 跳转传参

this.router.push({}) 跳转路由时,使用 $route 属性中 queryparams 来对路由进行传参

  • 传入 query:{“参数名”:值} 等同于 声明式的 /path?参数名 = 值
  • 传入 params:{“参数名”:值} 等同于 声明式的 动态传参 /path/值

说明

  • query 或者 params 任选一个
  • 推荐使用 name + quey 或 name + params 方式传参

注意事项

  • 使用 path 会忽略 params,因此 params 只能使用 name
  • 如果在当前路由中重复跳到当前路由并传参数提示冗余问题报错
    “NavigationDuplicated: Avoided redundant navigation to current location…”,不会跳转路由
基础使用
this.$router.push({
  path: '路由名称',
  name: '路由名',
  query: {
    "参数名": 
  },
  params: {
    "参数名": 
  }
});

案例模拟

  • main.js入口文件 中的路由配置里 定义动态参数的 /:参数名 用于 params 接收参数
  • 对应组件内 使用 $router.params.val $router.query.val 按需接收对应传入的参数
  • App.vue 在 this.router.push({}) 方法中撰写 paramsquery,并传入对应 key 和 值
  • 实现效果:使用 this.$router.push({}) 方式跳转路由时,并传递参数
main.js
const routes = [
  {
    path: '/my',
    name:'My',
    component: My,
  },
  {
    path: '/part/:user/:id',
    component: Part,
  },
];
My.vue
<template>
  <div>
    <li>我的收藏</li>
    <li>我的历史</li>
    <li v-if="$route.query.music">{{ $route.query.music }}</li>
  </div>
</template>
Part.vue
<template>
  <div>
    <li>关注明星</li>
    <li>发现精彩</li>
    <li>寻找伙伴</li>
    <li>加入我们</li>
    <li v-if="$route.params.id">你关注的人:[ID {{ $route.params.id }}] {{ $route.params.user }}</li>
  </div>
</template>
Vue
<template>
  <div>
      <span @click="oneBtn">朋友A</span>
      <span @click="twoBtn">我的音乐</span>
    </div>
    <div class="top">
      <!-- 设置挂载点 -->
      <router-view></router-view>
    </div>
  </div>
</template>
<script>

export default {
  methods: {
    oneBtn() {
      this.$router.push({
        name: 'Part',
        params: {
          id: '233',
          user: '夜夜'
        }
      })
    },
    twoBtn() {
      this.$router.push({
        name: 'My',
        query: {
          music: '菊花台'
        }
      })
    }
  }
}
</script>

效果展示

%title插图%num

$router 与 $route 区别

相关资料来自:脚本之家简书

  • $route 表示 (当前路由信息对象) 用以获取当前路由的 path, name, params, query 等属性
  • this.$router 在 vue 实例内部,通过 this.$router 访问路由实例,实现例如 编程式 跳转等方法
路由嵌套

配置对象的 children 属性可以嵌套 子路由对象子路由url 前面加上 父级url 进行切换

在 路由配置 中定义的 childern 传入的是一个 子路由配置 的对象数组,可使用 /path/path 进行跳转

%title插图%num

说明

%title插图%num
  • 一级路由 path 从 / 开始定义
  • 二级路由往后 path 直接写名字,无需 / 开头
  • 嵌套路由 在上级路由的 childern 数组里编写路由信息对象
  • 子级路由 同 父级一样也是通过 <router-view></router-view> 设置路由的挂载点

案例模拟

  • 定义二级路由文件 Recommend.vue、Ranking.vue、SongList.vue
  • 在 main.js 入口文件的 路由配置 中,为 指定路由增加 childern 属性,引入组件 并 配置对应 子级路由
  • 修改 Find.vue 文件,使用 <router-link> 的 to 路由切换,使用 <router-view></router-view> 挂载点
  • 实现效果:二级嵌套路由的铺设和跳转
Recommend.vue
<template>
  <div>推荐内容</div>
</template>
Ranking.vue
<template>
  <div>推荐内容</div>
</template>
SongList.vue
<template>
  <div>歌单 - 发现音乐内容</div>
</template>
main.js
import Recommend from '@/views/Second/Recommend.vue';
import Ranking from '@/views/Second/Ranking.vue';
import SongList from '@/views/Second/SongList.vue';

...

const routes = [
  ...
  {
    path: '/find',
    name:'Find',
    component: Find,
    // 嵌套的路由前面无需添加 /
    children:[
      {
        path:'recommend',
        component:Recommend,
      },
      {
        path:'ranking',
        component:Ranking,
      },
      {
        path:'songlist',
        component:SongList,
      },
    ]
  },
  ...
];
Find.vue
<template>
  <div class="findBox">
    <div class="menu">
      <router-link to="/find/recommend">推荐</router-link>
      <router-link to="/find/ranking">排行榜</router-link>
      <router-link to="/find/songlist">歌单</router-link>
    </div>
    <div class="content">
      <router-view></router-view>
    </div>
  </div>
</template>

效果展示

%title插图%num
激活类名

使用 <router-link> 时,会根据 url 的 精确/模糊 匹配模式 赋予指定类名

%title插图%num
  • 在 url 的 hash 完全匹配下 路由对应的 a 标签会赋予类  router-link-exact-activerouter-link-active
  • 在 url 的 hash 模糊匹配下 路由对应的 a 标签会赋予类 router-link-active

说明

  • router-link-exact-active 类的添加条件:url的hash值和href完全匹配
  • router-link-active 类的添加条件:url的hash值包含href路径值匹配

案例模拟

  • 实现效果:使完全匹配下的嵌套子级路由呈现选中样式
Find.vue
<template>
  <div class="findBox">
    <div class="menu">
      <router-link to="/find/recommend">推荐</router-link>
      <router-link to="/find/ranking">排行榜</router-link>
      <router-link to="/find/songlist">歌单</router-link>
    </div>
    <div class="content">
      <router-view></router-view>
    </div>
  </div>
</template>
CSS
/* 为 menu 下的 a 标签赋予选中效果 */
.menu a.router-link-exact-active.router-link-active{
  transform: scale(1.1);
  background-color: rgb(204, 65, 65);
}

效果展示

%title插图%num
全局前置守卫

路由跳转之前,会触发 router.beforeEach() 函数,可用作跳转前验证、阻止跳转

该函数常用于跳转前 验证用户是否登录、用户是否有权限等判断。详细文档

main.js
const routes = [
 ...
 ];

const router = new VueRouter({
  routes,
})

//未登录
let isLogin = false;
router.beforeEach((to, from, next) => {
  if (to.path === '/my' && isLogin === false) {
    alert('请登录');
    //阻止路由跳转
    next(false);
  } else {
    next();
  }
});

效果演示

%title插图%num

语法

  • router.beforeEach((to,from,next) => {} ); to 是跳转方对象 from是跳转目标 next是执行跳转
  • 场景:当你要对路由进行权限判断时,需要用到 router.beforeEach()
  • 跳转:next() 路由正常跳转 | next(false) 在原地停留 | next(‘/path’) 强制跳转到传入参数的指定 /path 路径上
成员 描述
to.path 路由要跳转的hash路径目标
to.params 路由跳转携带的params参数
to.name 路由要跳转的路由名目标
from.path 路由跳转前的hash路径
from.name 路由跳转前的路由名
next 函数体,不传值为执行跳转,传入false表示不跳转
路由独享守卫

在路由配置上每项单独定义的 beforeEnter 守卫

beforeEnter 守卫 只在进入路由时触发,不会在 paramsquery 或 hash 改变时触发。

( 例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects
它们只有在 从一个不同的 路由导航时,才会被触发 )

详细内容参考 官方文档

JavaScript
const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // 不进行跳转
      return false
    },
  },
]

你也可以将一个函数数组传递给 beforeEnter 

这在为不同的路由重用守卫时很有用

JavaScript
function removeQueryParams(to) {
  if (Object.keys(to.query).length)
    return { path: to.path, query: {}, hash: to.hash }
}

function removeHash(to) {
  if (to.hash) return { path: to.path, query: to.query, hash: '' }
}

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: [removeQueryParams, removeHash],
  },
  {
    path: '/about',
    component: UserDetails,
    beforeEnter: [removeQueryParams],
  },
]
Vant 组件库
介绍

Vant 是一个轻量、可靠的移动端 Vue组件库,开箱即用

支持移动项目中大多数使用场景的 Vue组件库,包含了组件所需的 js 和 css

相关文档:https://www.w3cschool.cn/vantlesson/
Vant组件库:gitee地址

特点

  • 提供60多个高质量组件,覆盖移动端各类场景
  • 性能极佳,组件平均体积不到1kb
  • 完善的中英文文档示例
  • 支持 Vue2 & Vue3
  • 支持按需引入和主题定制
%title插图%num
全部引入

导入所有 Vant组件

vant 支持一次性导入所有组件,引入所有组件会增加代码包体积,因此不推荐这种做法

tips: 配置按需导入后,将不允许直接导入所有组件

下载包

PowerShell
# yarn 安装 vue2 版本的 vant
yarn add vant@latest-v2
# npm 安装 vue2 版本的 vant
npm install vant@latest-v2

引用包

mian.js
import Vue from 'vue';
// 引入 vant 所有组件
import Vant from 'vant';
import 'vant/lib/index.css';
// 全局注册 vant组件
Vue.use(Vant);

使用 vant组件

查看官网文档,使用 vant提供的标签 制作样式

Vue
<template>
  <div>
    <van-button type="primary">主要按钮</van-button>
    <van-button type="success">成功按钮</van-button>
    <van-button type="default">默认按钮</van-button>
    <van-button type="warning">警告按钮</van-button>
    <van-button type="danger">危险按钮</van-button>
  </div>
</template>

效果展示

%title插图%num
手动按需引入

手动引入使用 vant 的某个组件

手动单独引入,快速了解:官方文档 – 按需引入

说明

  • 引入vent组件 的完整包过于臃肿,我们在使用vant组件时,首先建议按需引入
  • 在 .vue 单文件下引入时,使用 import 用变量命名方式接收导入,并用 components 成员引入
  • 在 .vue 单文件下引入时,要注意使用驼峰命名方式对应标签的 横线命名 例如(<van-button> 等于 VanButton组件)

使用 按需引入 的 vant组件

  • 在 components 引入组件时候,例如 Button组件 时也可以采用 [Button.name]:Button 的方式
  • 下方演示中 [Button.name]:Button 与 VanButton:Button 是等价的。相当于使用它自己提供的标签命名
App.vue
<template>
  <div>
    <van-button type="primary">主要按钮</van-button>
    <van-button type="success">成功按钮</van-button>
    <van-button type="default">默认按钮</van-button>
    <van-button type="warning">警告按钮</van-button>
    <van-button type="danger">危险按钮</van-button>
  </div>
</template>

<script>
// button组件
import Button from 'vant/lib/button';
// button样式
import 'vant/lib/button/style';
export default {
  // 引入组件
  components: {
    // 对应上面标签名 采用横线转驼峰的方式
    VanButton: Button
  }
}
</script>

效果展示

%title插图%num
自动按需引入

使用 babel 的插件 babel-plugin-import ,实现自动按需引入 vant组件

babel-pugin-import 是一款babel插件,他会在编译过程中将 import 的写法自动转换成按需引入的方式

安装插件

PowerShell
# 安装插件
npm i babel-plugin-import -D

配置插件

在 babel.config.js 上进行配置插件后,实现 vant组件 自动按需导入的效果

babel.config.js
module.exports = {
  presets: [
    '@vue/cli-plugin-babel/preset'
  ],
  plugins: [
    ['import', {
      libraryName: 'vant',
      libraryDirectory: 'es',
      style: true
    }, 'vant']
  ]
}

使用插件

  • 直接在 main.js 全局引入需要的 Vant组件,(重启服务器)
  • .vue 单文件 会根据代码中使用的组件 自动转换成 按需引入形式
main.js
// 使用 babel-plugin-import 后会自动按需引入 Vant组件
import { Button } from 'vant';
// Button组件 进行全局注册
Vue.use(Button);
App.vue
<template>
  <div>
    <van-button type="primary">主要按钮</van-button>
    <van-button type="success">成功按钮</van-button>
    <van-button type="default">默认按钮</van-button>
    <van-button type="warning">警告按钮</van-button>
    <van-button type="danger">危险按钮</van-button>
  </div>
</template>

<script>
export default {}
</script>

效果展示

%title插图%num
Vant 弹出框

Vant组件 中的 弹出框样式,用于取代 HTML 自带的 alert() 弹出框

%title插图%num

Vant组件的 弹出模态框,常用于消息提示、消息确认,或在当前页面内完成特定的交互操作。
支持组件调用和函数调用两种方式。相关文档

引入

通过 全局 或 局部 的方式引入 vant弹出框

全局

main.js
import { Dialog } from 'vant';

// 原型链方式注入
Vue.prototype.$dialog = Dialog;
App.vue
<template>
  <div>
    <van-button type="primary" @click="btn">提示</van-button>
  </div>
</template>

<script>
export default {
   methods:{
    btn(){
      this.$dialog({message:'你好Vue!'});
    }
   }
}
</script>

效果展示

%title插图%num

局部

Vue
<template>
  <div class="box">
    <van-button type="primary" @click="btn">提示</van-button>
  </div>
</template>

<script>
import { Dialog } from 'vant';
export default {
   methods:{
    btn(){
      Dialog({message:'你好Vue!'});
    }
   }
}
</script>

效果展示

%title插图%num

参数介绍

Dialog 可以对其配置项的成员对象传参,呈现不同效果

参数 说明 类型 默认值
title 标题 string
width 弹窗宽度,默认单位为 px number | string 320px
message 文本内容,支持通过 \n 换行 string | () => JSX.ELement
messageAlign 内容对齐方式,可选值为 left right string center
theme 样式风格,可选值为 round-button string default
className 自定义类名 string | Array | object
showConfirmButton 是否展示确认按钮 boolean true
showCancelButton 是否展示取消按钮 boolean false
confirmButtonText 确认按钮文案 string 确认
confirmButtonColor 确认按钮颜色 string #ee0a24
confirmButtonDisabled v3.5.0 是否禁用确认按钮 boolean false
cancelButtonText 取消按钮文案 string 取消
cancelButtonColor 取消按钮颜色 string black
cancelButtonDisabled v3.5.0 是否禁用取消按钮 boolean false
overlay 是否展示遮罩层 boolean true
overlayClass 自定义遮罩层类名 string | Array | object
overlayStyle 自定义遮罩层样式 object
closeOnPopstate 是否在页面回退时自动关闭 boolean true
closeOnClickOverlay 是否在点击遮罩层后关闭弹窗 boolean false
lockScroll 是否锁定背景滚动 boolean true
allowHtml 是否允许 message 内容中渲染 HTML boolean false
beforeClose 关闭前的回调函数,返回 false 可阻止关闭,支持返回 Promise (action: string) => boolean | Promise<boolean>
transition 动画类名,等价于 transitionname 属性 string
teleport 指定挂载的节点,等同于 Teleport 组件的 to 属性 string | Element body

案例演示

单击按钮,弹出一个 vent 弹出框;有内容和标题,并取消按钮

Vue
<template>
  <div>
    <van-button type="primary" @click="btn">突发事件</van-button>
  </div>
</template>

<script>
import { Dialog } from 'vant';
export default {
  methods: {
    btn() {
      Dialog({
       message: '提示',
       title:'欸哥们,这瓜多少钱一斤?',
        showCancelButton: true
     });
    }
  }
}
</script>

效果展示

%title插图%num
Vant 登录表单

用 Vant组件库 完成一个基本的 登录页面 所需要的样式和功能

按需在 main.js 引入了vant组件的 Form, Field, CellGroup 组件,并在 vue单页面铺设

说明

vant组件库的组件通常会提供预设的传递方法,例如 <van-form> 的rules是它的 验证规则
详细内容可查阅:https://vant-contrib.gitee.io/vant/#/zh-CN/form

案例演示

完成一个登录页面铺设

mian.js
// 使用 babel-plugin-import 后会自动按需引入 Vant组件
import { Button, Form, Field, CellGroup, Dialog } from 'vant';
// Button组件 进行全局注册
Vue.use(Button);
Vue.use(Form);
Vue.use(Field);
Vue.use(CellGroup);

// 原型链方式注入
Vue.prototype.$dialog = Dialog;
Vue
<template>
  <div>
    <van-form @submit="onSubmit">
      <van-cell-group inset>
        <van-field
        v-model="username"
        name="用户名"
        label="用户名"
        placeholder="用户名"
        :rules="[{ required: true, message: '请填写用户名' }]"
         />
        <van-field 
        v-model="password" 
        type="password" 
        name="密码" 
        label="密码" 
        placeholder="密码"
        :rules="[{ required: true, message: '请填写密码' }]"
         />
      </van-cell-group>
      <div style="margin: 16px;">
        <van-button round block type="primary" native-type="submit">
          提交
        </van-button>
      </div>
    </van-form>
  </div>
</template>

<script>
export default {
  data() {
    return {
      username: '',
      password: ''
    };
  },
  methods: {
    onSubmit(value) {
      this.$dialog({ message: JSON.stringify(value) });
    }
  }
};
</script>

效果展示

%title插图%num
后记

基础内容的笔记已经写完,网站常常报错,不容易啊…

后续知识,请查阅 Vue笔记 更多内容