Vue2 / 3

2 3 3

vue2 vuerouter3 vuex

3 4 4

vue3 vuerouter4 vuex4

1. 思路

做任何需求的套路:

  1. 先铺设标签和样式
  2. 铺设数据(固定数据/js动态创建数据/后台返回数据)
  3. 写交互,多思考用户在页面上的动作,实现对应功能的代码
  4. 如果需要把用户输入的值/动作的结果,返回给后台,则调用后台接口即可

核心步骤

  1. 准备容器
  2. 引包
  3. 创建vue实例new Vue()
  4. 指定配置项------>渲染数据
    • el 指定挂载点(通过el冒号配置选择器,指定Vue管理的是哪个盒子)
    • data 提供数据(提供变量)

el后面跟上一个选择器

vue.js网址(引包)

v2.cn.vuejs.org

cn.vuejs.org

可以下载👇


也可以访问在线链接👇

<script src="https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.js"></script>

一旦引入vuejs核心包,在全局环境中,就有了vue构造函数

👇

有构造函数就可以创建实例了呀

js 复制代码
    <script>
        const app=new Vue()
    </script>

👇

指定配置项(el,data)

2. 插值表达式

3. Vue指令:v-

  • v-html="",用来设置innerhtml
  • v-show="" 和 v-if=""
  • v-else 和 v-else-if=""
  • v-on:事件名="一段可执行的代码"(v-on:可简写为@)
  • v-on:事件名="methods中的函数名"(@)

this指向的也就是你当前的实例(data上的数据是挂在你const的实例上的)

  • el,data,methods是并列的
  • v-bind:属性名="表达式" 动态设置html的标签属性(src,url,title)(可省略v-bind,直接冒号...)
    • 可操作:class="{}"/"[]"
      *
      1. 传对象(导航栏点击高亮显示,适用于一个类名的来回切换)(键就是类名,值是布尔值,如果为true就说明有这个类,否则没有)
      • <li v-for="(item,index) in list" :key="item.id" @click="activeIndex=index"><a :class="{active:index===activeIndex}" href="#">{{item.name}}</a></li>
        1. 传数组
    • 可操作style :style="css属性名:属性值"
  • v-for="(item,index) in 数组"(这个数组就是你data里的一组数据)
  • v-model='data里的变量',双向数据绑定(获取和设置)
    • 应用于一些表单元素:
    • 输入框input
    • 文本域textarea
    • 复选框 input:checkbox
    • 单选框 input:radio
    • 下拉菜单 select

删除列表对应项的思路(小黑书架)

不用改变flag布尔值的方式的原因是:你的数据是通过v-for渲染的,所以一删都删
思路

  • 根据index下标删
  • 根据id删(一般就用这个,id是唯一标识,更加稳定)

😙小黑记事本需求

  1. 列表渲染 v-for
  2. 删除功能v-on(@click)
  3. 添加功能v-on(@click)
  4. 底部统计 和 清空(插值表达式,@click)

4. 指令的修饰符

5. 计算属性,配置项computed

声明在computed中的,一个计算属性对应一个函数

methods与computed的区别

  • computed计算属性是基于它们的依赖依赖属性进行缓存的,只有在它的相关依赖发生改变时才会重新求值

  • 而methods只要被触发就会重新渲染,调用执行

😙成绩表单需求

  1. 渲染功能(v-for,:key)
  2. 删除功能
    • (@click.prevent="del(item.id)",prevent表示点击后不刷新页面,也就是阻止默认行为)
  3. 添加功能
  4. 统计总分,求平均分(计算属性,页面直接插值表达式调用就行)
    • v-model绑定数据,再用methods方法绑定点击事件
js 复制代码
this.list.unshift({ 
    id:+new Date(),
    subject:this.subject,
    score:this.score 
})

不过一般这种添加功能 的时候,方法里一般会有三部分

  • 判断输入是否为正确的格式
  • 添加
  • 最后清除输入框内文字

6. watch监听器(与data等并列)

vue第二天

😙Vue水果购物车

全选反选

说明是双向的

  • 当全部一个个勾选上时------要自动勾选全选
    • 必须小选框都选中,全选按钮才选中,用every
  • 当勾全选时------上面也要全部反选上
    • 全选框用v-model="isAll"
    • 因为你也需要在点击全选框修改值,所以这个计算方法要用完整写法(需要修改值,就必须用完整写法;因为默认简写的形式是不能修改值的)
    • 要让所有小选框同步状态,所以用for each
  • 小选框------v-model="item.isChecked"
  • 全选框------v-model="isAll"

统计总数与总价

跟之前那个成绩表单不同

  • 成绩表单是只要加入进去的数据的成绩都是有用的,所以整体求和
  • 但是这个购物车的统计是有选择性的,只有你勾选上它才参与统计

7. Vue生命周期和其生命周期的四个阶段和钩子函数

四个阶段:

  1. 创建
  2. 渲染(挂载)
  3. 更新
  4. 销毁
    生命周期函数也就是钩子函数

😙小黑记账清单需求

  1. 基本渲染
  2. 添加功能
  3. 删除功能
  4. 饼图渲染

发送请求修改的是后端数据,所以必须再重新渲染一遍,这样前端页面也就可以看到变化了 饼图暂时没复习,等有需要了再来看.........


8. 工程化开发和脚手架vue cli

9. 父子关系

父 ------> 子

  1. 给父组件中的子组件添加自定义属性,并传值(子组件以添加属性的方式传值)
  2. 父组件 通过props------将数据传递给组件

props是在子组件中的,子组件在props里去接收父组件的数据

  1. 子组件使用
  • 就是现在想把父组件'学前端,来黑马!'这个title用在子组件中

子 ------> 父

  1. 先在子组件里写好按钮,注册好事件,并写好方法
  2. 子组件 在这个方法里利用$emit------通知组件去修改更新
  3. 父组件需要接收这个消息,所以在父组件中的子组件上绑上监听
  4. 父组件中提供对应处理的逻辑函数

10. props校验

js 复制代码
props: {
    w: {
      type: Number,
      required: true,
      default: 0,
      validator(val) {
        // console.log(val)
        if (val >= 100 || val <= 0) {
          console.error('传入的范围必须是0-100之间')
          return false
        } else {
          return true
        }
      },
    },
  },
}

😙小黑记事本------组件通信

  1. 拆分组件(分成头,身,底)
  2. 渲染待办事件
  3. 添加任务
  4. 删除
  5. 合计和清空
  6. 持续化存储

但凡数据变化了,我们都需要往本地里去存储

  • 所以我们用watch去深度监听myList的变化
  • 监视后往本地里存
  • 进入页面优先读取本地
js 复制代码
//父组件中(是与methods并列的)


//尝试从 `localStorage` 中获取名为 `'myList'` 的项的值,并将其解析为一个JavaScript对象或数组,然后将这个值赋给 `myList` 属性。

//localStorage.getItem('list')得到的是一个json字符串
//我们还需要把它转成对象 JSON.parse
 myList: JSON.parse(localStorage.getItem('list')) ||[
 ...
 ]


watch: {
    myList: {
      deep: true,//深度监视
      //处理函数
      handler(newVal) {
      // 监视完------往本地里存
        localStorage.setItem('list', JSON.stringify(newVal))
      },
    },
  },

11. 非父子通信------eventbus事件总线(更复杂的话就用vuex,不复杂就可以用这个)

12. 非父子通信------provide和inject(跨层级共享数据)

13. v-model详解和简写(子父双向绑定)

  • 数据变,视图跟着变:value
  • 视图变,数据跟着变@input

相当于

为什么要把v-model拆开用??

  • 假如你现在写一个下拉表单
    • 因为你的数据是写在父组件里的
    • 但是你的v-model是双向绑定,但是父传子又是单向数据流,所以不能用

14. .sync修饰符(子父双向绑定)

跟v-model的区别

15. ref和$refs 获取dom和组件

16. Vue异步dom更新------解决方法$nextTick


为了提升性能,Vue是异步更新Dom的

$nextTick:等dom更新后,立即触发执行此方法里的函数体(虽然settimeout也可以实现同样的功能,但是等待的时间要自己写)

  • 语法:this.$nextTick(函数体)
js 复制代码
this.$nextTick(()=>{
...
}
)

17. 自定义指令v-...------全局和局部

自己定义的指令,可以封装一些dom的操作

18. v-loading指令封装

发送请求需要时间

所以请求的数据回来之前,页面处于空白未渲染的状态

所以:

  • loading------就是一个蒙层效果,盖在你的盒子上
  • 数据请求中------添加蒙层
  • 数据请求完毕------移除蒙层

19. 插槽------默认和具名

默认(一个定制位置)

  1. 首先你这个含有插槽的需要单独封装成一个组件

  2. 其次在父组件里按正常导入组件的方式导入这个含有插槽的组件(不过插槽里的文字要写在这个里面)

  3. 然后在子组件中需要插槽的地方写成<slot></slot>

js 复制代码
// 父组件中
<MyDialog>你确定要退出吗?(正式内容)</MyDialog>

// 子组件中
<slot>我是备用(默认)内容</slot>
// 如果上面父组件里的子组件标签中没有内容,就会使用这个备用内容

区别

  • 默认插槽:只有一个定制位置
  • 具名插槽:有多个定制位置,并且只要插槽起了名字,就是具名的

具名(多个定制位置)

  1. 子组件中有多个插槽的定制位置<slot></slot>
    • 所以为了区分不同位置,给slot加name属性
    • 比如:<slot name="head"></slot>
  2. 在父组件中用template上配合v-slot的写法来分发插槽
    • <template v-slot="head">大标题</template>
    • 也可以简写成"井号+插槽名"的方式<template #head>大标题</template>

插槽的传值(以添加属性的方式)------作用域插槽

😙商品列表知识点

Vue组件封装案例------商品列表 - 掘金 (juejin.cn)

  1. @dblclick="方法"------双击
  2. @blur="isEdit = false"------失焦时隐藏

20. 路由

为什么要用路由?

因为"单页面应用程序",所有的功能都在一个页面上,特点是页面按需更新

什么是路由?

一种映射关系

路径和组件之间的

  • 就比如单页面中,有不同的组件页面,所对应的路径也就不同
  • 所以我们要确定的就是什么路径去匹配什么组件

VueRouter插件

  • 作用:修改地址栏路径时,切换显示匹配的组件
  • vue2所对应的vuerouter版本是3.6.5

VueRouter的使用(5+2)

  1. 固定的5个步骤在main.js里写
  2. 组件建在views目录下
    • (页面组件要放在views里,小的复用组件就可以放在components里)
  3. 把创建的views目录下的组件在main.js里去配路由规则
    • 路由规则------就是路径与组件之间的对应关系(path,component)
  4. 先配置导航,然后配置路由出口
    • 导航:也就是你你切换组件的导航,href="#/find"
    • 路由出口:也就是你这个路径所匹配的组件的显示位置,<router-view></router-view>

Vue学习第五天 - 掘金 (juejin.cn)

Vue学习第六天 - 掘金 (juejin.cn)

路由模块封装

路由配置全部写在main.js里不易维护

所以我们将有关路由的文件,统一放在router文件夹下的index.js中,并且在index.js里需要导出路由router

声明式导航------全局组件router-link(代替a标签实现高亮)

本质还是a标签,只不过多了一些属性

  • 自带类名,可以直接在css里写样式,让标签高亮
js 复制代码
//herf
<a href="#/find">发现音乐</a>

//to
<router-link to="/find">发现音乐</router-link>
  • 类名分别是模糊匹配router-link-active精确匹配router-link-exact-active
  • 但是我们嫌上面这两个类名都太长了
  • 所以可以这样写,来自定义👇
js 复制代码
const router = new VueRouter({
      routes:[...],
      linkActiveClass:"类名1",
      linkExactActiveClass:"类名2" 
      })

声明式导航------跳转传参

!!!!- $route.query.参数名key,这里接收参数用的是route

  • 分为 查询参数传参 和 动态路由传参

在跳转路由时,进行传值

Vue路由重定向

直接在路由最前面里加一句就行了

js 复制代码
const router = new VueRouter({
  routes:[
     {path:'/',redirect:'/home},
     {...}
  ],
})

404

直接在路由最后面里加一句就行了

还要创建NotFound组件

*表示任意路径

js 复制代码
const router = new VueRouter({
  routes:[
     {...},
     {path:"*",component:NotFound(这可以写任意的路径模块)}
  ],
})

路由模式设置

  • hash路由(默认),带井号#
  • history路由(常用),不带,但是需要后台配置访问规则
js 复制代码
const router = new VueRouter({
  mode:"history"
  routes:[...],
})

21. 路由------编程式导航

基本跳转

!!!!这里接收参数用的是router,this.$router.push('路由路径')

  1. path路径跳转
  2. name命名路由跳转

路由传参

  1. path路径传参

查询参数传参

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

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

接收参数跟原来一样$route.query.参数名

动态路由传参

js 复制代码
this.$router.push('/路径/参数值')
this.$router.push({
   path:'/路径/值',
})

接收参数跟原来一样$route.params.参数名


  1. name路径传参

查询参数传参

js 复制代码
//只有这一种写法
this.$router.push({
  name:'路由名字',
  query:{
     参数名1:'参数值1',
     参数名2:'参数值2'
  }
})

接收参数跟原来一样$route.query.参数名

动态路由传参

js 复制代码
this.$router.push({
   name:'路由名字',
   params:{
      参数名:'参数值'
   }
})

接收参数跟原来一样$route.params.参数名

嵌套路由

22. vuex(状态管理工具/管理通用数据的工具)

vuex 多组件共享数据 Vue学习第七天---Vuex - 掘金 (juejin.cn)


state、mutations、actions、getters

  1. 搭建环境,创建项目
  2. 创建一个空仓库(在store文件夹里新建index.js)
  3. 把新建的仓库挂载到main.js上
  4. 完成后,所有组件就都可以去访问它了

  1. state------获取数据
    • 类似于vue组件中的data
    • 使用数据方式------按层次顺序打点(从store开始) / 辅助函数mapState (自动映射到计算属性中)
  2. mutations------修改(同步)
    • 不过vuex同样遵循单项数据流,组件中不能直接修改仓库的数据
    • mutation函数的第一个参数必须是state,最多两个参数(如果需要多个,需要包装成一个对象)
    • 使用------commit调用this.$store.commit('') / 辅助函数mapMutationns(自动映射到methods方法中)
    • 通过e形参,然后e.target.value可以拿到输入框的值,+e.target.value可以转数字
  3. actions------处理异步操作
    • 使用------dispatch调用(在绑定的事件的methods里写) / 辅助函数mapActions(映射到methods方法中)
    • context上下文,相当于store;所以有store(有context就有commit)
  4. getters------计算属性的类似
    • 第一个参数必须是state,必须有返回值(返回的就是getters的值)
    • 使用------通过打点访问 / 辅助函数mapGetters(映射到计算属性中)

vuex模块化

  1. 在store文件夹下新建modules文件夹,再写js文件
  2. 在modules文件夹里的子模块js,需要在store文件夹下的总仓库index.js中导入并注册

如何使用子模块中的state、mmutations、actions、getters

23. Vue3

Vue3学习 - 掘金 (juejin.cn)

vue2与vue3区别

这种称为是Vue2的选项式API

js 复制代码
export default {
     data(){
         return {
         
         };
      methods:{
         
         };
      computed:{
         
         };
       watch:{
         
         }
     }
}

当代码逐渐增多,也就是比如methods和computed里的方法太多,从视觉上的对应关系就会变弱,不易维护

而Vue3属于组合式API

  • 直接------声明数据,声明方法
  • 组件导完就能用,不用注册
  • template不再要求只能有一个根元素了
  • 加上setup就允许在script中直接编写组合式API

组合式API

setup选项------组合式api的入口

  1. 这个比钩子beforeCreate还要早
  2. 也就是它在创建实例之前就执行了,所以setup函数中是获取不到this的,也就是undefined(vue3很少用this)
  3. setup需要写成一个函数,直接往配置项里面去写
  4. 将来里面可以编写组合式的API,可以往里面调各种函数


5. 特点------要想使用,必须return------但是如果加了setup就不需要了

reactive和ref函数(声明数据)

  1. reactive({})------接收一个对象类型的数据,返回一个响应式的对象

比如👇:

js 复制代码
<script setup>
// reactive:接收一个对象类型的数据,返回一个响应式的对象
// 导包
import { reactive } from 'vue'
const state = reactive({
	count: 100
})
const setCount = () => {
	state.count++
}
</script>

<template>
	<div>
		<div>{{ state.count }}</div>
		<button @click="setCount">+1</button>
	</div>
</template>
  1. ref()------可接收 简单 类型 或者 对象类型的数据,传入并返回一个响应式的对象
  • 跟reactive唯一不同的就是可以接收简单类型,其他都一样

  • 但是,脚本中访问数据,需要通过 .value(不点的话,返回的是对象),而template页面中不需要加

computed

js 复制代码
<script setup>
// 导入
import { computed } from 'vue'

// 执行函数 变量接受 在回调参数中return计算值

//执行函数 在回调参数中return基于响应式数据做计算的值(计算逻辑) ,用变量接收
const computedState = computed(() => {
	return 基于响应式数据做计算之后的值
})
</script>

tip:👇

watch

  1. 侦听 一个或多个数据 的变化,数据 变化时执行回调 函数
  2. 分为------侦听单个数据 和 侦听多个数据
  3. 两个额外参数------immediate (一进页面立刻执行一次)和 deep (深度侦听),
    • 默认watch进行的是 浅层监视
    • (也就是可以直接监测到简单类型数据变化;但是监测不到复杂类型内部数据的变化)
  4. 也可以精确侦听对象里的某一个属性

单个👇

js 复制代码
<script setup>

//1. 导入watch
import { ref, watch } from 'vue'
const count = ref(0)

// 2. 调用watch 侦听变化
	// watch后面跟上一个ref对象(count),后面再去写一个回调
// 这里面写count而不是count.value(写.value相当于监视了0,0有什么好监视的)
watch(count, (newValue, oldValue) => {
	console.log(`count发生了变化,老值为${oldValue},新值为${newValue}`)
})
// 上面代码的意思是:一旦当前这个这个count变化了,就会执行后面的回调,后面的回调当中可以拿到新值和老值(即变化前和变化后的)
</script>

多个👇

js 复制代码
<script setup>

import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('cp')

//侦听多个数据,写成数组形式在里面
// 里面任何一个值变化,都会触发回调
watch(
	[count, name],
	([newCount, newName], [oldCount, oldName]) => {
		console.log('count或者name变化了',[newCount,newName],[oldCount,oldName])
	}
)
</script>

额外参数👇

js 复制代码
<script>
const count = ref(0)
watch(count, () => {
	console.log('count发生了变化变化')
}, {
	immediate: true // 一进页面立刻执行一次
        deep:true
})
</script>

精确侦听某个属性👇

父子通信

父传子

  • 相当于去掉了父组件的data传参
  • 由于写了setup,所以无法直接配置props选项,所以用到了编译器宏
  1. 传死数据
  2. 传动态数据

子传父

模板引用

通过ref ------表示获取真实的dom对象 或者 组件实例对象

如何使用👇

然后通过ref对象.value即可访问到绑定的元素

tip:👇

  • 在默认情况下<script setup>语法糖下 组件内部 的属性和方法是 不开放给父组件访问
  • 可以通过defineExpose()编译宏 指定哪些属性和方法允许访问,把他们暴露出去!

provide和inject

顶层 组件向任意的 底层组件传递数据和方法 ,实现跨层组件通信(比如像爷传孙)

  1. 顶层组件通过 provide 函数提供 数据
js 复制代码
provide('key',顶层组件中的数据 / ref对象,也就是响应式数据 / 方法)
  1. 底层组件通过 inject 函数 提供数据
js 复制代码
const message = inject('key')

tip:渲染时候注意,顶层组件包中间,中间组件包底层

  1. 如果想要修改某个数据时,就要遵循"谁的数据谁维护"的原则
  • 所以引出------跨层级传递函数=>给孙后代传递可以改数据的方法
js 复制代码
// 在你想要改的数据的vue(也就是你最开始provide这个数据的地方)中提供provide修改的函数,共享方法

//跨层级传递函数=>给孙后代传递可以改数据的方法
// !!!相当于往子孙后代中共享了一个方法
provide('changeCount',(newCount) =>{
  count.value = newCount
})


//在子孙后代中去接收这个函数
const changeCount = inject('changeCount')
const clickFn = () => {
// 调用
  changeCount(1000)
}

24. Vue3.3 新特性

defineOptions宏

  • 为了解决这一问题,引入了defineProps defineEmits这两个宏。但这只解决了propsemits这两个属性
  • 如果我们要定义组件的name或其他自定义的属性,还是得回到最原始的用法 -- 再添加一个普通的<script>标签。
  • 视觉上不合理
  • 所以
  • 引入 defineOptions宏
  • .顾名思义,主要是用来定义 Option API 的选项. 可以用defineOptions 定义任意的选项(props,emits,expose,slots除外,它们有专属的宏)
js 复制代码
<script setup>
defineOptions({
	name: 'Foo',//给组件命名
	inheritAttrs: false,
	// ...更多自定义属性
})
<script>

defineModel

在Vue3中,自定义组件 上使用v-model,相当于传递一个modelValue属性, 同时触发 updata:modelValue 事件

所以就要求我们,先定义 props, 再定义 emits. 其中有许多重复的代码. 如果需要修改此值, 还需要手动调用 emit 函数

  • 太麻烦了,所以用defineModel来简化(只动了子组件里的代码)
js 复制代码
<script setup>
import MyInput from '@/components/my-input.vue'
import { ref } from 'vue'
const txt = ref('123456')
</script> 
<template>
  <div>
    <MyInput v-model="txt"></MyInput>
    {{ txt }}
  </div>
  </template> 
  //------------------------------------------------------------------------------------------------------------------
//<script setup>
//defineProps({
//	modelValue: String
//})
//const emit = //defineEmits(['updata:modelValue'])
//</script>

<script setup>
// 1. 不再需要props来接收了,而是直接model接收
//2.你需要修改这个数据也不再需要emit!!!,而是直接修改 
import { defineModel } from 'vue'
const modelValue = defineModel()
</script>

<template>
<div>
  <input	
    type="text"
    :value="modelValue"
    @input="e => modelValue = e.target.value"
  >
  //@input="e =>emit('update:modelValue,e.target.value')"
</div>
</template>

用defineModel的前提 是需要在vite.config.js中加配置

js 复制代码
plugins: [
    vue({
      script:{
        defineModel:true
      }
    }),
  ],

25.Pinia

Pinia 是 Vue 的最新状态管理工具, 是Vuex的 替代品(只有state,actions,getters)

  1. 提供了更加简单的API(去掉了mutation,也就是action既可以异步又可以直接修改数据了;;相当于mutations和actions合二为一)

  2. pinia如何实现getter?------computed计算属性函数

  3. 提供符合组合式风格的API(和Vue3新语法统一)

  4. 弃掉了modules的概念, 每一个store都是一个独立的模块

  5. 配合 TypeScript 更加友好,提供可靠的类型推断

安装,基本使用,storeToRefs方法,持久化👇

Vue3.3新特性与Pinia - 掘金 (juejin.cn)

相关推荐
leoZ2318 小时前
Claude 驱动的全栈开发:Spring Boot + Vue 的 BS 架构实践
vue.js·spring boot·架构
荒诞英雄11 小时前
从 17MB Vendor 大包到按需加载:Vite 多入口 Vue 组件库首屏优化实践
vue.js·vite
jsonbro11 小时前
手把手带你实现发布订阅模式
前端·vue.js·设计模式
Cobyte13 小时前
23.Vue Vapor 组件 attrs 的实现
前端·javascript·vue.js
斯特凡今天也很帅14 小时前
xml页面可以打开,不报错,但是显示数据的地方也不显示,我是怎么解决的
xml·vue.js
柯克七七16 小时前
给老项目加了 TypeScript,本来只想自己爽,结果全公司代码审查标准被我抬高了
前端·vue.js·typescript
自然 醒18 小时前
前端如何实现在线预览office常见文件功能?
前端·vue.js
肉肉不吃 肉18 小时前
前端调试跨域如何解决
前端·vue.js
卓怡学长18 小时前
w268基于springboot + vue 物流系统
java·数据库·vue.js·spring boot·spring·intellij-idea
2601_9628517419 小时前
计算机毕业设计之基于SSM的网络安全课程资源分享平台
vue.js·算法·安全·web安全·yolo·目标检测·课程设计