vue3

Vue是一套用于构建用户界面渐进式 JavaScript框架

  渐进式 JavaScript框架 : 表示我们可以在项目中一点点来引入和使用Vue,而不一定需要全部使用Vue来开发整个项目;

常见的基础指令

v-once : 只执行一次

v-pre : 跳过该元素及其所有子元素的编译

v-cloak  : 用于隐藏尚未完成编译的 DOM 模板  搭配css  [v-cloak] { display : none ;}

v-memo : 只有满足的值,才会重新渲染页面 [代码实例]

class的绑定[代码实例]style的绑定 [代码实例]

v-on : 事件绑定  传递多个参数 -- 固定值 $event

v-on的修饰符

  .stop - 调用 event.stopPropagation()。

  .prevent - 调用 event.preventDefault()。

  .capture - 添加事件侦听器时使用 capture 模式。

  .self - 只当事件是从侦听器绑定的元素本身触发时才触发回调。

  .{keyAlias} - 仅当事件是从特定键触发时才触发回调。

  .once - 只触发一次回调。

  .left - 只当点击鼠标左键时触发。.right - 只当点击鼠标右键时触发。.middle - 只当点击鼠标中键时触发。

  .passive - { passive: true } 模式添加侦听器

v-if , v-else-if ,v-else  和 v-show

  template元素可以当做不可见的包裹元素,并且在v-if上使用,但是最终template不会被渲染出来

  区别 : 

    v-show是不支持template; v-show不可以和v-else一起使用;

    v-show元素无论是否需要显示到浏览器上,它的DOM实际都是有存在的,只是通过CSS的display属性来进行切换;

    v-if当条件为false时,其对应的原生压根不会被渲染到DOM中;

    如果我们的原生需要在显示和隐藏之间频繁的切换,那么使用v-show; 如果不会频繁的发生切换,那么使用v-if

v-for : 循环

  被监听的方法有 : push() , pop() , unshift() , shift() , splice() , reverse() , sort()  [这些方法都会直接修改原来的数组]

  不会修改原数组的方法,那么就直接替代它 : filter() , concat() , slice()

  v-for中的key的作用 : 主要用在vue的虚拟Dom算法:在新旧VNode比较

  (key用于虚拟Dom,而虚拟Dom又可以做新旧VNode对比,又会生产有虚拟Dom树 : 可以跨平台编译,可以增强性能)

 

v-model : 双向数据绑定[都用在表单]

  它相当于 : v-bing绑定value属性的值  ;  v-on绑定input事件监听到函数中,函数会获取最新的值赋值到绑定的属性中

  1.v-model 绑定 checkbox [代码实例]

  2.v-model绑定 radio [代码实例]

  3.v-model绑定 select [代码实例]

  4.修饰符 : 

    .lazy  :  会将绑定的事件切换为 change 事件,只有在提交时(比如回车)才会触发

    .trim :  自动过滤用户输入的守卫空白字符

 

两个个Options Api :(computed,watch)

1.computed 计算属性

特点 : 1.有缓存 ; 2.在调用的时候不用加();

简写模式 : 跟函数写法一样

原始模式 :  get 和 set  [代码实例]

 

2.watch 监听器

简写模式 : 跟函数写法一样 , 想要监听那个,就在那个()

原始模式 :  [代码实例]

特别模式 : $watch [代码实例]

 

3.全局组件 : [代码实例]

4.局部组件 : [代码实例]

 

脚手架 

安装 :  npm install @vue/cli -g  

创建 : Vue create 项目的名称   /    vite创建  npm init  vue@latest

创建的信息

 

组件之间的通信

1.父传子: props

  在组件上可以写一些元素, 子组件可以通过props来接收到

  A: props的默认写法 : 数组 [弊端 : 不能对类型进行验证 , 没有默认值的]  [代码实例]

  B: props的对象写法-数组写法 : [代码实例]

  C:当我们传递给一个组件某个属性,但是该属性并没有定义对应的props或者emits时,就称之为 非Prop的Attribute
    默认会将这些 attribute 会添加到子组件的根元素上
    如果不希望组件的根元素继承 attribute ,可以在组件中设置 inheritAttrs: false; 
    子组件想到得到这些属性可以用 $attrs  来接收  [代码实例]   

2.子传父: $emit

  子组件通过$emit发出自定义事件,父组件接收自定义事件

    普通形式 : [代码实例]

    vue3新特性 : [代码实例]

3.祖孙组件的传递

  祖先采用 : Provide 发送  一般都是写成函数形式

  孙子采用 : Inject  接收 [代码实例] 

4.全局事件总线

  vue3已经没有提供全局事件总线的$on,$off,$once方法了

  这里我们采用这个库 : npm i hy-event-store 

  emit : 发送       on : 监听        off : 移除

  使用的方法 : [代码实例]

 

插槽

  子组件 用  <slot> 标签来表示插槽 , 属性name 表示插槽的名字 

  父组件 插入 指定那个插槽 用 : v-slot:名字   简化 : #名字

  作用域插槽 子组件通过在 <slot>标签上传递信息 , 父组件通过props接受

  1.普通插槽 [代码实例]

  2.具名插槽 [代码实例]  动态传数据 [代码实例]

  3.作用域插槽 [代码实例]

 

零散知识点 : 

  1.$refs的使用 : 直接获取到元素对象或者子组件实例  [代码实例] 

  2.动态组件的使用 : 以前我们可以通过v-if来让哪些组件显示;现在有了动态组件了

    动态组件  ,  通过一个特殊的attribute is 来实现 : <component  is=' '>  </component>

    传值和监听事件都是一样的写法 [ is 的来源是子组件的name的值 ]   [代码实例] 

  3.keep-alive  保存组件的状态,不会被销毁掉

    3个属性 :      

      include - string | RegExp | Array。只有名称匹配的组件会被缓存;
      exclude - string | RegExp | Array。任何名称匹配的组件都不会被缓存;
      max - number | string。最多可以缓存多少组件实例,一旦达到这个数字,那么缓存组件中最近没有被访问的实例会被销毁;

    使用了它后,会出现2个声明周期 :   activated  和  deactivated   [代码实例]

  4.分包 : 组件的分包可以通过  defineAsyncComponent  来实现异步组件 [异步组件就是为了可以分包使用]

    

  5.组件的v-model[代码实例]  不常用的!

   

   6.mixin的基本使用 

  

   mixin的全局混入 : 

  

 

vue3的 Composition  API开始

setup 函数 :  它代替了 : options API 的 methods、computed、watch、data、生命周期等等

  它的两个参数 :  props  和  context

    props : 是父组件传递过来的属性会被放到props对象中,我们在setup中如果需要使用,那么就可以直接通过props参数获取

    context,我们也称之为是一个SetupContext,它里面包含三个属性 :    

      1.attrs:所有的非prop的attribute;
      2.slots:父组件传递过来的插槽(这个在以渲染函数返回时会有作用,后面会讲到);
      3.emit:当我们组件内部需要发出事件时会用到emit(因为我们不能访问this,所以不可以通过 this.$emit发出事件);
  

   返回值 : 可以在模板template中被使用,也就是说我们可以通过setup的返回值来替代data选项

 

第一个API : reactive 

在 setup 中定义的数据提供响应式的特性,那么我们可以使用 reactive 的函数
  1.我们使用reactive函数处理我们的数据之后,数据再次被使用时就会进行依赖收集
  2.当数据发生改变时,所有收集到的依赖都是进行对应的响应式操作(比如更新界面
  3.事实上,我们编写的data选项,也是在内部交给了reactive函数将其编程响应式对象的;

reactive 函数 只能处理复杂类型 : object array   [ 代码实例 ]

 

第二个API : ref

原因 : 因为reactive只能使用复杂类型,所以出现了 ref 来使用简单类型(string,boolean,number)[而且 ref 也可以使用复杂类型

使用 ref 返回的是一个 ref对象 ,我们的值是对象里面的value : 一般 ref对象.value  [代码实例]

注意 : 

  1.在模板中使用,vue会自动帮我们解包,不需要 .value  [解包 : 自动取出其中的value]

  2.在setup中,需要 ref对象.value

  3.ref 是一个浅层的解构 : 在template使用的时候可以不用.value , 在template修改一定需要.value  [ 代码实例 ]

 

总结 : ref 和 reactive Api 

   reactive  :

    一般是应用于本地的数据 ;

    多个数据之间是有联系的 ;

  ref : 

    一般都是定义本地的一些简单数据;

    定义从网络请求获得的数据 [ref对象.value = [请求数据]

 

第三个API :readonly

  vue是一个单向数据流(规范) : 父组件传递的数据,子组件只能使用,不能修改;

  原因 : 正常子组件却是可以修改父组件传递的数据的 ; 所以vue3产生了 readonly 来防止 子组件的修改行为

  解决 : 如果子组件确实想修改 : 应该发送数据, 让父组件来修改 [这样做才知道哪个子组件来修改父组件的值]

  错误实例 (没采用单向数据流) : [ 代码实例 ]

  正确实例(采用readonly) : [ 代码实例 ]

  注意 : 经过readonly 处理后的对象是不能被修改的 , 但是原本的对象我们可以修改

 

第四.Reactive判断的API 和 ref判断的API

isProxy
  检查对象是否是由 reactive 或 readonly创建的 proxy
 
isReactive
  检查对象是否是由 reactive创建的响应式代理
  如果该代理是 readonly 建的,但包裹了由 reactive 创建的另一个代理,它也会返回 true;
    const a = reactive({name:'吴亦凡'})   isReactive(a) = true
    const b = readonly({name:'吴亦凡'})   isReactive(b) = false
    const c = readonly({a})   isReactive(c) = true
 
isReadonly
  检查对象是否是由 readonly 创建的只读代理
 
toRaw
  返回 reactive 或 readonly 代理的原始对象(不建议保留对原始对象的持久引用。请谨慎使用)。
 
shallowReactive
  创建一个响应式代理,浅层的响应式,不对深层的监听。
 
shallowReadonly
  创建一个 proxy,浅层的只读,不对深层的只读。
 

isRef

  判断值是否是一个ref对象

shallowRef

  创建一个浅层的ref对象[ref创建的对象,也是一个深层的响应式的]

triggerRef

  手动触发和shallowRef创建的浅层的,变为深层的

 

 

 

第五个API : toRefs 和 toRef

  原因 : 我们通过reactive创建出来的数据,想要对它进行解构; 但是解构出来的值,就失去了响应式了

  解决 : toRefs 就来解决失去响应式的问题

    toRefs(值1)  : 值1 : 对象

  想要单独解构一个值 :  使用 toRef

    toRef(有值1和值2) : 第一个值是对象 , 第二个值是要解构对象中的哪个数据

     [ 代码实例 ]

 

第六个API : ref 获取元素和组件

  想要获取,我们要在onMounted中,才可以获取到.因为 setup 出现的时候,template还没编译呢   [ 代码实例 ]

 

第七个API : provide 和 inject 祖孙传递数据

provide(值1,值2)     :  值1(提供的属性名称)   ;  值2(提供的属性值)  

inject(值1,值2)   :   值1(provide提供的属性名称)  值2(可以提供默认值)

[ 代码实例 ]

 

computed 计算函数    [代码实例]

 

watch 和 watchEffect 监听函数

watch 

  1.watch 监听ref的简单类型(默认都是深度监听) [代码实例]

  2.watch 监听ref的复杂类型(需要加上deep,才可以监听到,但是得不到原对象) [代码实例]

    由于第二种情况,我们得不到值,这里建议监听复杂类型的,我们要使用reactive,不要用ref

  3.watch 监听reactive (并且可以得到原对象[代码实例]

 

watchEffect  [ 代码实例 ]

  1.watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖;

  2.只有收集的依赖发生变化时watchEffect传入的函数才会再次执行

  3.watchEffect会返回一个值,想要停止的时候,调用它就好了

生命周期函数

 

setup的语法糖

1.组件导入后,不需要用components 注册, 可以直接使用

2.顶层绑定会暴露给末班, 也就是不需要使用  return  了

3.接受父组件传递过来的东西 : defineProps 函数 [不需要导入,可以直接使用]

4.发送自定义事件 : defineEmits  函数 [不需要导入,可以直接使用]

5.defineExpose :

  在setup的语法糖中,想要把方法,属性暴露出去,需要使用 defineExpose ,

  暴露出去后,父组件可以通过 ref 来获取子组件,从而来调用子组件的方法和属性

[ 代码实例 ]

 

vue的路由器

一般我们直接用脚手架选线的,就有给我们配置了

1.路由分包也叫路由懒加载 : 其实就是为了打包后分开,不合在app.js的包里面.所以才有懒加载,可以优化渲染速度.

  懒加载可以给他们加上打包后的名称 :  component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')

 

2.如何使用? 

  1. <router-view></router-view>   来展示路由页面的 

  2. <router-link>Home</router-link>  来显示切换的  to属性指定的是路由的名称 ,这里还有一个隐藏的当前切换的class属性,可以自己找 
 

3.路由的重定向 + 路由的name和meta属性 + 没有匹配到路由 + 子路由    [ 代码实例 ]

 

4.动态路由  --   useRoute  - params   [ 代码实例 ]

 

5.编程式路由  --  useRouter  - query   [ 代码实例 ]

  叫做编程式路由 : 就是因为实在script中写到代码,所以才这样叫编程式路由

  router.push : 跳转

  router.replace :跳到新页面(没有历史记录)

  router.back() 返回

  router.forward() 前进

  router.go(数字)   正数 : 进, 负数 : 退 
 
总结 : useRoute  和 useRouter 的 区别 : 
useRoute : 是获取路由的信息
  每一个路由都会有一个route对象,是一个局部对象,它里面主要包含当前路由的一些基本信息,
  比如:name、meta、path、hash、query、params、fullPath、matched、redirectedFrom等
useRouter :  是一些操作路由的方法
  就上面编程式路由的几个方法
  

6.动态添加路由

 一般都是在后台管理系统出现,目前后台管理系统有2种做法 : 

  1.根据不同角色,生产不同的菜单 ; 对应的菜单的路由还是有注册的

  2.根据不同角色,生产不同的菜单 ; 菜单和路由都是动态注册的 === 这就应用到了动态添加路由

添加路由 :router.addRoute
 
删除路由 :router.removeRoute
 
检查路由是否存在 : router.hasRoute()
 
获取一个包含所有路由记录的数组 : router.getRoutes()
 
// 1.动态管理路由
let isAdmin = true
if (isAdmin) {
  // 一级路由
  router.addRoute({
    path: "/admin",
    component: () => import("../Views/Admin.vue")
  })

  // 添加home,下面的vip子页面
  router.addRoute("home", {
    path: "vip",
    component: () => import("../Views/HomeVip.vue")
  })
}

 

7.路由导航守卫

to : 进入的页面。from :离开的页面

beforeEach

// 路由导航守卫
// 进行任何的路由跳转之前, 传入的beforeEach中的函数都会被回调
// 需求: 进入到订单(order)页面时, 判断用户是否登录(isLogin -> localStorage保存token)
// 情况一: 用户没有登录, 那么跳转到登录页面, 进行登录的操作
// 情况二: 用户已经登录, 那么直接进入到订单页面
router.beforeEach((to, from) => {
  // 1.进入到任何别的页面时, 都跳转到login页面
  // if (to.path !== "/login") {
  //   return "/login"
  // }

  // 2.进入到订单页面时, 判断用户是否登录
  const token = localStorage.getItem("token")
  if (to.path === "/order" && !token) {
    return "/login"
  }
})

其他的导航守卫 : 地址

完整的导航解析流程:
 1.导航被触发。
 2.在失活的组件(同个组件 == 动态路由)里调用 beforeRouteLeave 守卫。
 3.调用全局的 beforeEach 守卫。
 4.在重用的组件里调用 beforeRouteUpdate 守卫(2.2+)。
 5.在路由配置里调用 beforeEnter。
 6.解析异步路由组件。
 7.在被激活的组件里调用 beforeRouteEnter。
 8.调用全局的 beforeResolve 守卫(2.5+)。
 9.导航被确认。
 10.调用全局的 afterEach 钩子。
 11.触发 DOM 更新。
 12.调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。
 

状态管理工具 : vuex 和 pinia

能用 pinia 尽量别用 vuex 

vue2 + vuex  [ 全部推荐使用映射 ]

state(数据) : [ 代码实例 ]

 

getters(计算属性) : [ 代码实例 ]

参数1:state 参数2:getters
 

mutations : [ 代码实例 ]  

修改 state 的数据,必须通过 mutation 来修改  [ 只写同步操作!!! 想发送异步的 : 采用actions]

mutations 参数1:state的 参数2.传递过来的数据

mutations的出现也是为了 devtools 来捕捉快照

 

actions(方法) : [ 代码实例 ] 

action 类似于 mutation,不同于 :

  action提交的是mutation,而不是直接变更状态;

  action可以包含任意异步操作 

  在store里面通过 commit 来提交 mutation

  在使用的时候通过dispatch来提交action

 

modules : [ 代码实例 ]

1.使用state时, 是需要state.moduleName.xxx
2.使用getters时, 是直接getters.xxx
3.派发事件时, 默认也是不需要跟模块名称
4.提交mutation时, 默认也是不需要跟模块名称

  

vue3 + vuex  [不推荐使用!!!,vue3推荐pinia]

state(数据) : [ 代码实例 ] 推荐使用基本,不用映射

 

getters(计算属性) : [ 代码实例 ] 推荐使用基本,不用映射

参数1:state 参数2:getters

 

mutations : [ 代码实例 ] 推荐使用基本,不用映射

修改 state 的数据,必须通过 mutation 来修改  [ 只写同步操作!!! 想发送异步的 : 采用actions]

mutations 参数1:state的 参数2.传递过来的数据

mutations的出现也是为了 devtools 来捕捉快照

mutations 在使用的时候通过 commit('') 来提交

 

actions(方法) : [ 代码实例 ] 推荐使用基本,不用映射

action 类似于 mutation,不同于 :

  action提交的是mutation,而不是直接变更状态;

  action可以包含任意异步操作 

在store里面通过 commit 来提交 mutation

在使用的时候通过dispatch来提交action

发送网络请求 : [ 代码实例 ]

 

modules : [ 代码实例 ]

1.使用state时, 是需要$store.state.模块名.xxx
2.使用getters时, 是直接$store.getters.xxx
3.派发事件时, 默认也是不需要跟模块名称
4.提交mutation时, 默认也是不需要跟模块名称

在模块中的话,getters,会有第三个参数 : rootState 得到的是根的state

getters: {
  doubleCount(state, getters, rootState) {
    return state.count + rootState.rootCounter
  }
},
 

vue3 + pinia [强烈推荐使用]

没有mutations ; ts支持 ; 不用module  ;  非常简单好用

npm i pinia

创建和使用 : [ 代码实例 ]

state(数据) - getters(计算属性) : [ state 和 getters 的代码实例 ]

重置方法 : $reset 

修改信息 : $patch

actions(方法) :  [代码实例]

 

axios网络请求库 npm i axios

1.特点 - 支持多种请求方式 - 常见的配置选项 

 

2.get请求(params)  和  post请求(data) 的 2种方式  :  [ 代码实例 ]

 

3.创建axios实例  [ 代码实例 ]

原因:  

  当我们从axios模块中导入对象时, 使用的实例是默认的实例;

  当给该实例设置一些默认配置时, 这些配置就被固定下来了.

  但是后续开发中, 某些配置可能会不太一样;

  比如某些请求需要使用特定的baseURL或者timeout等.

  这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.
 
4.请求和响应拦截器
axios.interceptors.request.use(请求成功拦截, 请求失败拦截)
axios.interceptors.response.use(响应成功拦截, 响应失败拦截)
 
5.项目操作  => (axios请求库封装)
 
 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

   

 

posted @ 2022-09-08 09:44  杨建鑫  阅读(298)  评论(0编辑  收藏  举报