Vue3笔记

Vue3学习

B站:学习笔记
视频地址:https://www.bilibili.com/video/BV1FP4115739/

安装相应环境

  1. 安装node.js
https://nodejs.org/en/
  1. 安装VScode
https://code.visualstudio.com/

一、Vite2

前置知识:

https://vitejs.cn/guide/

二、搭建第一个Vite项目

注意:需要vite需要node.js版本>=12.0.0

npm init vite

1.运行:

PS E:\html\vue3-demo> npm init vite
Need to install the following packages:
  create-vite@3.2.1
Ok to proceed? (y) y
√ Project name: ... vue3-demo
√ Select a framework: » Vue
√ Select a variant: » JavaScript

Scaffolding project in E:\html\vue3-demo\vue3-demo...

Done. Now run:

  cd vue3-demo
  npm install 
  npm run dev

2.进入创建好的文件夹,运行npm install

cd vue3-demo
npm install

3.运行起来

npm run dev

访问以下网址:
在这里插入图片描述
在这里插入图片描述
运行成功!!
public目录下资源浏览器可以直接访问:
在这里插入图片描述
index.html:程序入口,type="module"加上浏览器支持模块化,才能导入Vue模块。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>第一个vite程序</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./src/main.js"></script>
  </body>
</html>

main.js:用于引入Vue后缀的文件,

import { createApp } from 'vue'//导入vue的createApp模块
import App from './App.vue' //导入自己新建的App.vue模块

const app = createApp(App)//创建vue模块
app.mount('#app')//加载vue模块与index.html的div的id对应

App.vue基础模板:单页面应用,以后的组件都在App.vue这个页面挂载。

<script setup>

</script>

<template>
    <div>
        app123
    </div>
</template>

<style lang="css">
    div {
        font-size: 20px;
    }
</style>

1、App.vue基础模板

简写

  • v-bind 对应
    后面跟上标签的属性::style=“{‘textDecoration’ : ui }”
    主要用于ref定义的属性能用于标签属性

  • v-on 对应 @
    主要用于事件触发调用函数

1.导入其他的vue文件
script 里加上 setup,导入其他的vue文件才能作为标签使用

<script setup>
    import Demo from '../src/components/Demo.vue'
</script>

<template>
    <Demo></Demo><!--导入的vue模板文件,可以直接当作标签使用!!-->
</template>

<style lang="css">
    div {
        font-size: 20px;
    }
</style>

2、ref模块

1.导入ref模块,用作定义数据或者类

<script setup>
    import {ref} from 'vue'
</script>

2.使用方法

<script setup>
    import { ref } from 'vue';
    const count = ref(0)//定义为0,也可以是字符串,布尔类型
    const handleClick = function(){
        count.value++//script里操作值要加value
    }
</script>

<template>
    <div>
       {{count}}  //这里不用加value,vue已经帮我们自动获取了,双向绑定
       <button @click="handleClick">add</button>//@click与v-on:click等价,缩写
    </div>
</template>
<style lang="css">
</style>

3、模板语法

<script setup>
   import { ref } from 'vue';
   const msg = ref('xianqitian')
   const rawHtml = ref('<h1>123</h1>')
   const title = ref('title')
   const object = ref({
    id : '110',
    class : 'box'
   })
   const number = ref(100)//定义数字
   const ok = ref(false)//布尔类型
   const works = ref('hello vue3')//定义字符串
   const isshow = ref(true)//布尔类型
   const handleClick = function(){//改变布尔类型的函数
    isshow.value = !isshow.value
   }

   const handleKeyup = function(e){//监测文本框输入的内容到控制台
        console.log(e.target.value)
   }
</script>

<template>
    <div>
      {{msg}}
    </div>

    <div>
      {{ rawHtml }}
    </div>

    <div v-html="rawHtml"></div><!--文本以标签解析显示-->
    <div v-bind:title="title">标题1</div><!--绑定title属性的值-->
    <div v-bind = "object" > 标题2 </div><!--绑定对象属性到标签属性里-->
    <div>
        {{number + 1}}<!--可以运算-->
        {{ ok ? 'yes' : 'no'}}<!--三元运算符,用于判断显示什么值-->
        {{works.split('').reverse().join('')}}<!--字符串转字符,反转,再转字符串-->
        
    </div>
    
    <div v-if="isshow">
        v-if显示了
    </div>
    <div>
        <button v-on:click="handleClick">点击显示开关</button><!--@click等价于v-on:click-->
    </div>

    <div>
        <input type="text" v-on:keyup.enter="handleKeyup"><!--监测文本框输入的内容-->
    </div>

</template>

<style lang="css">

</style>

语法例:v-on:keyup.enter=“handleKeyup”,监听文本框输入,加上.enter是回车后运行handleKeyup方法。
在这里插入图片描述

4、响应式基础

ref与reactive,两种定义属性的方法

<script setup>
    import { ref, reactive } from 'vue'
    const state = reactive({ count : 0 })//reactive定义一定要给对象
    
    const count = ref(0)

    const handleCountAdd = function(){//定义自增方法
        state.count ++
        console.log(state)
    }
    const Add = function(){//定义自增方法
        count.value ++
        console.log(count)
    }

</script>

<template>
    <div>
        <button @click="handleCountAdd">{{state.count}}</button><!--自己定义了哪个值就是哪个-->
    </div>
    <div>
        {{count}}<!--自动解析ref里的value值-->
    </div>
    <div>
        <button @click="Add">{{count}}</button>
    </div>
</template>

<style lang="css">
    
</style>

5、计算属性(computed)

computed属性方法:

<script setup>
    import { ref , computed } from 'vue';
    const count = ref(1)//ref在script里操作数据要加上.value(重要)
    const title = ref( ' hello')

    const handleclick = function(){
        count.value++
    }
    const doubleCount = computed(function(){//推荐用这种方式,点击不会打印
        console.log("hello")
        //计算属性会基于缓存
        return count.value * 2
    })
    // const doubleCount = function(){//用函数的方法技术数据,程序在运行其他的程序时,会额外的执行下面代码块的代码
    //     console.log("hello")
    //     return count.value * 2
    // }

    const handleChangeTitle = function(){
        title.value = "world"
    }
</script>

<template>
    <div>
       {{count}}
    </div>
    <div>
       {{doubleCount}}
    </div>
    <!-- <div>
       {{doubleCount()}}
    </div> -->
    <div>
        <button @click="handleclick">点击</button>
    </div>
    <div>
        {{title}}
    </div>
    <div>
        <button @click="handleChangeTitle">改变值</button>
    </div>
</template>

<style lang="css">

</style>

6、class&style绑定

<script setup>
    import { ref } from 'vue';
    const hasColora = ref(true)
    const italic = ref('italic')
    const ui = ref('underline')//定于属性样式


    const handleChange = function(){
        hasColora.value = ! hasColora.value
    }
    


</script>

<template>  <!-- 既有c的属性,也有italic,a和b的属性-->
    <div class="c" v-bind:class="[ italic , { a: hasColora , b : true } ]"> <!-- 可以判断样式是否显示,可以直接使用变量或者是直接使用布尔值-->
        <p :style="{'textDecoration' : ui }">hello Vue3</p><!-- 引用script里定义的属性值,这样就可以控制样式的显示了-->
    </div>
    <div>
        <button @click="handleChange"> change </button>
    </div>
</template>

<style lang="css">
    .a {
        color: red;
    }
    .b {
        font-size: 50px;
    }
    .c {
        background-color: aqua;
    }
    .italic {
        width: 200px;
        height: 200px;
    }
</style>

例子:example.vue
响应式的样式加载

<script setup>
    import { ref } from 'vue';
    const list = ref(['line1',' line2', 'line3'])
    const curentIndex = ref(0)
    const handleClick = function(index){//修改显示curentIndex为哪个下标
        curentIndex.value = index
    }
</script>

<template>
    <ul>
        <!--index == curentIndex返回一个布尔值,决定是否显示该active的样式-->
        <li 
        v-for = "item,index in list " 
        :class="{active : index == curentIndex}"
        @click="handleClick(index)"><!--传入元素的index,进行修改-->
        
        {{item}}
        </li>
    </ul>
</template>

<style lang="css">
    .active {
        color: red;
        font-size: 50px;
    }
</style>

7、条件渲染(v-if,v-else-if,v-else)

1.v-if,v-else-if,v-else用法,条件为ture就显示。
2.两两元素互斥,使用标签包裹起来,再用v-if标签。

<script setup>
    import { V_ON_WITH_KEYS } from '@vue/compiler-dom';
import { ref } from 'vue';
    const isShow = ref(true)
    const grade = ref(65)

    const handleChange = function(){
        isShow.value = !isShow.value
    }
    const handleKeyup = function(e){
        grade.value = e.target.value
    }
</script>

<template>
   <div v-if="isShow">
    hello
   </div>

   <div>
    <button @click="handleChange">change Show</button>
   </div>

   <div v-if="(grade >= 60)">
    A
   </div>
   <div v-else-if="(grade < 60 & grade >= 30)">
    B
   </div>
   <div v-else="(grade < 30)">
    C
   </div>
   <div>
    <input type="text" v-on:keyup.enter="handleKeyup"><!--监测文本框输入的内容,加上.enter按回车触发函数-->
   </div>

   <div>
    <template v-if="isShow">
        <p>hello</p>
        <p>!!!</p>
    </template>
    <template v-else>
        <p>vue3</p>
        <p>...</p>
    </template>
   </div>
</template>

<style lang="css">

</style>

8、列表渲染(v-if,v-for)

VScode里安装Vue Language Features (Volar)插件
v-if,v-for不能同时作用一个标签上。

  • 数组与对象的元素遍历展示。
<script setup>
    import { ref,reactive } from 'vue';
    const list = ref(['苹果','香蕉','橘子','土豆'])
    const course = reactive({
        title:"Atian学Vue3",
        author:'xianqitian',
        publishDate:'2020-12-07'
    })
</script>

<template>
   <ul>
    <template v-for="itme,index in list"> <!-- (重要)v-for与v-if不能作用与同一个标签上,所以要分开使用-->
        <li v-if="itme!='土豆'"><!-- 遍历数组中的元素,并实现过滤-->
            {{index}}-{{itme}}
        </li>       
    </template>
   </ul>

   <ul>
    <li v-for="c,k,i in course">  <!--遍历对象中的属性: i是下标,k是属性名,c是属性值 -->
        {{i}}-{{k}} : {{c}}
    </li>
   </ul>


</template>

<style lang="css">

</style>

9、事件处理($event)

简写

  • v-bind 对应
    后面跟上标签的属性::style=“{‘textDecoration’ : ui }”
    主要用于ref定义的属性能用于标签属性

  • v-on 对应 @
    主要用于事件触发调用函数

重要
触发两个函数运行,vue3特有的

<script setup>
    import { ref } from 'vue';
    const count = ref(0)
    const handleClick = function(number){
        count.value+=number
    }

    const handleInput = function(number,event){
        console.log(number)
        console.log(event.target.value)//event.target.value为获取到输入框的值
        
    }
    const handle1 = () =>{
        console.log('handle1')
    }
    const handle2 = () =>{
        console.log('handle2')
    }
</script>

<template>
   <div>
    {{count}}
   </div>

   <div>
    <button @click="handleClick(100)">增加</button>
   </div>

   <div>
    <input type="text" @input="handleInput(100,$event)">  <!-- 事件处理,$event特殊写法,使得可以传自己定的参数也可以传原本的$event事件 -->
   </div>

   <div>
    <button @click="(event)=>handleClick(100)">点击1</button><!--该语法了解即可-->
   </div>

   <div>
    <button @click="handle1(),handle2()">点击2</button><!--vue3特有的语法,可以同时调用两个函数,并且要加()运行一下,重要的括号不能忘了-->
   </div>

</template>

<style lang="css">

</style>

10、表单输入绑定(v-model)

1.双向绑定(原始的)
很麻烦

<script setup>
    import { ref } from 'vue';
    const textValue = ref('a')

    const handleInput = (e)=>{
        textValue.value = e.target.value
    }
    
</script>

<template>
   <div>
    <p>{{textValue}}</p>
    <input type="text" :value="textValue" @input="handleInput($event)">
   </div>
</template>

<style lang="css">

</style>

2.语法糖(v-model)

<script setup>
    import { ref } from 'vue';
    const textValue = ref('a')

    // const handleInput = (e)=>{
    //     textValue.value = e.target.value
    // }

    const textAreaValue = ref('a')

    const checked = ref(true)

    const picked = ref('One')

    const favorites = ref([])

    //const selectValue = ref('')//下拉单选字符串就行了
    const selectValue = ref([])//下拉多选要数组
</script>

<template>
   <div>
    <p>{{textValue}}</p>
    <!-- <input type="text" :value="textValue" @input="handleInput($event)"> -->
    <input type="text" v-model="textValue"><!--单行文本框-->
   </div>

   <div>
    
    <p style="white-space:pre-line">{{textAreaValue}}</p><!--加上这行style="white-space:pre-line"输出打印-->
    <textarea v-model="textAreaValue"></textarea><!--多行文本框-->
   </div>

   <div>
    <label for="chb"></label><!--label for是方便用户进行选择的-->
    <input id="chb" type="checkbox" v-model="checked">{{checked}}<!--多选框绑定布尔属性的逻辑(v-model)-->
   </div>
   
   <div>
    {{picked}}<!--选择哪个就是哪个value的值-->
    <input type="radio" value="One" v-model="picked">One <!--单选框绑定布尔属性的逻辑(v-model)-->
    <input type="radio" value="Two" v-model="picked">Two
   </div>

   <div>
    {{favorites}}
    <input type="checkbox" value="篮球" v-model="favorites">篮球<!--多选框绑定数组的逻辑(v-model)-->
    <input type="checkbox" value="台球" v-model="favorites">台球
    <input type="checkbox" value="羽毛球" v-model="favorites">羽毛球
   </div>

   <div><!--下拉框(v-model),也是利用v-model绑定属性进行获取value的值-->
    {{selectValue}}
    <select v-model="selectValue" multiple><!--加上multiple是多选-->
        <option value="">请选择</option>
        <option value="北京">北京</option>
        <option value="上海">上海</option>
        <option value="深圳">深圳</option>
        <option value="广州">广州</option>
    </select>
   </div>

</template>

<style lang="css">

</style>

11、生命周期函数(onMounted…)

为什么要使用生命周期函数,生命周期函数是什么?
因为dom节点没加载出来,就不能操作dom节点,会有问题。
Vue3提供了钩子函数可以使用
Mounted(加载完的意思)
导入onMounted模块

import { ref, onMounted} from 'vue';

在这里插入图片描述

<script setup>
    import { ref, onMounted, onBeforeMount, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from 'vue';//导入开头小写为函数
    const count = ref(0)
    let t = null
    // setTimeout(()=>{   //定时两秒执行,这种方法会频繁的创建setTimeout函数,会有内存溢出的问题。(不建议使用)
    //     count.value+=2
    // },2000)

    //console.log(document.getElementById('a').innerHTML)  //获取不到,因为dom节点没有加载出来(所以需要生命周期函数)

    t = setTimeout(()=>{
        count.value = 2
    },1000)

    onMounted(()=>{  //dom节点渲染完成后的回调函数
        console.log(document.getElementById('a').innerHTML) //放入钩子函数的回调函数里执行,就可以正确的获取到dom的值并输出。
        setTimeout(()=>{
            count.value = 2
        },2000)
    })

    onBeforeMount(()=>{//dom节点渲染前的回调函数
       // console.log(document.getElementById('a').innerHTML)
       // 这里可以用作修改之前定义的属性
    })

    onBeforeUpdate(()=>{
        console.log(document.getElementById('a').innerHTML)//改变属性元素,没渲染完dom元素之前执行,自动执行的
    })

    onUpdated(()=>{
        console.log(document.getElementById('a').innerHTML)//渲染完dom后执行的,自动执行的
    })

    onBeforeUnmount(()=>{//页面卸载之前执行
        console.log('onBeforeUnmount')
    })

    onUnmounted(()=>{//页面卸载之后执行(这里可以做清理函数的作用)
        console.log('onUnmounted')
        clearTimeout(t)//清理函数
    })

</script>

<template>
    <div id="a">
       {{count}}
    </div>
</template>

<style lang="css">

</style>

要想onUnmounted有效果,要在main.js里卸载实列

import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

const app = createApp(App)
app.use(Button)

app.mount('#app')//要注意代码放置的先后顺序


//卸载组件
 setTimeout(()=>{
     app.unmount()
 },5000)

12、监听器(watchEffect,watch)

类似于:狙击手一枪毙命,不像computed 要返回值。
就偷偷观察,你变我也变。
导入watchEffect,watch

import { ref , watchEffect , computed, watch } from 'vue';
<script setup>
    import { ref , watchEffect , computed, watch } from 'vue';
    const count = ref(0)
    const title = ref('hello')
    const doubleCount = computed( () => count.value * 2 )

    const handleClick = ()=>{
        count.value ++
        title.value =  "vue3"
    }

    // watchEffect(()=>{//能监听watchEffect里有的属性变化,代码块里的属性有变化就执行该监听器。(所有都会变化,不精准)
    //     console.log('count变化了:'+count.value)
    //     console.log('title变化了:'+title.value)
    // })

    // watch(//精确的监听页面,值变化,值不变化是不会执行的
    //     count,//监听的值
    //     ()=>{//监听的值变化了,就执行以下代码
    //     console.log('count变化了:'+count.value)
    //     }
    // )

    watch(//精确的监听页面,值变化,值不变化是不会执行的(第二种写法)
        ()=>{
            //这里可以写逻辑(一百行逻辑)
            console.log('hello vue3!!')
           return count.value  //监听的值
        },
        ()=>{//监听的值变化了,就执行以下代码
            console.log('count变化了:'+count.value)
        }
    )

</script>

<template>
   <div>
    {{count}}
    {{doubleCount}}
    {{title}}
   </div>
   <div>
    <button @click="handleClick">add</button>
   </div>
</template>

<style lang="css">

</style>

watch和 watchEffect都能响应式地执行有副作用的回调。它们之间的主要区别是追踪响应式依赖的方式;

  • watch 只追踪明确侦听的源。它不会追踪任何在回调中访问到的东西。另外,仅在响应源确实改变时才会触发回调。watch 会避免在发生副作用时追踪依赖,因此,我们能更加精确地控制回调函数的触发时机。
  • watchEffect,则会在副作用发生期间追踪依赖。它会在同步执行过程中,自动追踪所有能访问到的响应式property。这更方便,而且代码往往更简洁,但其响应性依赖关系不那么明确。

13、组件注册

组件允许我们将U划分为独立的、可重用的部分来思考。组件在应用程序中常常被组织成层层嵌套的树状结构:
在这里插入图片描述
这和我们嵌套HTML元素的方式类似,Vue实现了自己的组件数据模型,使我们可以在每个组件内封装自定义内容与逻辑。Vue同样也能很好地配合原生Web Component。

1.引入全局组件

先定义组件vue文件。
GlobalComponent.vue

<script setup>
    import { ref } from 'vue';
    
</script>

<template>
    <div>
       global component
    </div>
</template>

<style lang="css">

</style>

2.main.js配置

(重要)app.component(‘GC’,GlobalComponents)//将该页面定义为全局组件

import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

import  GlobalComponents  from './componentss/GlobalComponent.vue'

const app = createApp(App)

app.component('GC',GlobalComponents)//将该页面定义为全局组件,GC是自己起的名字

app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序


//卸载组件
// setTimeout(()=>{
//     app.unmount()
// },5000)

3.使用组件

<GC></GC><!-- 引入全局组件 -->
<script setup>
    import { ref } from 'vue';
</script>

<template>
   <div>
    <GC></GC><!-- 引入全局组件 -->
   </div>
</template>

<style lang="css">

</style>
2.引入局部组件

1.定义Child.vue组件

<script setup>
    import { ref } from 'vue';
    
</script>

<template>
    <div>
       Child
    </div>
</template>

<style lang="css">

</style>

2.导入局部组件

import Child from '../componentss/Child.vue'//导入局部组件

3.引入局部组件

<Child></Child><!-- 引入局部组件 -->
<script setup>
    import { ref } from 'vue';
    import Child from '../componentss/Child.vue'//导入局部组件
</script>

<template>
   <div>
    <GC></GC><!-- 引入全局组件 -->
    <Child></Child><!-- 引入局部组件 -->
   </div>
</template>

<style lang="css">

</style>

14、组件中的数据传递

1.Props(主要是父子主键传递数据)
1.1 父组件传递给子组件(通过绑定属性)

标签上使用(:属性= “XXX” )来向子组件传递数据。
传递会跟着变化

<script setup>
    import { ref } from 'vue';
    import Child1 from '../componentss/Child1.vue'
    import Child2 from '../componentss/Child2.vue'

    const count = ref(100)//传递的属性

</script>

<template>
    <div>
    <Child1 :count="count"></Child1>  <!-- 使用:count="count"方式来传递属性 -->
    <Child2 :count="count"></Child2> <!-- 使用:count="count"方式来传递属性 -->
    </div>
</template>

<style lang="css">
</style>

子组件使用父组件传来的属性:
用defineProps([‘count’])接收

<script setup>
    import { ref } from 'vue';
    defineProps(['count'])//接收父组件传来的属性
</script>

<template>
    <div>
       Child1-{{count}}<!--使用属性-->
    </div>
</template>

<style lang="css">

</style>
1.2 子组件传递给父组件(通过调用函数传值)

1.父组件里先定义自己的事件:@my-event=“handleMyEvent”

const handleMyEvent = (msg)=>{//要子组件能调用这个方法,父组件才能获取到值。
        console.log(msg.value)//这里拿到子组件传的值
    }
<Child2 :count="count" @my-event="handleMyEvent"></Child2> <!-- 自定义事件:@my-event="handleMyEvent"用来使得子组件能向父组件传递参数 -->

2.然后让子组件调用该事件函数(重要const emit = defineEmits([‘my-event’]))

const emit = defineEmits(['my-event'])//获取到父组件自己定义的事件

    const title = ref('hello VUE3')

    onMounted(()=>{//dom节点渲染完成就执行这个方法
        emit('my-event',title)//调用父组件的my-event方法传title过去(重要)

        console.log(values.count)//这里属于模板外,所以要变量接收才能调用
    })

3.完整代码(如下)
Props.vue

<script setup>
    import { ref ,onMounted} from 'vue';
    import Child1 from '../componentss/Child1.vue'
    import Child2 from '../componentss/Child2.vue'

    const count = ref(100)

    onMounted(()=>{
        setTimeout(()=>{
            count.value = 10000
        },5000)
    })

    const handleMyEvent = (msg)=>{//要子组件能调用这个方法,父组件才能获取到值。
        console.log(msg.value)//这里拿到子组件传的值
    }

</script>

<template>
    <div>
    <Child1 :count="count"></Child1>  <!-- 使用:count="count"方式来传递属性 -->
    <Child2 :count="count" @my-event="handleMyEvent"></Child2> <!-- 自定义事件:@my-event="handleMyEvent"用来使得子组件能向父组件传递参数 -->
    </div>
</template>

<style lang="css">

</style>

Child2.vue

<script setup>
    import { ref, onMounted} from 'vue';
    const values = defineProps(['count'])//模板直接使用不需要变量接收({{count}}),模板以外要变量接收才能使用
    const emit = defineEmits(['my-event'])

    const title = ref('hello VUE3')

    onMounted(()=>{//dom节点渲染完成就执行这个方法
        emit('my-event',title)//调用父组件的my-event方法传title过去(重要)

        console.log(values.count)//这里属于模板外,所以要变量接收才能调用
    })

</script>

<template>
    <div>
        Child2-{{count}}
    </div>
</template>

<style lang="css">

</style>

15、事件(defineEmits)

1.子组件向父组件传数据的第二种方法
定义component-event.vue(v-model:t=“title”)定义事件

<script setup>
    import { ref } from 'vue';
    import Chile from '../componentss/Child.vue'

    const title = ref('hello')
</script>

<template>
    {{title}}
   <Chile v-model:t="title"></Chile><!-- 这里定义t事件,子组件调用传参 -->
</template>

<style lang="css">

</style>

2.子组件调用事件传参(const emit = defineEmits([‘update:t’]), emit( ‘update:t’,title.value ))

<script setup>
    import { onMounted, ref } from 'vue';

    const title = ref('VUE3')
    
    const emit = defineEmits(['update:t'])//获取到父组件的子组件标签上的定义事件。(注意单词很容易写错,update:固定写法)

    onMounted(()=>{
        emit( 'update:t',title.value )//触发事件,传参给父组件。
    })

</script>

<template>
   <div>
    Child
   </div>
</template>

<style lang="css">

</style>

16、透传:attributes

1.transparent.vue

<script setup>
    import { ref } from 'vue';
    import Child3 from '../componentss/Child3.vue'//调用局部组件
</script>

<template>
    <div>
    <Child3 title="hello" class="a"></Child3> <!-- 这样子写属性会自动添加到子组件上 -->
    </div>
</template>

<style lang="css">
    .a {
        color: red;
    }
</style>

2.Child3.vue

<script>
export default {//阻断透传
    inheritAttrs: false
}
</script>

<script setup>
    import { ref ,useAttrs} from 'vue';

    const attrs = useAttrs()
    console.log(attrs)//获取属性集合,父组件传递的属性
</script>

<template>
    <div id="child"> Child3</div> <!-- 注意带上div -->
</template>

<style lang="css">

</style>

17、插槽(v-slot:XXX)

1.v-slot:XXX只能用于父组件的template标签上(具名插槽)

<!--可以只写v-slot:line2,不获取子组件传来的值也可以-->
<template v-slot:line2> <!-- v-slot:只能作用到template标签上 -->
    <div>VUE3</div><!--{{XXXX}}可以传递自己的常量-->
</template>

2.slot标签用于子组件里

<slot name="line2"></slot><!--name="line2"标识是哪个插槽-->

作用域插槽(v-slot:default默认显示)

<template v-slot:default="data01"><!--data就是子组件传过来的值(是一个数组)-->
     <div>{{hello}} slot {{data01.mark}}--{{data01.hello}}</div>  <!--{{data01.mark}}--{{data01.hello}}获取子组件传来的值,并用于标签显示-->
</template>

3.slot.vue

<script setup>
    import { ref } from 'vue';
    import Child4 from '../componentss/Child4.vue';

    const hello = ref('hello')
</script>

<template>
   <Child4>
    <!--可以直接v-slot:default="{mark,hello}"解析出传过来的属性,然后直接使用-->   
    <template v-slot:default="data01"><!--data就是子组件传过来的值(是一个数组)-->
        <div>{{hello}} slot {{data01.mark}}--{{data01.hello}}</div>  <!--{{data01.mark}}--{{data01.hello}}获取子组件传来的值,并用于标签显示-->
    </template>

    <!--可以只写v-slot:line2,不获取子组件传来的值也可以-->
    <template v-slot:line2="data02"> <!-- v-slot:只能作用到template标签上 -->
        <div>{{hello}} VUE3--{{data02.vue3}}</div><!--{{hello}}可以传递自己的常量-->
    </template>
   </Child4>
</template>

<style lang="css">

</style>

4.Chlid4.vue


<script setup>
    import { ref } from 'vue';
    const mark = ref('!!!')
</script>

<template>
    <div>
        <!--标签里的hello为默认值,如果主组件没有定义就显示这个。:mark冒号解析上面script定义的值,相当于是v-bind-->
        <!--也可以定义普通的属性用来传递(hello="hello")-->
        <slot :mark="mark" hello="hello">hello</slot>
        <slot name="line2" vue3="vue3"></slot><!--name="line2"标识是哪个插槽-->
    </div>
</template>

<style lang="css">

</style>

使用图例:
在这里插入图片描述

简写:v-slot = ‘#’(重要)

18、依赖注入(任何主键中数据传递的方法)

  • vue中解构provide和inject

1.使用:provide函数定义title属性,值为hello。用于孙组件获取值

provide('title','hello')//使用provide函数定义title属性,值为hello。用于孙组件获取值

2.使用:inject(‘title’)注入值,来使用。(可以在任何的组件里使用)

const title = inject('title')

3.inject-provide.vue

<script setup>
    import { onMounted, provide, ref } from 'vue';
    import Child5 from '../componentss/Child5.vue'
    import Child6 from '../componentss/Child6.vue'
    const title = ref('hello2')
    provide('title',title)//使用provide函数定义title属性,值为hello。用于孙组件获取值
    provide('count','100')//是响应式的,非常方便。

    onMounted(()=>{//是响应式的,非常方便。
        setTimeout(() => {
            title.value = 'VUE3'
        }, 2000);
    })
</script>

<template>
    <div>
        <Child5></Child5>
        <Child6></Child6>
    </div>
</template>

<style lang="css">

</style>

4.Chlid5和Child6

<script setup>
    import { ref,inject } from 'vue';
    const title = inject('title')//属性注入
</script>

<template>
   <div>Child5--{{title}}</div>
</template>

<style lang="css">

</style>
<script setup>
    import { ref ,inject} from 'vue';
   import Grandson from './Grandson.vue';
   const title = inject('title')//属性注入
</script>

<template>
   <div>{{title}}--Child6</div>
   <Grandson></Grandson>
</template>

<style lang="css">

</style>

5.Grandson.vue

<script setup>
    import { ref,inject} from 'vue';//inject注入
    const title = inject('title')//属性注入
    const count = inject('count')
</script>

<template>
    <div>{{title}}--Grandson--{{count}}</div>
</template>

<style lang="css">

</style>

19、组合式函数(模块化的拆分)

1.Demo.vue

<script setup>
    import useTitle from './useTitle'//拆分模块,导入不同功能的模块
    import useCount from './useCount'//拆分模块,导入不同功能的模块
    const {count,handleClick} = useCount()//解析出两个相当于是模块
    useTitle(count)
</script>

<template>
    <div>
       {{count}}
       <button @click="handleClick">add</button>
    </div>
</template>

<style lang="css">

</style>

2.useTitle.js

import {onMounted,onUpdated} from 'vue'
const useTitle = (title)=>{
    onMounted(()=>{
        document.title = title.value
    })

    onUpdated(()=>{//页面数据修改之后触发!!
        document.title = title.value
    })
}

export default useTitle // 将函数暴露出去

3.useCount.js

import { onMounted, onUpdated, ref } from 'vue';
const useCount = () => {
    const count = ref(0)
    const handleClick = function(){
        count.value++
    }
    return {count,handleClick}//有属性的对象,要返回属性跟函数
}

export default useCount // 将函数暴露出去

20、自定义指令

1.定义指令的js文件

const focus = {
    mounted: (el) => el.focus()//自动获取焦点的指令
}
export default focus  

2.在main.js里将一个自定义指令全局注册到应用层级也是一种常见的做法

  • app.directive(‘focus’,focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

import  GlobalComponents  from './componentss/GlobalComponent.vue'

import focus from './instructions/focus.js'
const app = createApp(App)

app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法

app.component('GC',GlobalComponents)//将该页面定义为全局组件

app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序


//卸载组件
// setTimeout(()=>{
//     app.unmount()
// },5000)

3.使用自己定义的指令

  • < input v-focus/> 使用自己定义的指令
<script setup>
    import { ref} from 'vue';
</script>

<template>
    <div>
        <input v-focus/><!-- 使用自己定义的指令 -->
    </div> 
</template>

<style lang="css">

</style>

21、插件

插件 (Plugins) 是一种能为 Vue 添加全局功能的工具代码。
1.定义自己的插件

import Demo from '../components/Demo.vue'
export default {
    install(app,options){
        // 配置此应用
        //插件没有严格定义的使用范围,但是插件发挥作用的常见场景主要包括以下几种:
        
        //1.通过 app.component() 和 app.directive() 注册一到多个全局组件或自定义指令。
        app.component('Demo',Demo)//注册了全局组件

        //2.通过 app.provide() 使一个资源可被注入进整个应用。
        //3.向 app.config.globalProperties 中添加一些全局实例属性或方法
        //4.一个可能上述三种都包含了的功能库 (例如 vue-router)。
        app.mixin({
            mounted(){
                console.log(options)//输出hello
            }
        })
    }
}

2.main.js中加载自己定义的插件

import myPlugin from './plugin/myPlugin'
app.use(myPlugin,'myPlugin-test')//定义自己的插件:第一个参数是插件,第二个参数是传递的值
import { createApp} from 'vue'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

import  GlobalComponents  from './componentss/GlobalComponent.vue'

import focus from './instructions/focus.js'


import myPlugin from './plugin/myPlugin'


const app = createApp(App)

app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法

app.component('GC',GlobalComponents)//将该页面定义为全局组件

app.use(myPlugin,'myPlugin-test')//定义自己的插件:第一个参数是插件,第二个参数是传递的值

app.use(Button)
app.mount('#app')//要注意代码放置的先后顺序


//卸载组件
// setTimeout(()=>{
//     app.unmount()
// },5000)

3.使用自己定义插件里注册的全局组件

<script setup>
    import { ref } from 'vue';
   
</script>

<template>
   <Demo></Demo>
</template>

<style lang="css">

</style>

三、路由(vueRouter4)

vueRouter4
在这里插入图片描述

// 1. 定义路由组件.
// 也可以从其他文件导入
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. 定义一些路由
// 每个路由都需要映射到一个组件。
// 我们后面再讨论嵌套路由。
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

// 3. 创建路由实例并传递 `routes` 配置
// 你可以在这里输入更多的配置,但我们在这里
// 暂时保持简单
const router = VueRouter.createRouter({
  // 4. 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
  history: VueRouter.createWebHashHistory(),
  routes, // `routes: routes` 的缩写
})

// 5. 创建并挂载根实例
const app = Vue.createApp({})
//确保 _use_ 路由实例使
//整个应用支持路由。
app.use(router)

app.mount('#app')

// 现在,应用已经启动了!s

1、vue3项目流程

1.index.html引入main.js文件定义 < div id=“app” >< /div >用来挂载vue将应用实例的根组件挂载在提供的 DOM 元素上。

 <body>
    <div id="app"></div>
    <script type="module" src="./src/main.js"></script>
  </body>

2.main.js导入各种组件,加载渲染。

import { createApp} from 'vue'
import Router from './router/router'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

import  GlobalComponents  from './componentss/GlobalComponent.vue'

import focus from './instructions/focus.js'


// import myPlugin from './plugin/myPlugin'//导入自定义插件


const app = createApp(App)

app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法

app.component('GC',GlobalComponents)//将该页面定义为全局组件

//定义自己的插件:第一个参数是插件,第二个参数是传递的值
//app.use(myPlugin,'myPlugin-test')  

app.use(Router)//注册页面路由

app.use(Button)
app.mount('#app')//mount方法,将应用实例的根组件挂载在提供的 DOM 元素上#app对应index.html的<div id="app"></div>。(要注意代码放置的先后顺序)


//卸载组件
// setTimeout(()=>{
//     app.unmount()
// },5000)

3.App.vue:main.js文件导入了App.vue,使用const app = createApp(App)来创建vue单独的入口。

<script setup>
    // import Demo from '../src/components/Demo.vue'
    // import Demo from '../src/components/Demo2.vue'
    // import Demo from '../src/components/Demo3.vue'
    // import Demo from '../src/components/Demo4.vue'
    // import Demo from '../src/components/Demo5.vue'
    // import Demo from '../src/components/Example.vue'
    // import Demo from '../src/components/Demo6.vue'
    // import Demo from '../src/components/Demo7.vue'
    // import Demo from '../src/components/Event.vue'
    // import Demo from '../src/components/Form.vue'
    // import Demo from '../src/components/LifeCycle.vue'
    // import Demo from '../src/components/watcher.vue'
    // import Demo from '../src/components/components.vue'
    // import Demo from '../src/components/Props.vue'
    // import Demo from '../src/components/component-event.vue'
    // import Demo from '../src/components/transparent.vue'
    // import Demo from '../src/components/slot.vue'
    // import Demo from '../src/components/inject-provide.vue'
    // import Demo from './composition-functions/Demo.vue'
    // import Demo from './instructions/Demo.vue'
    // import Demo from './plugin/Demo.vue'
    import Demo from './router/Demo.vue'
</script>

<template>
    <Demo></Demo>
</template>

<style lang="css">
</style>

4.定义router.js路由文件。

import { createRouter,createWebHistory } from "vue-router";//载入createRouter,createWebHistory模块
import Home from './Home.vue'//导入需要跳转的vue页面
import About from './About.vue'//导入需要跳转的vue页面

const routes = [
    {
        path:'/',
        redirect: '/home'//重定向页面
    },
    {
        path:'/home',
        component: Home//跳转的组件
    },
    {
        path:'/about',
        component: About//跳转的组件
    }
]

const router = createRouter({//创建router函数,创建相关的参数。
    routes,
    history: createWebHistory()
})

export default router //暴露router函数,方便其他文件调用。

5.新建Home.vue和About.vue

<script setup>
    
</script>

<template>

    <div>Home</div>
   
</template>

<style lang="css">

</style>
<script setup>
    
</script>

<template>

    <div>Home</div>
   
</template>

<style lang="css">

</style>

四、pinia(状态管理工具)

1.安装pinia

# 或者使用 npm
npm install pinia

2.在vue3的main.js里载入pinia

import { createPinia } from 'pinia'

app.use(createPinia())
import { createApp} from 'vue'
import Router from './router/router'
import { Button } from 'vant'//vue3小程序主键库
import App from './App.vue'//导入vue主入口文件(单页面应用)

import ElementPlus from 'element-plus'//导入element-plus
import 'element-plus/dist/index.css'//导入element-plus

import {createPinia} from 'pinia'//导入pinia类似于vuex的工具

import  GlobalComponents  from './componentss/GlobalComponent.vue'//将该页面定义为全局组件

import focus from './instructions/focus.js'//将一个自定义指令全局注册到应用层级也是一种常见的做法


// import myPlugin from './plugin/myPlugin'//导入自定义插件


const app = createApp(App)

app.directive('focus',focus)//将一个自定义指令全局注册到应用层级也是一种常见的做法

app.component('GC',GlobalComponents)//将该页面定义为全局组件


app.use(createPinia())//导入pinia类似于vuex的工具,不要忘记带括号,执行一下。

//定义自己的插件:第一个参数是插件,第二个参数是传递的值
//app.use(myPlugin,'myPlugin-test')  

app.use(Router)//注册页面路由

app.use(ElementPlus)//注册element-plus

app.use(Button)
app.mount('#app')//mount方法,将应用实例的根组件挂载在提供的 DOM 元素上#app对应index.html的<div id="app"></div>。(要注意代码放置的先后顺序)


//卸载组件
// setTimeout(()=>{
//     app.unmount()
// },5000)

3.使用pinia

https://pinia.web3doc.top/core-concepts/actions.html

1、创建store目录,目录下新建各种XXXXStore.js管理状态。(可以定义多个管理不同的状态)
例子:counterStore.js

import { defineStore } from 'pinia'


const useCounterStore = defineStore('StoreName',{//StoreName是自己定义的,defineStore方法返回的是函数
    state : ()=>{//定义state函数,并添加返回值
        return {
            count : 100
        }
    },
    actions:{//actions是对象,里面可以定义很多的函数(重要:可以使用异步函数,页面渲染完用vue里的onMounted方法调用后端接口)
        add(){
            this.count++//用this关键字来访问上述定义的值
        }
    },
    getters:{//定义计算state里的方法
        tolalPrice(){
            return this.count + 100
        }
    }
})

export default useCounterStore

Demo.vue

<script setup>
    import {storeToRefs} from 'pinia' //解构成ref
    import useCounterStore from '@/store/counterStore'
	import { onMounted } from 'vue';

    const counterStore =  useCounterStore()//用一个变量来接收useCounterStore暴露出的属性和方法
    const {count} = storeToRefs(counterStore)//可以直接使用,也可以解构成ref来用。(方法解构不了)
    const add = counterStore.add//解构,解不解都行,counterStore.add直接用也行
    console.log(counterStore)//输出的是proxy的对象
</script>

<template>
    <div>
       {{count}}<!--使用counterStore里的定义的count值-->
    </div>
    <div>
        <button @click='add()'>add</button><!--使用counterStore里的定义的add方法-->
    </div>
    <div>
        {{counterStore.tolalPrice}}<!--调用counterStore里getters里定义计算属性的值-->
    </div>
</template>

<style lang="css">

</style>

4.常用方法

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值