vue3一天内快速学习

简介

最流行的前端框架之一,本篇博文期望快速阅览 vue3 的知识点,1 天内看完,剩下就是熟练加综合应用了

npm 是包管理工具,相当于可以用它从中央仓库中拿到依赖包

node.js 实际上就是 js 的运行环境

vue3 学习

安装

mac 中先通过 brew 安装 node,这样 npm 也会自动帮你安装好

下载常用的 ide 软件 webstorm

使用 npm 安装 vue/cli,注意镜像源可以改成国内

npm install -g @vue/cli

安装好之后,在 webstorm 创建 vue 项目,然后我们运行一下

npm run serve

vue3 项目起来了,点击链接即可看到 vue 网页

http://localhost:5173/

项目结构

- project_name
    - node_modules 依赖
    - public
    - src 主要编码处
        - assets 存放静态资源,比如 css 文件,图片等
        - components vue 的组件
        - App.vue 主入口的组件,根组件,所有组件都是从这里开始
        - main.js js 主入口
    - index.html 首页

基础知识

学习的 vue3 之前您需要先要了解 html+css+javascript 的基础知识才能进行如下学习

扫描二维码关注公众号,回复: 15742996 查看本文章

应用实例必须挂载到 dom 元素或者 css 选择器之后才能渲染出来

<div id="app"></div>
app.mount('#app')

vue 开发时候,一个页面一般会有多个应用(app1,app2),将他们分别挂在到所需元素上

const app1 = createApp({
    
    
  /* ... */
})
app1.mount('#container-1')

const app2 = createApp({
    
    
  /* ... */
})
app2.mount('#container-2')

模版语法

{ {}}

双大括号传文本值

<span>Message: {
   
   { msg }}</span>
data() {
    
    
    return {
    
     // 返回一个对象
        msg: "文本"
    }
}

模版中支持表达式,比如 + 呀,三元运算啊,甚至函数语法,但不支持语句,比如 var 声明一个变量,这是一个语句就不行

// 支持
{
   
   { message.split('').reverse().join('') }}

v-html

使用 v-html 做属性传 html 内容,这样前端展现能看到 div 中有一个 html 了

<div v-html="rawHtml"></div>
data() {
    
    
    return {
    
    
        rawHtml: "<a href='www.baidu.com'>百度</a>"
    }
}

v-bind

使用 v-bind 传递属性,如下其 id 就等于 1000,v-bind 可以简写成 : 即可

<div v-bind:id="dynamicId"></div>
data() {
    
    
    return {
    
    
        dynamicId: 1000
    }
}

渲染展示

v-if 和 v-else

条件渲染一块内容,如下为 ture 就渲染

<p v-if="flag">展示</p>
data() {
    
    
    return {
    
    
        flag: true
    }
}

v-else 可以配合 v-if 一起使用

<p v-if="flag">展示</p>
<p v-else>不展示</p>

v-show

v-show 和 v-if 一样效果,那区别呢

v-if 你在打开网页检查能观察到那个 html 语句被删除了就没有被渲染,但是 v-show 发现那个不展现出来的语句还是被渲染了存在这样的 html 语句只不过 display 属性是 none,也就是说 v-if 开销更大

v-for 和 item in xxx

列表渲染,下面 item 你可以随便起名字,表示 newsList 中一个对象

<ul>
    <li v-for="item in newsList">
    {
   
   { item.title }}
    </li>
</ul>
data() {
    
    
    return {
    
    
        newsList: [
            {
    
    
                id: "1001",
                title: "新闻1"
            },
            {
    
    
                id: "1002",
                title: "新闻2"
            }
            
        ]
    }
}

然后有一个点,如果 js 这里多写了一个对象 id: 1003,vue 很好他不会把所有的 1001-1003 全部渲染,只会渲染新的 1003,但是要依赖于你家一个属性 key,vue 通过 key 能知道新加了什么对象

<ul>
    <li v-for="item in newsList" :key="item.id">
    {
   
   { item.title }}
    </li>
</ul>

如果没有 id 怎么办,数组下标也是唯一的,下面这种方式也可以

<ul>
    <li v-for="(item,index) in newsList" :key="index">
    {
   
   { item.title }}
    </li>
</ul>

事件处理

如何监听事件 v-on: 或者 @

简单例子

如下不断点击,就回不断加一显示

<button @click="count+=1"></button>
data() {
    
    
    return {
    
    
        count: 1
    }
}

触发函数

其实更常见是是 click 触发一个函数,而不是一个简单的表达式

<button @click="foo"></button>
data() {
    
    
    return {
    
    
        // 返回值
    }
}
methods: {
    
    
    foo() {
    
    
        // 函数操作
        // 需要读取 data 中是属性,请求用 this.xxx
    }
    /*
    foo(event) { // 这样也可以,可以使用 dom 中 event. 来设置一些东西
        // 函数操作
        // 需要读取 data 中是属性,请求用 this.xxx
    }
    */
}

函数带参数

传参数

<button @click="foo('aaa')"></button>
methods: {
    
    
    foo(data) {
    
     // 使用 data 接收
        // 函数操作
        // 需要读取 data 中是属性,请求用 this.xxx
    }
}

表单数据绑定 v-model

简单例子

如下,就是 v-model 绑定了 data 中返回的 username,然后随着 input 的输入,然后 p 标签中就回出现文本

<input type="text" v-model="username"></input>
<p>{
   
   { username }}</p>
data() {
    
    
    return {
    
    
        username: ""
    }
}

修饰符

下面 input,textarea,select 效果类似

.lazy

回车或者失去焦点时候触发,如下表示输入 msg 之后,当回车时候 p 中才会显示

<input v-model.lazy="msg"></input>
<p>{
   
   { msg }}</p>

.trim

自动过滤用户输入的文本的首尾空白字符

vue 的组件

单模版文件 SFC

.vue 结尾的 SFC 文件就是组件,后缀名以 .vue 结束

单文件组件包含 3 部分

<template>
</template>

<script>
</script>

<style>
</style>

实际中使用时候,往往App.vue 中会集成很多单文件组件,比如说在 App.vue 中有如下, script 中是不是很想 main 中集成了很多函数方法,通过 import 把这些函数引过来,然后在 components 中进行注册使用,最后在 template 中就可以展现出这个组件。可以把每个组件当成页面上某一个模块,这个模块就像一个函数方法,大家都被放在 App.vue 中使用集成

<template>
    <MyComponent />
</template>

<script>
import MyComponent from "./components/MyComponent.vue"

export default {
      
      
    name: 'App',
    components: {
      
      
        MyComponent
    }
}
</script>

<style scoped> // scoped 表示当前样式只在当前组件中生效
</style>

在这里插入图片描述

组件之间数据交互

prop 父组件到子组件传递

可以用于父组件到子组件的传递参数,具体看如下示例就明白了

子组件

<template>
{
   
   { key }}
</template>

<script>
export defualt {
      
      
    name: 'MyComponent',
    props: {
      
      
        key: {
      
      
            type: String,
            default: '' // 默认值
        }
    }
}
</script>

根组件

<template>
<MyComponent :key="title" /> // 传递数据
</template>

<script>
import MyComponent from './components/MyComponent.vue'

export default {
      
      
    name: 'App',
    data() {
      
      
        return {
      
      
            title: "标题"
        }
    },
    components: {
      
      
        MyComponent
    }
    
}
</script>

但是需要注意的是数组的默认值 default 必须用函数承接,这么写

default: funtion() {
    return []
}

$emit 反向传递:自定义事件

其实就是子组件 script 脚本中如果通过 $emit 给某个 key 赋值 value,然后在父组件中就能自定一个事件,这个事件就是@key,然后函数名中的(data)就是反向传过来的 value 了

看栗子,子组件

<template>
</template>

<script>
export default {
      
      
    name: "MyComponent",
    methods: {
      
      
        foo() {
      
      
            this.$emit("onEvent", "反向传递的数据")
        }
    }
}
</script>

父组件

<template>
    <button @onEvent="bar">按钮</button>
</template>

<script>
import MyComponent from "./"

export default: {
      
      
    name: "App",
    components: {
      
      
        MyComponent
    },
    methods: {
      
      
        bar(data) {
      
       // 这里 value 就传递过来了
            console.log(data)
        }
    }
}
</script>

组件生命周期

vue 共有 8 个生命周期

  • 创建时:beforeCreate,created
  • 渲染时:beforeMount,mounted
  • 更新时:beforeUpdate,updated
  • 卸载时:beforeUnmount,unmounted

比如我们在刷新页面时候,其实执行的是’创建时’和’渲染时’,当触发某个事件更新了某个布局,其实就是’更新时’被运行了

常见的可以把网络请求放在 mounted 渲染装框完成之后;把一些消耗资源的比如定时器逻辑的销毁放在 beforeUnmount 准备卸载之后

vue 引入第三方

vue 中有很多第三方,在实际工作项目中你可以直接拿来使用,比如轮播图效果人家写好的,你直接拿过来引用即可,而不是你造一个轮子

第三方组件在哪找呢:

  • vue 官方网站里头,可以找到 vue 推荐的一些第三方组件生态
  • 直接谷歌搜索 vue 某个一个效果的组件
  • github 去搜 vue 的组件
  • 靠经验知道经常用哪些 vue 组件

推荐一些好用的:

  • swiper:(swiper.com.cn)
    开源免费,触摸滑动的轮播图组件,纯 js 打造,面向平台,手机,电脑

网络请求

_Axios 网络请求

安装介绍

Axios 其实也是第三方的一个网络请求库,基于 promise 网络请求库

安装

npm install --save axios

get post 使用

一种是组件中引用另一种是全局引用,一般开发中基本都是全局去引用了,因为存在网络请求的组件可是很多的

get:

<script>
import axios from "axios"

export default {
    
    
    name: "MyComponent",
    mounted() {
    
     // 生命周期函数,组件已经渲染了
        axios({
    
    
            method: "get",
            url: ""
        }).then(res => {
    
     // 响应数据
            console.log(res.data)
        })
    }
}
</script>

更简单的写法:

axios.get("url").then(res => {
    
    
    console.log(res.data)
})

post:先要 npm 安装一下 querystring,他是为了把 data 请求对象转成 string,这样才能进行网络请求

<script>
import axios from "axios"
import querystring from "querystring"

export default {
    
    
    name: "MyComponent",
    mounted() {
    
     // 生命周期函数,组件已经渲染了
        axios({
    
    
            method: "post",
            url: "",
            data: querystring.stringify({
    
    
                username: "",
                password: "",
                verification_code: ""
            })
        }).then(res => {
    
     // 响应数据
            console.log(res.data)
        })
    }
}
</script>

也有更简单的写法:

axios.post("url", querystring.stringify({
    
    
    username: "",
    password: "",
    verification_code: ""
}))

局部和全局使用

上面例子是局部使用

如果需要全局使用,就需要在根组件中 import axios,然后挂载全局

import axios from axios

const app = createApp(App)
app.config.globalProperties.$axios = axios
app.mount('#app')

然后在子组件中就可以通过 this.$axios 拿到

网络请求的封装

可以在 src 下创建一个 util 文件,其中创建一个 request.js

import axios from "axios"
import querystring from "querystring"

// 网络请求公共配置
const instance = axios.create({
    
    
    timeout: 5000
})

// 发送数据之前拦截器,做一些发送之前的数据处理
instance.interceptors.request.use(
    config => {
    
    
        // 拦截成功做的处理
        if(config.methods == "post") {
    
    
            config.data = querystring.stringify(config.data)
        }
        return config;
    },
    error => {
    
    
        return Promise.reject(error)
    }
)

// 获取数据之前拦截器,响应时候拦截做一些处理
instance.interceptors.response.use(
    response => {
    
    
        // 拦截成功做的处理
        return response.status === 200 ? Promise.resolve(response) : Promise.reject(response)
    },
    error => {
    
    
        const {
    
     response } = error
    }
)

然后在 src 下粗行间 api 文件夹,存放 api 的 js

- src
    - api
        - base.js
        - index.js
    - components
        - MyComponent.vue

base.js 中有:

const base = {
    
    
    host: "http://xxxx.com",
    router: "/xxxxxx/yyyyyyy"
}
export default base;

index.js 中有

import axios from "../utils/request"
import axios from "../base"

const api = {
    
    
    getApi1() {
    
    
        return axios.get(path.host + path.router)
    }
}

在 MyComponent.vue 组件中可以 mounted() 函数中绑定这个请求

import api from "../api/index"

export default {
    
    
    name: "",
    props: {
    
    
        
    },
    mounted() {
    
    
        api.getApi1().then(
            res => {
    
    
                console.log(res.data)
            }
        )
    }
}

跨域解决方法

简介:
https://zhuanlan.zhihu.com/p/575259175
在这里插入图片描述

一般来说,跨域问题是在后端处理。因为浏览器对于同源策略的限制,前端无法直接访问不同域名下的资源。后端可以通过设置响应头,允许指定的域名访问资源,从而解决跨域问题。同时,后端也可以通过代理等方式,在服务端进行跨域请求

跨域问题的异常:
在这里插入图片描述

解决方式一般 2 中

  1. 后台解决 cors
  2. 前台解决 proxy

这里主要讲解前端解决
下面代码添加到 vue.config.js,添加之后一定要重启前端项目才能生效

devServer: {
    
    
    proxy: {
    
    
        '/api': {
    
    
            target: '产生跨域的地址',
            changeOrigin: true
        }
    }
}

路由配置

vue-router 项目中配置路由

vue router 是 vue.js 官方路由,通过他可以管理页面之间关系

- src
    - router
        - index.js   
    - views
    - components
    - main.js
    - App.vue

index.js 为路由的配置文件

import {
    
     CreateRouter, createWebHashHistroy } from "vue-router"
// 下面两个 import 是页面
import HomeView from ".../views/HomeView"
import AboutView from ".../views/AboutView"

// 创建路由
const routes = [
    {
    
    
        path: "/",
        component: HomeView
    },
    {
    
    
        path: "/about",
        component: AboutView
    }
]


const router = createRouter({
    
    
    history: createHashHistory(),
    routes
})

export default router

然后这个 src/router/index.js 在 main.js 中被引入,使用路由

import {
    
     createApp } from "vue"
import App from "App.vue"
import router from "router/index.js"

createApp(App).use(router).mount("#app")

然后我们实际在根组件 App.vue 中使用路由

<template>
    <router-link to="/">首页</router-link>
    <router-link to="/about">关于</router-link>
    <router-view></router-view>
</template>

本质:src/router 下的路由 js 文件被 main.js 所引入注册绑定根组件之后,再在根组件中就可以使用了

路由传递参数

router/index.js 中的路由

const routes = [
    {
    
    
        path: "/",
        component: HomeView
    },
    {
    
    
        path: "/about/:id", // 通过这种方式引入参数传递
        component: AboutView
    }
]

在 view 中的文件中可以

<p><router-link to="/about/123"></router-link></p>

在 router/AboutView 这个页面中可以通过如下方式取得 123 参数

{
   
   { $route.params.id }}

嵌套路由配置

场景比如主导航下又有很多子导航

文件结构:

- src
    - router
        - index.js
    - views
        - HomeViewSub
            - AboutMe.vue
            - AboutMe2.vue
        - HomeView.vue
        - AboutView.vue
    - components

router/index.js 中的路由。在 index.js 中可以看到一颗路有树

const routes = [
    {
    
    
        path: "/about",
        name: "about",
        component: () => import('../views/AboutView.vue'), // 延迟加载引入
        redirect: "/about/me", // 在 about 这个父级页面会重定向到它的第一个子页面
        children: [ // 二级导航路径不要加斜杠
            {
    
    
                path: "me",
                component: () => import("../views/HomeViewSub/AboutMe.vue")
            },
            {
    
    
                path: "me2",
                component: () => import("../views/HomeViewSub/AboutMe2.vue")
            }
        ]
    }
]

vuex 状态管理

vuex 就是更方便管理组件间数据交互,提供一种集中式管理

vuex 基本使用

安装

npm install --save vuex

目录

- src
    - store
        - index.js   

store/index.js

import {
    
     createStore } from "vuex"

// 帮忙管理组件和组件之间交互的数据
const store = createStore({
    
    
    // 所有数据放在这里
    state: {
    
    
        counter: 0 // 这个值可以被多个组件读取
    }
}) 

export default store

然后需要在 main.js 引入

import store from "./store"

createApp(App).use(store).mount("#app")

读取 counter 方式

{
    
    {
    
     $store.state.counter }}

getters 过滤数据

getter 对管理起来的数据进行过滤,这是在 store/index.js 中完成

import {
    
     createStore } from "vuex"

export default createStore({
    
    
    state: {
    
    
        counter: 0
    },
    // 过滤,设置过滤条件
    getters: {
    
    
        getCounter(state) {
    
    
            return state.counter > 0 ? state.counter : "数据异常"
        }
    }
})

读取方式

{
    
    {
    
     $store.getters.getCounter }}

mutations 改变数据

export default createStore({
    
    
    state: {
    
    
        counter: 0
    },
    // 过滤,设置过滤条件
    getters: {
    
    
        getCounter(state) {
    
    
            return state.counter > 0 ? state.counter : "数据异常"
        }
    }
    // 
    mutations: {
    
    
        addCounter(state) {
    
     // 此函数需要被调用
            state.counter++
        }
    }
})

调用方式:

this.$store.commit("addCounter")

另一种优雅调用方式

methods: {
    
    
    ...mapMutations(["addCounter"]),
    addClickHandle() {
    
    
        this.addCounter() // 这种写法更简单
    }
}

action 异步操作

store/index.js 中如下:

import {
    
     createStore } from "vuex"
import axios from "axios"

export default createStore({
    
    
    state: {
    
    
        
    },
    getters: {
    
    
        
    },
    mutations: {
    
    
        addCounter(state) {
    
    
            
        }
    },
    actions: {
    
    
        // 一个操作
        asyncAddCounter({
     
      commit }) {
    
    
            axios.get("http://xxx.com").then(res => {
    
    
                commit("addCounter", res.data) // 这里相当于把响应结果数据传给 mutations
            })
        }
    }
})

如果要取数的话:

this.$store.dispatch("asyncAddCounter")

更方便写法

methods: {
    
    
    ...mapActions(["asyncAddCounter"]),

    foo() {
    
    
        this.asyncAddCounter()
    }   
}

vue3 新特性

组合 API

ref 和 reactive 使用

组件中:

<template>
    <p>{
    
    {
    
     msg }}</p>
    
    <ul>
        <li v-for="(item,index) in names.list" :key="index"></li>
    </ul>
</template>

export default {
    
    
    name: "HelloWorld",
    // 组合式 api
    setup() {
    
    
        const msg = ref("消息") // 代替了 data
        const names = reactive({
    
    
            list: ["aa", "bb"]
        })
        return {
    
    
            msg
        }
    }
}

methods 函数

然后以前放在 methods 中的响应函数可以直接放在 setup 里头了

props 怎么用

export default {
    
    
    name: "HelloWorld",
    props: {
    
    
        msg: String
    }
    setup(props) {
    
    
        console.log(props.msg)
        return .............
    }
}

setup 中无 this 关键字

setup 中的生命周期函数

在这里插入图片描述

import {
    
     onMounted } from "vue"

export default {
    
    
    name: "",
    setup() {
    
    
        // 以前生命周期函数同一种只能存在一个,现在可以存在多个
        onMounted(() => {
    
    
            
        })
    }
}

更好 TS 支持

仍然建议 js,js 还是比 ts 多很多在开发时候

结合 Element Plus

vue2 对应 Element UI
vue3 对应 Element plus

安装

npm install --save element-plus

基本使用

完整引用(可能会导致文件变得很大)

import {
    
     createApp } from "vue"
import ElementPlus from "element-plus"
import "element-plus/dist/index.css"
import App from "App.vue"

const app = createApp(App)
app.use(ElementPlus).mount("#app")

按需引入,更常用的方式
但是你需要先进行插件安装

npm install -D unplugin-vue-components unplugin-auto-import

再修改 vue.config.js 配置文件(这个文件在 vue 项目中可以找到),具体修改方式可见网络
最后直接是用就行了

然后 element-plus 中的各种样式直接复制粘贴就可以直接使用了

图标使用

element-plus 图标是用需要额外说明,因为要显示它,除了你复制粘贴了,之前你还要 npm install 一下

npm install --save @element-plus/icons-vue

然后你需要在 src 下创建一个文件夹,比如叫 plugins,然后其中添加一个 icons.js 文件,这个文件里头怎么写可以网络下,写法比较固定
然后 main.js 中绑定

import elementIcon from "plugins/icons"
app.use(elementIcon)

猜你喜欢

转载自blog.csdn.net/abcnull/article/details/129645572