Vue2+Vue3 45-90集学习笔记

Vue2+Vue3 45-90集学习笔记

小兔鲜首页

页面开发思路:

  1. 分析页面,按模块拆分组件,搭架子(局部注册或全局注册)
    • 局部注册:App.js中 导入(import),注册(components),使用(<组件名></组件名>)
  2. 根据设计图编写htmlcss样式
  3. 拆分封装通用小组件(局部或全局注册)
    • 全局注册:main.js中 导入(import),注册(Vue.component('组件名',组件对象)),使用(<组件名></组件名>)

所有都折叠ctrl+k,ctrl+0

所有都展开ctrl+k,ctrl+j

一、组件的三大组成部分

1、注意点说明

  • template:有且只能由一个根元素
  • style:默认为全局样式影响所有组件,如果想限制为局部样式,给组件加上scoped属性,让样式只作用于当前组件
javascript 复制代码
<style scoped>
</style>

scoped原理:

1.给当前组件模板的所有元素都添加上一个自定义属性:data-v-hash值

2.css选择器后面,被自动处理,添加上了属性选择器div[data-v-hash值]

  • script:el根实例独有,data必须是一个函数,其他配置项一致
javascript 复制代码
data() {
	return {
		count:100
	}
}

每次创建新的组件实例,都会新执行一次data函数,得到一个新对象=>保证每个组件实例,维护独立的一个数据对象

二、组件通信

组件通信就是指组件与组件之间的数据传递

为什么要数据传递?

组件的数据是独立的,无法直接访问其他组件的数据,组件只能访问自己的数据

想用其他组件的数据,必须要进行组件通信

组件关系分类:

  • 父子关系:props和$emit
  • 非父子关系:1.provide&inject 2.eventbus

1、父子通信

父组件通过props将数据传递给子组件

子组件利用$emit通知父组件修改更新

javascript 复制代码
//父组件
<template>
  <div>
    <MySon :title="myTitle" @changeTitle="changeFn"></MySon>
  </div>
</template>

<script>
import MySon from './components/MySon.vue'

export default {
  data(){
    return {
      myTitle:'黑马程序员'
    }
  },
  components: {
    MySon
  },
  methods:{
    changeFn(newTitle){
      this.myTitle = newTitle
    }
  }
}
</script>

<style>
</style>
javascript 复制代码
//子组件
<template>
  <div>我是子组件
    {{ title }}
    <button @click="handleClick">修改title</button>
  </div>
</template>

<script>
export default {
  props:['title'],
  methods:{
    handleClick(){
      this.$emit('changeTitle','传智教育')
    }
  }
}
</script>

<style scoped>
</style>

父传子步骤

1.给子组件以添加属性的方式传值

2.在子组件内通过props接收数据

在子组件模板中直接使用
子传父步骤

1.在子组件内使用$emit触发事件,给父组件发送消息通知
this.$emit('事件名','传递过去的参数')

2.父组件监听事件

3.提供处理函数,形参会获取传递过来的参数

2、props详解

(1)什么是prop

prop定义:组件上注册的一些自定义属性

prop作用:向子组件传递数据

(2)prop校验

作用:为组件的prop指定验证要求,不符合要求,控制台就会有错误提示=>帮助开发者,快速发现错误

javascript 复制代码
props:{
	校验的属性名:类型 //Number/String/Boolean
}

更细致的校验要求

javascript 复制代码
props:{
	校验的属性名:{
		type:类型,//Number/String/Boolean
		required:true,//是否必填
		default:默认值,//默认值
		validator(value){
			//自定义校验逻辑
			return 是否通过校验(true/false)
		}
	}
}
(3)prop&data、单向数据流

共同点:都可以给组件提供数据

不同点:

  • data数据是自己的=>随便改(谁的数据谁负责)
  • prop数据是外部的=>不能直接改,单向数据流

子组件想要修改props数据,需要通过子传父通知到父组件,在父组件内修改

javascript 复制代码
//父组件
<template>
  <div>
    <MySon :count="count" @changeCount="changeFn"></MySon>
  </div>
</template>

<script>
import MySon from './components/MySon.vue'

export default {
  data(){
    return {
      count:999
    }
  },
  components: {
    MySon
  },
  methods:{
    changeFn(newCount){
      this.count = newCount
    }
  }
}
</script>

<style>
</style>
javascript 复制代码
//子组件
<template>
  <div>
    <button @click="handleSub">-</button>
    {{ count }}
    <button @click="handleAdd">+</button>
  </div>
</template>

<script>
export default {
  props:{
    count:{
      type:Number
    }
  },
  methods:{
    handleAdd(){
    //不可以使用this.count++,这样就修改了子组件内的count了
      this.$emit('changeCount',this.count+1)
    },
    handleSub(){
    //不可以使用this.count--,这样就修改了子组件内的count了
      this.$emit('changeCount',this.count-1)
    }
  }
}
</script>

<style scoped>

</style>

单向数据流:父组件的prop更新,会单向的向下流动,进而影响子组件,这个数据是单向流动的

三、综合案例:小黑记事本(组件版)

  1. 拆分基础组件
    新建组件 -> 拆分存放结构 -> 导入注册使用
  2. 渲染功能
    • 提供数据 => 提供在公共的父组件内 App.vue
    • 通过父传子,将数据传递给子组件
    • 利用v-for渲染
  3. 添加功能
    • 收集表单数据 => v-model
    • 监听事件(回车+点击 都要监听)
    • 子传父,将任务名称传递给父组件
    • 将任务名称添加到任务数组中unshift添加到数组最前面
  4. 删除功能
    • 监听点击事件 携带需删除的任务id
    • 子传父 ,将任务id传递给父组件
    • 在父组件内,任务数组中将 id===任务id 的任务删除filter方法
  5. 底部合计
    • 父传子任务数组
    • 在子组件内渲染任务数组的长度
  6. 清空功能
    • 监听点击事件
    • 子传父 通知父组件在父组件内清空任务数组
  7. 持久化存储
    • watch深度监视list变化 => 往本地存储,一进页面优先读取

四、非父子通信(拓展)-event bus 事件总线

作用:非父子组件之间,进行简易消息传递

  1. 创建一个都能访问到的事件总线(空Vue实例)
js 复制代码
import Vue from 'vue'
const Bus = new Vue()
export default Bus
  1. A组件(接收方),监听Bus实例的事件
js 复制代码
created () {
  Bus.$on('sendMsg', (msg) => {
    this.msg = msg
  })
}
  1. B组件(发送方),触发Bus实例的事件
js 复制代码
Bus.$emit('sendMsg', '这是一个消息')

五、非父子通信(拓展)-provide-inject

作用:跨层级共享数据

  1. 父组件 provide提供数据
js 复制代码
export default {
  provide () {
    return {
       // 普通类型【非响应式】
       color: this.color, 
       // 复杂类型【响应式】
       userInfo: this.userInfo, 
    }
  }
}

2.子/孙组件 inject获取数据

js 复制代码
export default {
  inject: ['color','userInfo'],
  created () {
    console.log(this.color, this.userInfo)
  }
}

注意

provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)

子/孙组件通过inject获取的数据,不能在自身组件内修改

六、v-model详解

1、v-model原理

原理:v-model本质上是个语法糖

作用:实现数据的双向绑定

  1. 数据变,视图跟着变 :value
  2. 视图变,数据跟着变 @input$event用于在模板中,获取事件的形参
javascript 复制代码
<input v-model='msg' type='text'>
等于
<input :value='msg' @input='msg=$event.target.value' type='text'>

模板中获取事件的形参需要用$event获取\

2、表单类组件封装、v-model简化代码

  1. 表单类组件的封装
    • 父传子:数据由父组件props传递过来的,v-model拆解绑定数据(因为子组件不能直接修改父组件的数据)
    • 子传父:监听输入,子传父传值给父组件修改

App.vue

js 复制代码
<template>
  <div class="app">
    <BaseSelect :cityId='selectId' @changeId='selectId = $event'></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  }
}
</script>

<style>
</style>

BaseSelect.vue

js 复制代码
<template>
  <div>
    <select :value='cityId' @change='handleChange'>
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
  props:{
    cityId:String
  },
  methods:{
    handleChange(e){
      this.$emit('changeId',e.target.value)
    }
  }
}
</script>

<style>
</style>
  1. 父组件v-model简化代码,实现子组件和父组件数据双向绑定
    • 子组件中,props通过values接收,事件触发input
    • 父组件中,v-model给组件直接绑定数据

子组件

js 复制代码
//父传子3.子组件使用   子传父1.添加监听
<select :value="value" @change="handleChange">...</select>
//父传子2.子组件props接收
props: {
  value: String
},
methods: {
  //子传父2.设置监听函数
  handleChange (e) {
    this.$emit('input', e.target.value)
  }
}

父组件

js 复制代码
<BaseSelect v-model="selectId"></BaseSelect>
等于
<BaseSelect :value="selectId" @input="selectId = 传入的参数"></BaseSelect>
//父传子1.子组件引入属性   子传父3.监听input,函数的形参接收

七、.sync修饰符

作用:可以实现子组件与父组件数据的双向绑定,简化代码

特点:prop属性名,可以自定义,非固定为value

本质::属性名@update:属性名合写

js 复制代码
<BaseSelect :visible.sync="selectId"></BaseSelect>
等于
<BaseSelect :visible="isShow" @update:visible="isShow = 传入的参数($event)"></BaseSelect>

App.vue

js 复制代码
<template>
  <div class="app">
    <button @click="isShow=true">退出按钮</butto
    //父传子1:注册属性 :visible='isShow'
    //子传父3:监听通知事件 @update.visible='isShow=$event'
    <BaseDialog :visible.sync='isShow'></BaseDialog>
  </div>
</template>

<script>
import BaseDialog from './components/BaseDialog.vue'
export default {
  data() {
    return {
      isShow: false,
    }
  },
  components: {
    BaseDialog,
  },
}
</script>

<style>
</style>

BaseDialog.vue

js 复制代码
<template>
  <div class="base-dialog-wrap" v-show="visible">//父传子3:子组件内渲染
    <div class="base-dialog">
      <div class="title">
        <h3>温馨提示:</h3>
        <button class="close" @click='handleClick'>x</button>//子传父1:监听点击事件
      </div>
      <div class="content">
        <p>你确认要退出本系统么?</p>
      </div>
      <div class="footer">
        <button @click='handleClick'>确认</button>//子传父1:监听点击事件
        <button @click='handleClick'>取消</button>//子传父1:监听点击事件
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
  	//父传子2:props接收
    visible: Boolean,
  },
  methods:{
    handleClick(){
    	//子传父2:给父组件传递通知
      this.$emit('update:visible',false)
    }
  }
}
</script>

<style scoped>
</style>

八、ref和$ref

作用:利用ref和$ref可以用于获取dom元素,或组件实例

特点:查找范围->当前组件内,更精确稳定

获取dom

  • 目标标签-添加ref属性
html 复制代码
<div ref="chartRef">我是渲染图表的容器</div>
js 复制代码
mounted () {
  console.log(this.$refs.chartRef)
}

获取组件

  • 目标组件-添加ref属性
javascript 复制代码
<BaseForm ref='baseForm'></BaseForm>
  • 恰当时机,通过this.$ref.xxx,获取目标组件,就可以调用组件对象里面的方法
javascript 复制代码
this.$refs.baseForm.组件方法()

九、Vue异步更新、$nextTick

Vue 是异步更新DOM (提升性能):代码执行完时,当前dom并没有立即更新
$nextTick:等dom更新后,才会触发执行此方法里的函数

语法:this.$nextTick(函数体)

javascript 复制代码
this.$nextTick(()=>{
	this.$refs.inp.focus()
})

十、自定义指令

1、自定义指令

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

语法:

  • 全局注册
javascript 复制代码
//在main.js中
Vue.directive('指令名', {
 "inserted" (el) {
   // 可以对 el 标签,扩展额外功能
   el.focus()
 }
})
  • 局部注册
javascript 复制代码
//在Vue组件的配置项中
directives: {
  "指令名": {
    inserted () {
      // 可以对 el 标签,扩展额外功能
      el.focus()
    }
  }
}
  • 使用自定义指令
    一定要先注册,再使用 ,否则会报错
    使用语法:v-指令名
  • 指令中配置项介绍
    • inserted:被绑定元素插入父节点时调用的钩子函数
    • el:使用指令的那个DOM元素,DOM元素添加了自定义指令后,el会与其绑定
javascript 复制代码
//局部注册自定义属性
directives:{
  focus:{
    inserted(){
      el.foucus
    }
  }
}

//全局注册自定义属性
Vue.directive(focus,{
  "inserted"(el){
    el.focus
  }
})
javascript 复制代码
//使用
<div>
  <h1>自定义指令</h1>
  <input v-focus ref="inp" type="text">
</div>

2、自定义指令的值

javascript 复制代码
//使用
<div v-color="color">我是内容</div>
//定义
directives: {
  color: {
    inserted (el, binding) {
      el.style.color = binding.value
    },
    update (el, binding) {
      el.style.color = binding.value
    }
  }
}
  1. 在绑定指令时,可以通过等号为自定义指令绑定具体的值
  2. 通过binding.value可以拿到指令的值,当其修改时会触发update函数,否则当修改binding.value的值时不会重新渲染

3、v-loading

1、场景

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

2、需求

封装一个 v-loading 指令,实现加载中的效果

3、实现

  1. 准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层
  2. 开启关闭 loading状态(添加移除蒙层),本质只需要添加移除类即可
  3. 结合自定义指令的语法进行封装复用
javascript 复制代码
<template>
  <div class="main">
    <div class="box" v-loading='isLoading'>
      <ul>
        <li v-for="item in list" :key="item.id" class="news">
          <div class="left">
            <div class="title">{{ item.title }}</div>
            <div class="info">
              <span>{{ item.source }}</span>
              <span>{{ item.time }}</span>
            </div>
          </div>
          <div class="right">
            <img :src="item.img" alt="">
          </div>
        </li>
      </ul>
    </div> 
  </div>
</template>

<script>
// 安装axios =>  yarn add axios || npm i axios
import axios from 'axios'

// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
export default {
  data () {
    return {
      list: [],
      isLoading: true
    }
  },
  async created () {
    // 1. 发送请求获取数据
    const res = await axios.get('http://hmajax.itheima.net/api/news')
    
    setTimeout(() => {
      // 2. 更新到 list 中,用于页面渲染 v-for
      this.list = res.data.data
      this.isLoading = false
    }, 2000)
  },
  directives:{
  	loading:{
		inserted(el,binding){
			binding.value ? el.classList.add('loading') : el.classList.remove('loading') 
		},
		updata(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('./loading.gif') no-repeat center;
}
.box {
  width: 800px;
  min-height: 500px;
  border: 3px solid orange;
  border-radius: 5px;
  position: relative;
}
.news {
  display: flex;
  height: 120px;
  width: 600px;
  margin: 0 auto;
  padding: 20px 0;
  cursor: pointer;
}
.news .left {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-right: 10px;
}
.news .left .title {
  font-size: 20px;
}
.news .left .info {
  color: #999999;
}
.news .left .info span {
  margin-right: 20px;
}
.news .right {
  width: 160px;
  height: 120px;
}
.news .right img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
</style>

十一、插槽

1、默认插槽

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

2、需求:将需要多次显示的对话框封装成一个组件,组件的内容部分不希望写死,希望使用的时候可以自定义

3、基本语法:

  • 组件内需要定制的结构部分,改用<slot></slot> 占位
  • 使用组件时,组件标签的内部填入slot的内容
  • 给插槽传入内容时,可以传入纯文本、html标签、组件

MyDialog.vue

javascript 复制代码
<template>
  <div class="dialog">
    <div class="dialog-header">
      <h3>友情提示</h3>
      <span class="close">✖️</span>
    </div>

    <div class="dialog-content">
      <slot></slot>//在需要定制的位置,使用slot占位
    </div>
    <div class="dialog-footer">
      <button>取消</button>
      <button>确认</button>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {

    }
  }
}
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
}
.dialog {
  width: 470px;
  height: 230px;
  padding: 0 25px;
  background-color: #ffffff;
  margin: 40px auto;
  border-radius: 5px;
}
.dialog-header {
  height: 70px;
  line-height: 70px;
  font-size: 20px;
  border-bottom: 1px solid #ccc;
  position: relative;
}
.dialog-header .close {
  position: absolute;
  right: 0px;
  top: 0px;
  cursor: pointer;
}
.dialog-content {
  height: 80px;
  font-size: 18px;
  padding: 15px 0;
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
}
.dialog-footer button {
  width: 65px;
  height: 35px;
  background-color: #ffffff;
  border: 1px solid #e1e3e9;
  cursor: pointer;
  outline: none;
  margin-left: 10px;
  border-radius: 3px;
}
.dialog-footer button:last-child {
  background-color: #007acc;
  color: #fff;
}
</style>

App.vue

javascript 复制代码
<template>
  <div>
    <MyDialog>
    	你确认要删除么?//在使用组件时,组件标签内填入内容
    </MyDialog>
  </div>
</template>

<script>
import MyDialog from './components/MyDialog.vue'
export default {
  data () {
    return {

    }
  },
  components: {
    MyDialog
  }
}
</script>

<style>
body {
  background-color: #b3b3b3;
}
</style>

2、后备内容

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

<slot></slot>标签内,放置内容, 作为默认显示内容(即如果在使用组件时为插槽传入内容则显示传入的内容,否则将显示在<slot></slot>内放置的默认内容)

3、具名插槽

默认插槽:一个定制的位置

具名插槽:给多个slot起名字从而定制多个位置

  1. 给slot使用name属性区分名字
  2. template配合v-slot来对应定制的位置,v-slot可以简写为#

4、作用域插槽

(1)插槽分为默认插槽和具名插槽

(2)作用域插槽的作用:给插槽上绑定数据,将来使用组件时就可以用

(3)使用步骤

  1. 给slot标签以添加属性的方式传值
javascript 复制代码
<slot :id='item.id' msg='测试文本'></slot>
  1. 所有添加的属性都会被收集到一个对象之中
javascript 复制代码
{id:3,msg:'测试文本'}
  1. 在template中,通过#插槽名='obj'接收,默认插槽名为default
javascript 复制代码
<组件名 :list='list'>
	<template #default = 'obj'>
		<button @click='del(obj.id)'>删除</button>
	</template>
</组件名>

MyTable.vue

js 复制代码
<template>
  <table class="my-table">
    <thead>
      <tr>
        <th>序号</th>
        <th>姓名</th>
        <th>年纪</th>
        <th>操作</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for='(item,index) in data'>
        <td>{{index + 1}}</td>
        <td>{{item.name}}</td>
        <td>{{item.age}}</td>
        <td>
          //1.给slot以添加属性的方式传值
          <slot :row='item'></slot>
          //2.将所有的属性添加到一个对象中,例如
          //{
          //	row:{id:1,name:xxx,age:18}
          //}
        </td>
      </tr>
    </tbody>
  </table>
</template>

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

<style scoped>
.my-table {
  width: 450px;
  text-align: center;
  border: 1px solid #ccc;
  font-size: 24px;
  margin: 30px auto;
}
.my-table thead {
  background-color: #1f74ff;
  color: #fff;
}
.my-table thead th {
  font-weight: normal;
}
.my-table thead tr {
  line-height: 40px;
}
.my-table th,
.my-table td {
  border-bottom: 1px solid #ccc;
  border-right: 1px solid #ccc;
}
.my-table td:last-child {
  border-right: none;
}
.my-table tr:last-child td {
  border-bottom: none;
}
.my-table button {
  width: 65px;
  height: 35px;
  font-size: 18px;
  border: 1px solid #ccc;
  outline: none;
  border-radius: 3px;
  cursor: pointer;
  background-color: #ffffff;
  margin-left: 5px;
}
</style>

App.vue

js 复制代码
<template>
  <div>
    <MyTable :data="list">
      //通过template #插槽名='变量名'来接受上述对象
      <template #default='obj'>
        <button @click='del(obj.item.id)'>删除</button>
      </template>
    </MyTable>
    <MyTable :data="list2">
      <template #default='obj'>
        <button @click='show(obj.item)'>查看</button>
      </template>
    </MyTable>
  </div>
</template>

<script>
  import MyTable from './components/MyTable.vue'
  export default {
    data () {
      return {
     	list: [
            { id: 1, name: '张小花', age: 18 },
            { id: 2, name: '孙大明', age: 19 },
            { id: 3, name: '刘德忠', age: 17 },
          ],
          list2: [
            { id: 1, name: '赵小云', age: 18 },
            { id: 2, name: '刘蓓蓓', age: 19 },
            { id: 3, name: '姜肖泰', age: 17 },
          ]
      }
    },
    methods:{
      del(id){
        this.list = this.list.filter(item=>item.id!==id)
      },
      show(row){
        console.log(row)
      }
    }
    components: {
      MyTable
    }
  }
</script>

十二、路由入门

1、单页应用程序&路由介绍

单页应用程序:SPA-Single Page Application是指所有的功能都在一个html页面 上实现

单页面应用程序,之所以开发效率高,性能好,用户体验好

最大的原因就是:页面按需更新

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

访问路径 和 组件的对应关系如何确定呢? 路由

Vue中的路由:路径和组件映射关系

2、路由的基本使用

(1)VueRouter介绍

作用:修改 地址栏路径时,切换显示 匹配的组件

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

使用步骤(5+2)

固定5个步骤:

  1. 下载 VueRouter 模块到当前工程,版本3.6.5
bash 复制代码
npm add vue-router@3.6.5
  1. main.js中引入VueRouter
js 复制代码
import VueRouter from 'vue-router'
  1. 安装注册(main.js)
js 复制代码
Vue.use(VueRouter)
  1. 创建路由对象(main.js)
js 复制代码
const router = new VueRouter()
  1. 注入,将路由对象注入到new Vue实例中,建立关联(main.js)
js 复制代码
new Vue({
  render: h => h(App),
  router:router
}).$mount('#app')

2个核心步骤

  • 创建需要的组件 (views目录),配置路由规则
js 复制代码
//在main.js中
import Find from './views/Find'
import My from './views/My'
import Friend from './views/Friend'

const router = new VueRouter({
  routers:[
    {path:"/find",component:Find},
    {path:"/my",component:My},
    {path:"/friend",component:Friend}
  ]
})
  • 配置导航,配置路由出口(路径匹配的组件显示的位置)
js 复制代码
<div class="top">
//配置导航
  <a href="#/find">发现</a>
  <a href="#/find">我的</a>
  <a href="#/find">朋友</a>
</div>
<div class="content">
//配置路由出口
  <router-view></router-view>
</div>

3、views目录和components目录

.vue文件分为2类,都是 .vue文件(本质无区别)

  • 页面组件 (配置路由规则时使用的组件)
  • 复用组件(多个组件中都使用到的组件)
  1. src/views文件夹

    页面组件 - 页面展示 - 配合路由用

  2. src/components文件夹

    复用组件 - 展示数据 - 常用于复用

4、路由的模块封装

目标:将路由模块抽离出来,更利于维护

方法:将main.js中的路由配置抽离到router/index.js中,并在main.js中导入impor router from './router/index.js'

注意:更改原来组件的路径

路径简写:
脚手架环境下 @指代src目录,可以用于快速引入组件

javascript 复制代码
import Find from './views/Find'
import My from './views/My'
import Friend from './views/Friend'
等于
import Find from '@/views/Find'
import My from '@/views/My'
import Friend from '@/views/Friend'

5、使用router-link替代a标签实现高亮

(1)使用router-link替代a标签实现高亮

javascript 复制代码
<div>
  <div class="footer_wrap">
    <router-link to="/find">发现音乐</router-link>
    <router-link to="/my">我的音乐</router-link>
    <router-link to="/friend">朋友</router-link>
  </div>
  <div class="top">
    <router-view></router-view>
  </div>
</div>

对比a标签

js 复制代码
<div class="top">
//配置导航
  <a href="#/find">发现</a>
  <a href="#/find">我的</a>
  <a href="#/find">朋友</a>
</div>
<div class="content">
//配置路由出口
  <router-view></router-view>
</div>

(2)功能:

  1. 能跳转:配置to属性指定路径(必须),无需#,本质还是a标签
  2. 能高亮,默认会提供高亮类名,可以设置高亮样式
    • 使用router-link跳转后,当前点击的链接默认加了两个class的值 router-link-exact-activerouter-link-active
    • 给任意一个class属性添加高亮样式即可实现功能

router-link-exact-activerouter-link-active的区别:

  1. router-link-active模糊匹配:to="/my" 可以匹配 /my、/my/a、/my/b ...
  2. router-link-exact-active精确匹配:to="/my" 仅可以匹配 /my

(3) 声明式导航:

router-link两个高亮类名太长了

javascript 复制代码
const router = new VueRouter({
  routes: [...],
  linkActiveClass: "类名1",//配置模糊匹配的类名
  linkExactActiveClass: "类名2"//配置精确匹配的类名
})

十三、声明式导航-跳转传参

目标:在跳转路由时进行传值

1、跳转传参

  1. 查询参数传参
  • 语法格式:<router-link to="/path?参数名1=值1&参数名2=值2"></router-link>
  • 对应页面接受传递过来的值:$route.query.参数名
javascript 复制代码
//Home
<div class="hot-link">
  热门搜索:
  <router-link to="/search?key=黑马程序员">黑马程序员</router-link>
  <router-link to="/search?key=前端培训">前端培训</router-link>
  <router-link to="/search?key=如何成为前端大牛">如何成为前端大牛</router-link>
</div>

//Search
<p>搜索关键字: {{ $router.query.key }}</p>
  1. 动态路由传参
  • 配置动态路由
javascript 复制代码
const router = new VueRouter({
  routes: [
    ...,
    { 
      path: '/search/:words', //配置动态路由
      component: Search 
    }
  ]
})
  • 配置导航链接
javascript 复制代码
规则:to="/path/参数值"
<router-link to="/search/黑马程序员">黑马程序员</router-link>
<router-link to="/search/前端培训">前端培训</router-link>
<router-link to="/search/如何成为前端大牛">如何成为前端大牛</router-link>
  • 对应页面组件接收传递过来的值
javascript 复制代码
规则:$route.params.参数名
<p>搜索关键字: {{ $router.params.words }}</p>
  1. 差异
    查询参数传参:比较适合传多个参数
    动态路由传参:比较适合传单个参数
  2. 动态路由参数的可选符
javascript 复制代码
const router = new VueRouter({
  routes: [
    ...,
    { 
      path: '/search/:words?', //加上问号,可以不传参数
      component: Search 
    }
  ]
})

十四、Vue路由的重定向

重定向 => 匹配 / 后, 强制跳转 /home 路径\

javascript 复制代码
{ path: 匹配路径, redirect: 重定向到的路径 },
比如:
const router = new VueRouter({
	routes:[
		{path:'/',redirect:'/home'},
		...
	]
})

十四、Vue路由的404

当路径找不到匹配时,给个提示页面

javascript 复制代码
import NotFind from '@/views/NotFind'

const router = new VueRouter({
  routes: [
    ...
    { path: '*', component: NotFind } 
  ]
})

path:'*'前面的路径都匹配不上就命中最后这个路径,所以一定要放在最后一个

十五、Vue路由-模式设置

路由的路径看起来不自然, 有#,使用history路由看起来更加自然

hash路由和history路由对比:

hash路由(默认): http://localhost:8080/#/home

history路由:http://localhost:8080/home

javascript 复制代码
const router = new VueRouter({
    mode:'histroy', //默认是hash
    routes:[]
})

十六、编程式导航-两种路由跳转方式

点击按钮可以实现跳转

  1. path路径跳转(简单方便)
    $router指大的路由实例对象
javascript 复制代码
//简单写法
this.$router.push('路由路径')//路由路径:/home或/search....

//完整写法
this.$router.push({
  path: '路由路径'
})

路由路径:/home或/search...

  1. name命名路由跳转(适合path路径长的场景)

配置路由时起个名字

javascript 复制代码
const router = new VueRouter({
  routes: [
    ...
    { name:'路由名',path: '/path/xxx', component: xxx } 
  ]
})

通过name进行跳转

javascript 复制代码
this.$router.push({
  name: '路由名'
})

十七、路由跳转+传参

1、query传参+path跳转

javascript 复制代码
//简单写法
this.$router.push('/路径?参数名1=值1&参数名2=值2')

//完整写法
this.$router.push({
	path:'/路径',
	query:{
		参数名1:'参数值1',
		参数名2:'参数值2'
	}
})

2、query传参+name跳转

javascript 复制代码
const router = new VueRouter({
	routes:[
		{name:'路由名',path:'/path/xxx',component:xxx}
	]
})
this.$router.push({
	name:'路由名',
	query:{
		参数名1:'参数值1',
		参数名2:'参数值2'
	}
})

3、动态路由传参+path跳转

javascript 复制代码
//简单写法
this.$router.push('/路径/参数值')

//完整写法
this.$router.push({
	path:'/路径/参数值',
})

4、动态路由传参+name跳转

javascript 复制代码
const router = new VueRouter({
	routes:[
		{name:'路由名',path:'/path/:参数名',component:xxx}
	]
})

this.$router.push({
	name:'路由名',
	params:{	
		参数名:'参数值'
	}
})

十八、VueCli自定义创建项目

目标:基于VueCli自定义创建项目架子

javascript 复制代码
vue create demo

十九、ESlint代码规范

下载ESlint插件自动修改规范错误的代码

相关推荐
OpenTiny社区2 小时前
从零开发 AI 聊天页要两周?试试这款 Vue3 垂直对话组件库 TinyRobot,直接开箱即用
前端·vue.js·github
Cobyte2 小时前
22.Vue Vapor 组件 props 的实现
前端·javascript·vue.js
白雾茫茫丶4 小时前
探索 Nuxt.js 全栈能力:用 Better-Auth 打造类型安全的 RBAC 权限系统
前端·vue.js·nuxt.js
向阳而生6604 小时前
文件上传也能玩出花?Vue3 教你优雅实现“选择文件”和“选择文件夹”🚀
vue.js
3630458414 小时前
Signal 带来的架构问题思考
前端·vue.js
古夕1 天前
第三方 SSO 接入实践:redirect_uri 编码、回调一致性与跨项目联调
前端·vue.js
Ruihong1 天前
Vue withDefaults 转 React:VuReact 怎么处理?
vue.js·react.js·面试
稀土熊猫君1 天前
一个人能做出什么开源项目?
vue.js·后端·开源
DarkLONGLOVE2 天前
快速上手 Pinia!Vue3 极简状态管理使用教程
javascript·vue.js
宸翰2 天前
解决 uni-app App 端 vue-i18n 占位符丢失:封装跨端可用的 tf 格式化方法
前端·vue.js·uni-app