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 [email protected]
  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插件自动修改规范错误的代码

相关推荐
在下_诸葛18 分钟前
狂神SQL学习笔记六:列的数据类型讲解
笔记·sql·学习
Ⅰㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤㅤ37 分钟前
03 UV
笔记·学习·3dmax
BillKu37 分钟前
遵守 Vue3 的单向数据流原则:父组件传递对象 + 子组件修改对象属性,安全地实现父子组件之间复杂对象的双向绑定示例代码及讲解
javascript·vue.js·elementui
Nuyoah.2 小时前
《vue3学习手记3》
前端·javascript·vue.js·学习·前端框架
初遇你时动了情2 小时前
vue3 uniapp vite 配置之定义指令
javascript·vue.js·uni-app
BillKu2 小时前
reactive 解构赋值给 ref
前端·javascript·vue.js
鑫不想说话1064763 小时前
ts+vue3出乎意料的推导报错
vue.js·typescript
dasseinzumtode3 小时前
在 Vue 3 中实现右键菜单功能
前端·vue.js
楼田莉子3 小时前
C++学习记录:
开发语言·c++·学习
-曾牛3 小时前
Git完全指南:从入门到精通版本控制 ------- Git 查看提交历史(8)
大数据·git·学习·elasticsearch·个人开发