前端Web
- VUE
- Vue开发前的准备
- 模板语法
- 文本
- 原始HTML
- 属性Attribute
- 使用JavaScript表达式
- 列表渲染
- 事件处理
- 表单输入绑定
- 修饰符
- 组件基础
- 单文件组件
- 加载组件
- 组件的组织
- Props组件交互
- Prop类型
- 自定义事件组件交互
- Vue引入第三方
- Axios网络请求
- 安装
- 引入
- Axios网络请求封装
- 网络请求跨域解决方案
- Vue引入路由配置
- 在Vue中引入路由
- 路由传递参数
- 嵌套路由配置
- Vue状态管理(Vuex)
- 引入Vuex的步骤
- Vue状态管理核心(Vuex)
- Getter
- Mutation
- Action
- Vue3新特性
- ref或者reactive
- methods中定义的方法写在setup()
- setup()中使用props和context
- setup()中使用生命周期函数
- Provide / Inject
- Fragment
VUE
Vue开发前的准备
- 安装Vue工具
Vue CLI
:Vue.js 开发的标准工具,Vue CLI
是一个基于 Vue.js 进行快速开发的完整系统
npm insta11 -g @vue/cli
安装之后,你就可以在命令行中访问vue
命令。你可以通过简单运行vue
,看看是否展示出了一份所有可用命令的帮助信息,来验证它是否安装成功。
vue --version
- 创建一个项目
运行以下命令来创建一个新项目
vue create vue-demo
温馨提示
在控制台中,可以用上下按键调整选择项
在控制台中,可以用空格(spacebar)选择是否选中和取消选中
可以选择默认项目模板,或者选“手动选择特性”来选取需要的特性。
我们选择 Babel
和 Progressive Web App (PWA) Support
两个选项即可
温馨提示
不要选中Linter/Fomatter
以避免不必要的错误提示
Vue目前有两个主流大版本 vue2 和 vue3 ,选择 vue3 最新版本
配置放在哪里:In dedicated config files
专用配置文件或者In package.json
在package.json文件
将其保存为未来项目的预置?y代表保存,并添加名字,n不保存
-
项目创建成功如下提示信息
-
运行项目
- 第一步:进入项目根目录
cd vue-demo
- 第二步:运行
npm run serve
启动项目
- 第一步:进入项目根目录
-
安装Vue高亮插件
- VSCode中安装
vetur
或者volar
都可,前者针对Vue2版本,后者针对Vue3版本
- VSCode中安装
模板语法
文本
数据绑定最常见的形式就是使用“Mustache”(双大括号)语法的文本插值
<span>Message:{{ message }}</span>
一般配合JS中的data()
设置数据
export default {
name: 'HelloWorld',
data(){
return {
message:"文本"
}
}
}
原始HTML
双大括号会将数据解释为普通文本,而非HTML代码。为了输出真正的HTMl,需要使用v-html
指令
<div>{{ rawHtml }}</div>
<div v-html="rawHtml"></div>
data(){
return {
rawHtml:"<a href='https://www.baidu.com'>百度</a>"
}
}
属性Attribute
Mustache语法不能在HTML属性中使用,然而可以使用v-bind
指令
<div v-bind:id="dynamicID"></div>
data(){
return {
dynamicID:10001
}
}
温馨提示
v-bind
可以简写成:
使用JavaScript表达式
Vue.js提供了完整的JavaScript表达式支持
{{ number + 1 }}
{{ ok ? 'Yes' : 'No' }}
{{ message.split('').reverse().join('') }}
这些表达式会在当前活动实例的数据作用域下作为JavaScript被解析,有个限制就是,每个绑定都只能包含单个表达式,所以下面的例子都不会生效。
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流程控制也不会生效,需要使用三元表达式 -->
{{ if (ok) { return message } }}
列表渲染
- 用
v-for
把一个数组映射为一组元素
我们可以用v-for
指令基于一个数组来渲染一个列表。v-for
指令需要使用item in items
形式的特殊语法,其中items
是源数据数组,而item
则是被迭代的数组元素的别名
<ul>
<li v-for="item in newsList">
{{item.title}}
</li>
</ul>
data(){
return {
newsList:[
{
id : 1001,
title : "今日新闻1"
},
{
id : 1002,
title : "今日新闻2"
},
{
id : 1003,
title : "今日新闻3"
},
]
}
}
- 维护状态
当Vue正在更新使用v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,需要为每一项提供一个唯一的key
attribute:
<li v-for="(item,index) in newsList" :key="item.id | index">
事件处理
- 监听事件
我们可以使用v-on
指令(通常缩写为@
符号)来监听DOM事件,并在触发事件时执行一些JavaScript。
用法为v-on:click="methodName"
或使用快捷方式@click="methodName"
- 事件处理方法
许多事件处理逻辑会更为复杂,所以直接把JavaScript代码直接写在v-on
指令中时不可行的,因此v-on
指令还可以接收一个需要调用的方法名称。
<button @click="clickHandle">按钮</button>
<p>{{ message }}</p>
data(){
return {
message:'消息'
}
},
methods:{
clickHandle(event){
//在事件中,读取data中的属性,需要通过this.属性
this.message = "xxxx";
// event 是原生的DOM event
console.log(event);
event.target.innerHTML = "点击之后";
}
}
- 内联处理器中的方法
这是官方的翻译称呼,其实可以称之为“事件传递参数”
<button @click="say('hi')">say hi</button>
<button @click="say('hello')">say hello</button>
methods:{
say(data){
console.log(data);
}
}
表单输入绑定
可以使用v-model
指令在表单<input>
、<textarea>
以及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
v-model
负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
<input type="text" v-model="username">
<p>{{ username }}</p>
data(){
return {
username:""
}
}
修饰符
-
.lazy
- 在默认情况下,
v-model
在每次input
事件触发后将输入框的值与数据进行同步。可以添加.lazy
修饰符,从而转为在change
(失去焦点/回车)事件之后同步
- 在默认情况下,
-
.trim
- 如果要自动过滤用户输入的首尾空格,可以使用
.trim
修饰符
- 如果要自动过滤用户输入的首尾空格,可以使用
组件基础
单文件组件
Vue单文件组件(又名*.vue
文件,缩写为SFC)是一种特殊的文件格式,它允许将Vue组件的模板、逻辑与样式封装在单个文件中
<template>
<div></div>
</template>
<script>
export default{
name:"MyComponent",
}
</script>
<!-- scoped:如果在style中添加此属性,戴白哦当前样式只在当前组件中生效 -->
<style scoped>
</style>
加载组件
- 第一步:引入组件
import MyComponent from './components/MyComponent.vue'
- 第二步:挂载组件
components:{MyComponent}
- 第三步:显示组件
<MyComponent />
或<my-component />
组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织
Props组件交互
组件与组件之间是需要存在交互的,否则完全没关系,组件的意义就很小了
Prop
是你可以在组件上注册的一些自定义attribute
- 父组件
<MyComponent :title="title" :age="age"/>
data(){
return{
title:"这是一个标题",
age:20
}
}
- 子组件
<template>
<div>
<p>{{ title }}</p>
<p>age={{ age }}</p>
</div>
</template>
<script>
export default{
name:"MyComponent",
props:{
title:{
type:String,
default:""
},
age:{
type:Number,
default:0
}
}
}
</script>
<style scoped>
</style>
Prop类型
Prop传递参数其实是没有类型限制的
props:{
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
}
温馨提示
数据类型为数组或者对象的时候,默认值是需要返回工厂模式
names:{
type:Array,
//数组和对象必须使用函数进行返回
default:function(){
return []
}
}
自定义事件组件交互
自定义事件可以在组件中反向传递数据,prop
可以将数据从父组件传递到子组件,可以利用自定义事件$emit
实现反向传递
- 子组件
<template>
<div>
<h3>自定义事件</h3>
<button @click="sendClickHandle">传递数据</button>
</div>
</template>
<script>
export default{
name:"MyComponent",
data(){
return{
message:"MyComponent"
}
},
methods:{
sendClickHandle(){
//参数1:字符串:理论上是随意的,但是需要具有意义
//参数2:传递的数据
this.$emit("onEvent",this.message)
}
}
}
</script>
<style scoped>
</style>
- 父组件
<MyComponent @onEvent="getDataHandle"/>
methods:{
getDataHandle(data){
console.log(data);
this.message = data;
}
}
Vue引入第三方
Swiper
- 开源、免费、强大的触摸滑动插件
- 是纯JavaScript打造的滑动特效插件,面向手机、平板电脑等移动终端
- 能实现触屏焦点图、触屏Tab切换、触屏轮播图切换等常用效果
温馨提示
官方文档:https://swiperjs.com/vue
安装指定版本:npm install --save swiper@8.1.6
Axios网络请求
Axios是一个基于promise的网络请求库
安装
Axios的应用是需要单独安装的
npm install --save axios
引入
- 组件中引入:
import axios from "axios"
- 全局引用:
import axios from "axios"
const app = creatApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app')
//在组件中调用
this.$axios
Axios网络请求封装
在日常应用过程中,一个项目中的网络请求会很多,此时一般采取的方案是将网络请求封装起来
在src
目录下创建文件夹utils
,并创建文件request.js
,用来存储网络请求对象axios
import axios from "axios"
import querystring from "querystring"
const errorHandle = (status, info) =>{
switch(status){
case 400:
console.log("语义有误");
break;
case 401:
console.log("服务器认证失败");
break;
case 403:
console.log("服务器拒绝访问");
break;
case 404:
console.log("地址错误");
break;
case 500:
console.log("服务器遇到意外");
break;
case 502:
console.log("服务器无响应");
break;
default:
console.log(info);
break;
}
}
const instance = axios.create({
//网络请求的公共配置
timeout:5000
})
// 拦截器最常用
// 发送数据之前
instance.interceptors.request.use(
config =>{
// 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;
// 错误的处理才是最需要关注的
errorHandle(response.status,response.info)
}
)
export default instance;
在src
目录下创建文件夹api,并创建文件index
和path
分别用来存放网络请求方法和请求路径
网络请求跨域解决方案
JS采取的是同源策略
- 同源策略是浏览器的一项安全策略,浏览器只允许js代码请求和当前所在服务器域名,端口,协议相同的数据接口上的数据,这就是同源策略
- 也就是说,当协议,域名,端口任意一个不同时,都会产生跨域问题
目前主流的跨域解决方案有两种:
- 后台解决:cors
- 前台解决:proxy
在vue.config.js
中:
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer:{
proxy:{
'/api':{
target: '<url>',//产生跨域的地址
changeOrigin: true
}
}
}
})
温馨提示
在解决完跨域配置之后,需要重启服务器
Vue引入路由配置
在Vue中,可以通过vue-router
路由管理页面之间的关系
Vue Router是Vue.js的官方路由,它与Vue.js核心深度集成,让用Vue.js构建单页应用变得轻而易举
在Vue中引入路由
- 第一步:安装路由
npm install --save vue-router
- 第二步:配置独立的路由文件
import { createRouter, createWebHashHistory } from "vue-router"
import HomeView from "@/views/HomeView.vue"
import About from "@/views/About.vue"
// 配置信息中需要页面的相关配置
const routes = [
{
path:"/",
component:HomeView
},
{
path:"/about",
component:About
}
]
const router = createRouter({
/**
* createWebHashHistory
* home: http://localhost:8080/#/
* about: http://localhost:8080/#/about
*
* 原理:a标签锚点链接
*/
/**
* createWebHistory
* home: http://localhost:8080/
* about: http://localhost:8080/about
* 此种方式需要后台配合做重定向,否则会出现404问题
* 原理: H5 pushState()
*/
history: createWebHashHistory(),
routes
})
export default router;
- 第三步:引入路由到项目
// main.js
import router from './router'
app.use(router)
- 第四步:指定路由显示入口
<router-view />
- 第五步:指定路由跳转
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
路由传递参数
页面跳转过程中,是可以携带参数的
- 第一步:在路由配置中指定参数的
key
{
path:"/list/:name",
name:"list",
component:() => import("../views/ListView.vue")
}
- 第二步:在跳转过程中携带参数
<router-link to="/list/xxx"></router-link>
- 第三步:在详情页面当中读取路由携带的参数
<p>{{ $route.params.name }}</p>
嵌套路由配置
路由嵌套是非常常见的需求
- 第一步:创建子路由要加载显示的页面
- 第二步:在路由配置文件中添加子路由配置
{
path:"/list",
name:"list",
redirect:"/list/list1",
component:() => import("../views/ListView.vue"),
children:[
{
// 二级路径不要加 /
path:"list1",
component:() => import("...")
},
{
path:"list2",
component:() => import("...")
}
]
}
- 第三步:指定子路由显示位置
<router-view></router-view>
- 第四步:添加子路由跳转链接
<router-link>
- 第五步:重定向配置
redirect:"/list/list1"
Vue状态管理(Vuex)
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式+库。它采用集中式存储管理应用的所有组件的状态并以相应的规则保证状态以一种可预测的方式发生变化。
简单来说,状态管理可以理解成为了更方便的管理组件之间的数据交互,提供了一个集中式的管理方案,任何组件都可以按照指定的方式进行读取和改变数据。
引入Vuex的步骤
- 第一步:安装Vuex
npm install --save vuex
- 第二步:配置Vuex文件
import { createStore } from "vuex"
// Vuex的核心作用就是 管理组件之间的状态
export default createStore({
// 所有的状态都放在这里(数据)
state:{
counter : 0
}
})
- 第三步:在主文件中引入Vuex
import store from "./store"
app.use(store)
- 第四步:在组件中读取状态
<!-- 第一种方式 -->
<p>{{ $store.state.counter }}</p>
<!-- 第二种方式 -->
<p>{{ counter }}</p>
import { mapState } from "vuex"
// 专门读取Vuex的数据
computed:{
...mapState(["counter"])
}
Vue状态管理核心(Vuex)
Getter
对Vuex中的数据进行过滤
import { createStore } from "vuex"
export default createStore({
state:{
counter : 0
},
getters:{
getCounter(state){
return state.counter > 0 ? state.counter : "counter数据异常"
}
}
})
读取数据
// 第一种
<p>{{ $store.getters.getCounter }}</p>
// 第二种
<p>{{ getCounter }}</p>
import { mapGetters } from "vuex"
computed:{
...mapGetters(["getCounter"])
}
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
import { createStore } from "vuex"
export default createStore({
state:{
counter : 0
},
getters:{
getCounter(state){
return state.counter > 0 ? state.counter : "counter数据异常"
}
},
mutations:{
addCounter(state, num){
state.counter += num
}
}
})
调用事件
// 第一种
methods:{
addClickHandle(){
// 固定调用方式
this.$store.commit("addCounter", 15)
}
}
// 第二种
import { mapMutations } from "vuex"
methods:{
...mapMutation(["addCounter"]),
addClickHandle(){
this.addCounter(15)
}
}
Action
Action类似于Mutation,不同在于:
- Action提交的是mutation,而不是直接改变状态
- Action可以包含任意异步操作
// actions 为异步操作所准备的
actions:{
asyncAddCount({ commit }){
// 假设数据来源于网络请求
axios.get("...").then(res => {
// 使用方式
commit("addCounter", res.data[0])
})
}
}
调用事件
// 第一种
methods:{
addAsyncClickHandle(){
// 固定调用方式
this.$store.dispatch("asyncAddCount")
}
}
// 第二种
import { mapActions} from "vuex"
methods:{
...mapActions(["asyncAddCount"]),
addClickHandle(){
this.asyncAddCount();
}
}
Vue3新特性
- 六大亮点
- Performance:性能更比Vue 2.0强。
- Tree shaking support:可以将无用模块“剪辑”,仅打包需要的。
- Composition APl: 组合API
- Fragment, Teleport, Suspense:“碎片”,Teleport即Protal传送门,“悬念”
- Better TypeScript support:更优秀的Ts支持
- Custom Renderer APl:暴露了自定义渲染API
ref或者reactive
在2.x中,通过组件data的方法来定义一些当前组件的数据
data(){
return {
name: "xxx",
list: [],
}
}
在3.x中,通过ref或者reactive创建响应式对象
import { ref,reactive } from "vue"
export default {
name: 'ListView',
// 组合式API
setup(){
// ref
const message = ref("这是一条message");
// reactive
const names = reactive({
list:['x1','x2','x3']
})
return{
message,
names
}
}
}
methods中定义的方法写在setup()
在2.x中methods来定义一些当前组件中的内部方法
methods:{
fun(){}
}
在3.x中直接在setup方法中定义并return
setup(){
const fun = ()=>{
// some code
}
return{
fun
}
}
setup()中使用props和context
在2.x中,组件的方法中可以通过this获取到当前组件的实例,并执行data变量的修改,方法的调用,组件的通信等等,但是在3.x中,setup()在beforeCreate和created时机就已调用,无法使用和2.x一样的this,但是可以通过接收setup(props,ctx)的方法,获取到当前组件的实例和props
export default {
props:{
name:String,
},
setup(props,ctx){
console.log(props.name)
// setup中没有this关键字
ctx.emit('event')
},
}
setup()中使用生命周期函数
可以通过在生命周期钩子前面加上“on”来访问组件的生命周期钩子。
import { onMounted } from "vue"
export default{
setup(){
// 比2.x有优势,以前同一个生命周期函数只能存在一个,现在可以存在多个
onMounted(() =>{
// some code 1
}),
onMounted(() =>{
// some code 2
})
}
}
Provide / Inject
provide()
和inject()
可以实现嵌套组件之间的数据传递。- 这两个函数只能在
setup()
函数中使用。 - 父级组件中使用
provide()
函数向下传递数据。 - 子级组件中使用
inject()
获取上层传递过来的数据。 - 不限层级
// 父组件
import { provide } from "vue"
setup(){
provide("customVal", "父组件向子组件传递的值");
}
// 子组件
import { inject } from "vue"
setup(){
const customVal = inject("customVal");
return{
customVal
}
}
Fragment
- 不再限于模板中的单个根节点