Vue3 全文知识点

vue全文知识点

    • vue3 学习
      • 1 关于项目初始化
      • 2 vue3 语法 setup
      • 3 vue3 语法 和 vue2 语法兼容
      • 4 setup 语法糖
      • 5 响应式数据-基础
      • 6 响应式数据-ref 定义对象类型数据
      • 6 toRef,toRefs 将多个非响应式数据转变为响应式数据 refImpl
      • 7 computed 计算属性
      • 8 watch 监听 [ref对象(包含计算属性),getter方法(对象属性),响应式对象,数组(包含前三类)]
      • 9 ref绑定
      • 10 props 子组件接收父组件传值
      • 11 vue3 生命周期
      • 12 hooks 组件封装
      • 13 router 路由
        • 路由配置
        • 路由使用
        • 组件缓存
        • 路由守卫
        • 路由模式
      • 14 pinia 状态管理器
        • 安装配置与基础使用
        • 修改 state 数据
        • actions 操作函数定义
        • getter 函数和 storeToRefs 响应式解构
        • $subscribe 监听数据变化
      • 15 组件
        • 组件切换
        • 组件传值
          • defineProps
          • v-bind/v-on/v-model
          • ref 和 $parent
          • provide/inject
          • 其他
        • 组件插槽
          • 默认插槽
          • 具名插槽(手动指定插槽) v-slot 可以简化
          • 作用域插槽(指定插槽并可以操作插槽绑定的数据)
      • 其他[事件修饰符、自定义指令、多环境配置]
        • 事件修饰符
        • 自定义指令
        • 多环境配置

vue3 学习

1 关于项目初始化

    index.html  App.vue  main.ts
    index.html : 根html文件 指定渲染的根元素
    App.vue : 根组件
    main.ts : 项目入口文件

    index.html 中引入  main.ts
    main.ts 引入 App.vue 并指定挂载位置

2 vue3 语法 setup

    选项式 转 结构式 

    setup return 可以直接返回渲染页面

3 vue3 语法 和 vue2 语法兼容

    vue3 语法 和 vue2 语法是兼容的 data() methods();
    
    但是:
        data() 中可以读取 setup 中的数据 用 this. 访问
        setup() 中 读取不到 data() 中的数据

    不要混用

4 setup 语法糖

     setup 语法糖 减少了 setUp(){} 结构 并且可以自动将内部定义的数据和方法
     进行rutern 暴露出去

     但 对组件的暴露不能 写在 一个 script 里面
        默认情况:组件名同文件名
     1、新写一个 script 单独用于暴露组件
     2、插件 vite-plugin-vue-setup-extend
        需要配置插件到 vite.config.ts

5 响应式数据-基础

    ref() : 基本数据类型响应式数据
        在js 中需要通用 .value 进行操作和访问,模板中可以省略
    
    reactive : 只能定义对象数据类型响应式数据,对象,数组 。。。
        直接访问即可
        注意:对 reactive 定义的变量重赋值会导致响应式失效
            对象:此时需要通过 object.assign() 重新赋值  
                 =》  carA = object.assign({},car)  || object.assign(carA,car)
                 object.assign(o1,o2,o3,o4,...) 将 o1 后的所有对象数据解构到 o1 身上 
            数组:需要通过 数组方法 进行操作

6 响应式数据-ref 定义对象类型数据

    ref() : 对象类型数据
        注意:ref 定义的对象类型响应式数据需要通过 ref.value.xxx 访问

    ref 定义的是一个 refimpl 对象
        访问refimpl 对象的 value 属性

    原理:ref 定义对象类型数据时,是通过 reactive() 方法将数据转换成 proxy 对象
    
    最终:在定义响应式数据时,基本数据类型和不太深的对象数据 都用 ref

6 toRef,toRefs 将多个非响应式数据转变为响应式数据 refImpl

    toRef(单个值),toRefs 
    toRef("21号");    toRef(Preson, 'name');
    let { name,age } = toRefs(Preson);

   对于 {} 对象,单纯创建一个 refImpl 对象
   对于 reactive() 方法创建的 proxy 对象,需要通过 toRefs() 方法将 proxy 对象中的数据转换为 refImpl 对象

7 computed 计算属性

    // 简写 仅可读
    let fullName = computed(()=>{
        return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + "-" + lastName.value;
    });

    // 完整 可读写
    let AllFullName = computed({
        get(){
            return firstName.value.slice(0,1).toUpperCase() + firstName.value.slice(1) + "-" + lastName.value;
        },
        set(val){
            firstName.value = val.split("-")[0];
            lastName.value = val.split("-")[1];
        }
    }); 

8 watch 监听 [ref对象(包含计算属性),getter方法(对象属性),响应式对象,数组(包含前三类)]

    watch(监视内容,回调函数()=>{},监视属性{})

     watch(sum,(newv,oldv)=>{ // 基本数据
        console.log("");
    },{deep:true,immediate:false});

    watch(Preson,(newv,oldv)=>{   // 注意对于 reactive 定义的对象会自动开启强制的 深度监视
        console.log("");
    },{deep:true,immediate:false});

    watch(return preson.age,(newv,oldv)=>{
        console.log("");
    },{deep:true,immediate:false});
   
    watch([()=>preson.name,sum,Preson],(newv,oldv)=>{
        console.log("");
    },{deep:true,immediate:false});
   

9 ref绑定

    原生可以使用 id 唯一指定页面元素,但在 vue 单页面应用中当前路由中涉及的所有组件都会加载到页面,此时可能会导致 id 重复,取值异常。
    使用 ref 指定唯一页面元素,就算是在单页面中存在多个相同的 ref 值,vue 均可以正常取到相应组件的相应元素(ref 组件作用域)。
    ref 普通html标签
        
let refDiv = ref(); // 必须同页面元素绑定的 ref 值完全相同 refDiv.value : 必须在组件挂载后才能取到值,对 ref 元素进行操作。 ref 组件标签 可以获取到子组件,但默认情况下获取不到子组件的数据需要,子组件自己使用 defineExpose({}) 暴露才能获取 此时父组件 可以使用 refxx.value.xx 获取子组件对于的值,方法...... 并可以进行修改,会同步到子组件 【子-》父组件传值】

10 props 子组件接收父组件传值

      父组件绑定需要传的值
    子组件使用: let props = defineProps(['desc','persoonList']) 接收,模板中可以直接使用,js中需要 props.xxx

    withDefaults(defineProps<{persoonList?:Presons,desc:string}>(),{  // 限制接收类型 + 可以不传 + 默认值
        persoonList:()=>{[{id:"张三",name:"wda",age:12}]},
        desc:"adddd"
    });

11 vue3 生命周期

   setup() 创建时期 setup语法糖
   onBeforeMount 和 onMounted      挂载时期 
   onBeforeUpdate 和 onUpdated     dom更新时期
   onBeforeUnmount 和 onUnmounted  组件销毁时期

    路由生命周期

   onActivated  onDeactivated 对应缓存组件还有,组件激活,组件失活

12 hooks 组件封装

    命名规范: useXXX
    hooks 集中封装需求组件的属性、数据、方法 等
    1、在 hooks 目录中新建对应组件的封装文件  useXXX (use 开头)
    2、定义 function 进行暴露
    3、使用 return 返回封装内部数据、方法、属性
    4、在调用组件中引入 hook,并使用 
        let { dogList,getImg } = useDog();
        let { sum,add } = useSum();

13 router 路由

路由配置
    依赖 vue-router 组件依赖
    定义
        在 router 目录下 index.js 中定义 router
        引入并全局挂载到vue实例  app.use(router)
    引入
        局部 :在需要使用的组件内部引入 (useRouter,useRoute)
        全局 : export {} declare global {xxx}
            在需要的地方直接 : let router = useRouter();
路由使用
    
    
    使用
        router-link : 使用 to 指定跳转
        redirect : 路由重定向
    参数
        query : 指定参数 =》 {name:val,......}
            注:query 传递参数时
        params : 指定cans => {name:val,....} 。但要求路由定义为 path:/a/b/:name1/:name2
            注:parms 传参时只能使用name
        props:
            布尔模式 : 设置 props:true 
                组件中通过 defineProps 获取。注:仅能获取 parmas 参数
            函数模式 : 设置 props(route){return xxx} 
                组件中通过 defineProps 获取
            对象模式 : 设置 props :{xxx:xx,xxx:xx}
                组件中通过 defineProps 获取. 静态数据
    函数路由
        router.push(replace) 追加/替换 
        router.go(num)  动步跳转
组件缓存
    缓存路由组件
        KeepAlive
        
        
            
                
            
        

        
        
            
                
            
        

        
        
            
                
            
        

    缓存组件生命周期
        对于缓存的组件 UnMount Mount 组件生命周期不会生效
        onActivated    : 组件激活
        onDeactivated  : 组件失活
路由守卫
    路由守卫
        全局路由守卫:beforeEach,beforeResolve,afterEach  [router.js 配置]
            beforeEach((to,from,next)=>{}):路由跳转之前
            beforeResolve((to,from,next)=>{}):路由解析之前。导航被确认之前执行
            afterEach((to,from)=>{}):路由跳转之后
        参数(to,from,next){}   to:预跳转路由。from:当前路由。next():放行

        路由独享守卫 :beforeEnter    [router.js 的 具体路由项]
            beforeEnter(to,from,next)=>{}

        组件内守卫 : onBeforeRouteUpdate , onBeforeRouteLeave [组件内调用]
            组件内部的守卫,它们只在当前组件的路由发生变化时触发
            onBeforeRouteUpdate:在当前路由改变时被调用
            onBeforeRouteLeave:在导航离开组件的路由时调用。可以用来阻止导航
路由模式
    路由模式:
        hash: # 及其后面的字符称为 hash,hash 的变化不会导致浏览器向服务器发送请求,因此页面不会重新加载。
        history: 无 # 路由的切换是通过 HTML5 History API 实现的,这种方式可以实现 URL 的无刷新跳转
        配置:[router.js] history: createWebHistory() / createWebHashHistory()
            根路由:history: createWebHistory(import.meta.env.BASE_URL)
            import.meta.env.BASE_URL : [vite.config.ts] 中配置 base

14 pinia 状态管理器

安装配置与基础使用
    mian.ts 引入:import { createPinia } from 'pinia';  创建:const Pinia = createPinia();  挂载:app.use(Pinia);
    
    配置目录 /store      
        新增对应的 store 模块 (单模块)
        模块中新建 defineStore("模块名",{配置项[state.getter,actions]})
            const useCounterStore = defineStore("counter",{
                state:() => ({
                    count : 'pinia store'
                }),
            });
    
    基础使用
        import useCounterStore from '@/store/count'
        const counterStore = useCounterStore();
        {{ counterStore.count }}
        console.log("counterStore.count:",counterStore.count);
修改 state 数据
    一、直接修改:
        counterStore.count += 1
    二、通过 $patch 函数可批量修改
        counterStore.$patch({
            count:count.count -1
        });
    三、通过 actions 函数修改 (见以下)
actions 操作函数定义
    定义
        在 @/store/count 对应模块中定义 actions{} 区域
        在其中定义方法函数 funcName(params){this}  this 可获取到 state 中的数据
        方法函数中可以定义 异步方法 或其他的 复杂操作
    使用
        counterStore.countAdd(5);
        counterStore.CountDecrement(5);
getter 函数和 storeToRefs 响应式解构
    定义
        在 @/store/count 对应模块中定义 getters{} 区域
        在 getters 方法函数中获取入参 (state){操作 state中的数据}
    使用
        doubleCount 可以同 state 中定义的数据一样直接使用
        可以使用解构赋值 和 storeToRefs 可以简化数据操作并保证数据的响应式
        let { count,doubleCount } = storeToRefs(counterStore);
$subscribe 监听数据变化
    store.$subscribe((mutation,state)=>{})
        mutation:一个包含变化信息的对象,它描述了状态是如何被改变的(比如通过直接设置、通过 action 修改等),但它不直接包含旧状态的值。
        state:store 的当前状态的快照。

    counterStore.$subscribe((mutation, state) => {
        console.log('状态变化了:', mutation, '新状态:', state)
        console.log('新的count:', state.count)
    });

15 组件

组件切换
    组件切换
        v-if        
        component :is="指定活动组件"  
组件传值
defineProps
    默认传值:
        withDefaults(defineProps<{person:IPerson, list?:IPerson[]}>(), {
            list: () => [{ id: '100', username: 'haha', age: 14 }]
        });

    父->子组件传值
        
    通过调用的子组件给其通过 给子组件 绑定值传递
        子组件通过 defineProps(['','']) 获取值
        defineProps<{num:string,name:string,preson:Presons}>()   ts中可以指定传递的值类型
v-bind/v-on/v-model
    子->父组件传值
        事件绑定传值     
            :bindName='funcName'
            defineProps(['bindName'])
            props.bindName(parames);   

        自定义事件传值
            @bindName='funcName'
            defineEmits(['bindName']) 
            emit('bindName',parames);

        v-model 双向绑定传值(重要)
            原理: v-model 绑定的属性,会自动绑定 v-bind 和 v-on,v-bind:value="value" v-on:input="value = $event.target.value"
            例子:  ===  
                    ===  

            子组件:
                let emit = defineEmits(['update:list']);      //相当于接受自定义事件
                let props2 = defineProps(['list']);           //接收父组件传值
                emit('update:list',arr);                      //通过emit方法,将数据传递给父组件
ref 和 $parent
    getCurrentInstance : 获取当前实例,vue3 中不能获取 this 的指向,需要通过 getCurrentInstance 获取
    getCurrentInstance()?.proxy.$parent / getCurrentInstance()?.proxy.$refs

    ref 和 $parent
        ref(父组件中获取子组件实例[数据,方法,属性等]): 
            普通元素,获取普通页面元素的值(html)
            组件: 获取组件的实例,通过实例可以获取组件中的数据、方法、属性等 (核心)
                1、子组件定义属性、方法、数据;并通过 defineExpose 暴露出去。
                2、父组件引用子组件并标记 ref 值;并且需要定义一个相同的 ref 值。let childRef = ref(null);
                3、通过子组件 ref 实例调用
                    list.value = childRef?.value?.list   //属性
                    childRef?.value?.addItem('vue')      //方法
    
        $parent(子组件中获取所有的父组件暴露的属性和方法数据)
            1、父组件通过 defineExpose 暴露。
            2、子组件通过 $parent 获取父组件暴露的属性和方法数据。    
            3、调用  
                import { getCurrentInstance } from 'vue';
                let parents = getCurrentInstance()?.proxy.$parent;
                parents.parentData = '通过 $parent 修改父组件值' ;  parents.updateParentData('通过 $parent 调用父组件方法')     
provide/inject
    provide/inject (父->后代)暴露和引入传值
    可以在任意后代组件 inject 获取父组件 通过 provide 暴露出的数据、属性、方法
    使用:
        1、父组件暴露 provide(暴露名)
            provide('msg',msg);
            provide('changeMsg',changeMsg);
            provide('preson',preson);
        2、后代组件引入并使用 inject('暴露名',默认值)
            let msg = inject('msg');
            let preson = inject('preson',{ id: '100', username: 'haha', age: 14 });
            let changeMsg = inject('changeMsg',(val:string)=>{});

其他
    1、attrs:通过内部 $attrs 可以实现父组件向后代组件传值;原理:vue3 中父组件向子组件传值,子组件未明确指定获取的值,会存放到 $attrs 
    2、mitt(任意):同vue2 的pubsub。通过下载并配置 mitt 插件,在组件中通过 mitt.emit('事件名',参数) 除非事件,通过 mitt.on('事件名',回调函数) 监听事件,mitt.off
    ('事件名') 取消监听事件
    3、vuex/pinia(任意): 通过全局数据状态管理,共享属性

组件插槽
    插槽:包括 默认插槽、具名插槽、作用域插槽
        1、所有插槽都包含默认值 默认内容 当使用该插槽定义的组件时,如果没有传递内容,则显示默认内容
        2、默认插槽因为不进行区分,因此在存在多个默认插槽时,会全部相同
默认插槽
    默认插槽:默认值,多个默认插槽值相同
具名插槽(手动指定插槽) v-slot 可以简化
    子组件定义插槽:   顶部区域 
    组件使用处: 
        
         
作用域插槽(指定插槽并可以操作插槽绑定的数据)
    子组件定义插槽:      其中:users 为子组件中定义的数据
    组件使用处: 
        

其他[事件修饰符、自定义指令、多环境配置]

事件修饰符
    .stop    阻止事件冒泡:vue事件会从点击处向外层冒泡触发每一层绑定的相同事件
    .prevent 阻止默认行为,阻止 a,input 等默认带的事件
    .capture 事件捕获,从外到内依次触发每层的事件直到真实的事件触发点
    .self    事件触发控制,当且仅当是元素本身触发事件时才会执行事件。会跳过冒泡和捕获(跳过非拦截)
    .once    事件仅触发一次
    
自定义指令
    全局指令 (main.ts/js)
        app.directive("zlmc",{})
            参数1:指令的名称,注意,在定义的时候,指令的名称前面,不需要加 v- 前缀,但是在调用的时候,必须在指令名称前加上 v- 前缀来进行调用。
            参数2:是一个对象,这个对象身上有一些指令相关的回调函数,这些函数可以在特定的阶段执行相关的操作。

        指令的回调函数有两个参数:
            第一个参数:是指令所绑定的DOM元素,它是HTMLElement类型,通过这个参数,你可以直接访问和操作DOM。例如,你可以改变元素的样式、属性、或者监听事件等。
            第二个参数:是一个对象,它包含了关于指令的详细信息,如指令的值、参数、修饰符等。

    私有指令 (vXxxxxx) v 开头
        const vDoubi = {
            // 在每个函数中,第一个参数都是element,表示被绑定了指令的那个DOM元素,这个element参数,是一个原生的JS对象
            // 第二个参数 binding 提供了关于指令绑定的信息。
            beforeMount(element: any, binding: any) {
                // 此时元素刚绑定了指令,还没有插入到DOM中去
                console.log("执行beforeMount函数:", element, binding);
            },
            // mounted表示元素插入到DOM中的时候会执行mounted函数,只执行一次
            mounted(element: { innerText: string; }, binding: { value: string; }) {
                console.log("执行mounted函数:", element, binding);
                element.innerText = "逗比: " + binding.value; // 初始化,前面添加上逗比
            },
            // 当模板中有数据更新的时候,即使不是当前指令用到的数据,都会执行updated,可能会触发多次
            updated(element: { innerText: string; }, binding: { value: string; }) {
                console.log("执行updated函数:", element, binding);
                element.innerText = "逗比: " + binding.value; // 数据更新后,前面添加上逗比
            },
        }
多环境配置
    项目根目录创建环境配置文件:
        创建普通全局变量 .env
        创建开发环境变量 .env.development
        创建测试环境变量 .env.test
        创建生产环境变量 .env.production
    创建环境变量:
        格式为 VITE_ 开头,格式是:VITE_变量名=值
    使用环境变量:
        import.meta.env.VITE_API_URL
    预定于环境变量:
        import.meta.env.MODE:自带的默认变量 development 、test 、 production
        import.meta.env.BASE_URL:基础路径配置,对应vite.config.ts中的 base 配置项
    指定启动环境:
        在 package.json 文件中,你可以通过 --mode 参数指定构建或启动时使用的环境
        "scripts": {
            "dev": "vite --mode development",  // 以开发环境运行
            "dev:test": "vite --mode test",  // 以测试环境运行
            "build:test": "vite build --mode test",  // 以测试环境打包
            "build:prod": "vite build --mode production",  // 以生产环境打包
            // ...其他
        },

你可能感兴趣的:(vue.js,javascript,ecmascript)