文章目录
- 简介
- vue3 学习
- 安装
- 项目结构
- 基础知识
- 模版语法
- {{}}
- v-html
- v-bind
- 渲染展示
- v-if 和 v-else
- v-show
- v-for 和 item in xxx
- 事件处理
- 如何监听事件 v-on: 或者 @
- 简单例子
- 触发函数
- 函数带参数
- 表单数据绑定 v-model
- 简单例子
- 修饰符
- .lazy
- .trim
- vue 的组件
- 单模版文件 SFC
- 组件之间数据交互
- prop 父组件到子组件传递
- $emit 反向传递:自定义事件
- 组件生命周期
- vue 引入第三方
- 网络请求
- _Axios 网络请求
- 安装介绍
- get post 使用
- 局部和全局使用
- 网络请求的封装
- 跨域解决方法
- 路由配置
- vue-router 项目中配置路由
- 路由传递参数
- 嵌套路由配置
- vuex 状态管理
- vuex 基本使用
- getters 过滤数据
- mutations 改变数据
- action 异步操作
- vue3 新特性
- 组合 API
- ref 和 reactive 使用
- methods 函数
- props 怎么用
- setup 中的生命周期函数
- 更好 TS 支持
- 结合 Element Plus
- 安装
- 基本使用
- 图标使用
简介
最流行的前端框架之一,本篇博文期望快速阅览 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 server
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 的基础知识才能进行如下学习
应用实例必须挂载到 dom 元素或者 css 选择器之后才能渲染出来
<div ></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:></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 中
- 后台解决 cors
- 前台解决 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)