官网链接:https://cn.vuejs.org/
如果出现普通用户无法新建项目,必须要管理员身份新建,那么可以在nodejs的安装路径设置安全选项,提高普通用户的权限。
具体方法参考:
https://blog.csdn.net/weixin_43174650/article/details/121865934
0 基本标签
标签 | 功能 |
---|---|
template | 模板 |
div | 块 |
h1~h6 | 标题 |
p | 文字 |
header | 头部 |
main | 主体 |
button | 按钮 |
img | 图片 |
canvas | 画布 |
ul | 无序列表 |
ol | 有序列表 |
li | 列表项目,用在ul和ol中 |
input | 输入文本框 |
textarea | 文本区域 |
select | 下拉选择框 |
1 模板语法
首先来看一下项目的结构,src下存放了需要我们关注的文件。
- assets下包含了静态资源,包括图片和公共的css文件。
- components下存放vue的组件。
- App.vue是根组件。
- main.js是主入口文件。
1.2 文本
数据绑定,形成能改变的动态文字。使用双花括号{{ }}
插入文字。
<template>
<p>{{ message }}</p>
</template>
<script>
export default {
data() {
return {
message:"学习Vue"
}
}
}
</script>
1.3 链接
双花括号会将数据解释为普通文本,而不是HTML代码。为了输出真正的HTML代码,需要使用v-html
代码。
<template>
<div>{{rawHtml}}</div>
<div v-html="rawHtml"></div>
</template>
<script>
export default {
data() {
return {
rawHtml:"<a href='https://www.baidu.com'>百度搜索</a>"
}
}
}
</script>
1.4 属性(attribute)
位于尖角括号内的<*** class="text" width="100px" height="200px"
>,为标签的属性。
要让属性(class或id)成为能按照js改变的属性,需要使用v-bind
指令。
<template>
<div v-bind:id="dynamicID"></div>
</template>
<script>
export default{
data(){
return{
dynamicID:10001,
}
}
</script>
注意:v-bind:
可以简写为:
。
1.5 表达式
只能单行表达式!
赋值语句不可以,if表达式也不可以。
<template>
<p>输入:{{ num }},输出:{{ num + 10 }}</p>
<p>{{ flag ? "真":"假" }}</p>
</template>
<script>
export default{
data(){
return{
flag : true,
num:10,
}
}
}
</script>
2 渲染方式
2.1 条件渲染:v-if和v-else
使用变量flag的true和false来控制是否渲染此对象。v-if后面可以紧跟着v-else来表达另外一种选择时的渲染对象。
<template>
<p v-if="flag">Hello World!</p>
<p v-else>I am Jonathan!</p>
</template>
<script>
export default{
data(){
return{
flag : true,
}
}
}
</script>
2.2 v-show
只能控制一个,要么显示要么不显示。
<template>
<p v-show="flag">Hello World!</p>
</template>
<script>
export default{
data(){
return{
flag : true,
}
}
}
</script>
两者的区别:
v-if是真正的条件渲染,没有被渲染的会背销毁,重新渲染的会重建。是惰性的,有更高的切换开销。
v-show只是显示不显示的问题,所有都被渲染,有最高的初始渲染那开销。
2.3 列表渲染:v-for
把一个数组映射为一组元素,然后渲染。
维护模式,添加:key="id"
确定一个唯一的标识,以便后期渲染时,只渲染新增的元素,以节约渲染开销。
<template>
<ul>
<li v-for="news in newslist" :key="news.id">
{{ news.title }}
</li>
</ul>
</template>
<script>
export default{
data(){
return{
newslist:[
{
id:1001,
title:"今日新闻1"
},
{
id:1002,
title:"今日新闻2"
},
{
id:1003,
title:"今日新闻3"
},
{
id:1004,
title:"今日新闻4"
},
}
}
}
</script>
3 事件处理
3.1 监听事件:v-on或@
使用v-on
或者@
来监听DOM事件,并在触发事件时执行一些Javascript。用法为:v-on:lick="methodName"
或者使用快捷方式@click="methodName"
。
3.1.1简单事件处理
直接在click事件中添加变量自增。
<template>
<button @click="counter += 1">点击增加counter值:{{ counter }}</button>
</template>
<script>
export default{
data(){
return{
counter:0,
}
}
}
</script>
3.1.2 事件处理方法
如果事件处理逻辑较为复杂,则v-on接收一个需要调用的方法(函数)名称。
<template>
<button @click="clickHandle">点击弹出对话框</button>
</template>
<script>
export default{
methods:{
clickHandle(){
alert("只因你太美!");
},
}
}
</script>
3.1.3 获取、修改页面信息
获取页面中的数据需要使用this.
来指定对象。
event时间内有较多参数,也可以修改。
<template>
<p>{{ message }}</p>
<button @click="changeText">撤回消息</button>
</template>
<script>
export default{
data(){
return{
message:"消息通知",
}
},
methods:{
changeText(event){
// 在时间中,读取data中的属性,是需要通过this.属性
this.message = "消息被撤回了。";
console.log(event); //event为原生DOM event
event.target.innerText = "无新消息";
},
}
}
</script>
3.1.4 事件传递参数
click可以传递参数到js内。
1、点击按钮传递参数:
<template>
<p>----------------</p>
<button @click="sendParam('hi')">send hi</button>
<button @click="sendParam('bye')">send bye</button>
</template>
<script>
export default{
methods:{
sendParam(data){
console.log(data);
},
}
}
</script>
点击按钮可以发现参数传递成功,调试输出了对应文本。
2、点击文本/列表传递参数
<template>
<ul>
<li @click="clickItemHandler(name)"
v-for="(name,index) in namelist"
:key="index">{{ name }}</li>
</ul>
</template>
<script>
export default{
data(){
return{
namelist:['owen','john','frank'],
}
},
methods:{
clickItemHandler(name_param){
console.log(name_param)
},
}
}
</script>
点击无序列表的各个项目,可以发现下方调试面板输出了对应的name。
4 表单输入绑定
4.1 数据绑定v-model
可以使用v-model
指令在表单<input>
、<textarea>
、<select>
元素上穿件双向数据绑定,该指令会根据控件类型自动选取正确的方法来更新元素。
<input>
为输入文本框,只有左半个标签,无</input>
。
<template>
<input type="text" v-model="username">
<input type="text" v-model="password">
<button @click="logIn">登录</button>
</template>
<script>
export default{
data(){
return{
username:'',
password:'',
}
},
methods:{
logIn(){
console.log('username:' + this.username + ' ,password:' + this.password);
console.log();
},
}
}
</script>
输入用户名和密码,点击登录,可以看到调试界面出现对应数据。
4.2 修饰符
4.2.1 lazy
在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步。如果添加lazy
修饰符,将会转化为在change
事件之后进行同步(比如输入回车、鼠标点击其他位置)。
<template>
<input type="text" v-model.lazy="username">
<input type="text" v-model="password">
<p>{{ username }},{{ password }}</p>
</template>
<script>
export default{
data(){
return{
username:'',
password:'',
}
},
}
</script>
输入两个文本框,可以发现下方文字不同的输出效果。
4.2.2 trim
自动过滤用户输入的首尾空白字符。
<template>
<input type="text" v-model.trim="textBox">
<p>{{ textBox }}</p>
</template>
<script>
export default{
data(){
return{
textBox:'',
}
},
}
</script>
前后的空格都被过滤,中间的空格没有过滤。
5 组件基础
5.1 单文件组件
Vue单文件组件,文件后缀是.vue,是一种特殊的文件格式,运行将Vue组件的模板、逻辑与样式封装在单个文件中。
template
:模板部分,相当于htmlscript
:逻辑部分,相当于js。规范编程的话需要在export default
内指定组件的name
。style
:样式部分,相当于css。如果添加scoped
,则表示当前样式只在该组件内部生效,外部不生效。
//文件名:MyComponent.vue
<template>
<h1>单文件组件</h1>
</template>
<script>
export default{
name:"MyComponent"
}
</script>
<style scoped>
h1{
color:red;
}
</style>
5.2 加载组件
(1)<script>
内引入组件:import MyComponent from './components/MyComponent.vue'
(2)<script>
内挂载组件:components: { MyComponent }
(3)<template>
内显示组件:<MyComponent />
或<my-component />
注意:<script setup> </script>
可以在<template>
之前,如果这样的话,就不用第二步挂载组件了,但引入其他组件时,export default
会报错。
在根组件App.vue内引用MyComponent.vue:
<script setup>
import HelloWorld from './components/HelloWorld.vue';
import TheWelcome from './components/TheWelcome.vue';
</script>
<template>
<header>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<MyComponent /> //此处显示组件
<HelloWorld />
</div>
</header>
<main>
<TheWelcome />
</main>
</template>
<script> // 此处引入组件,挂载组件
import MyComponent from './components/MyComponent.vue';
export default{
components:{MyComponent}
}
</script>
5.3 组件组织关系
通常一个应用会以一棵嵌套的组件树的形式来组织。
6 样式style
<template class="styleName"> </template>
中class
能够引用样式。
在<style>
中能够使用的样式种类:
名称 | 功能 |
---|---|
border | 设置边框(线性、宽度、颜色、圆角) |
width | 宽度 |
height | 高度 |
color | 字体颜色 |
background | 背景(颜色、图片、位置) |
font | 字型(字体、字号、加粗、斜体) |
text | 文本(居中、行高、溢出内容处理) |
margin | 外边距(上下左右) |
padding | 内边距 |
参考网址:https://www.jianshu.com/p/ee736030239b
7 Props的组件交互
组件之间的数据存在交互,有传递数据的方式。
7.1 正向数据传递
prop是可以在组件上注册一些自定义的属性(attribute)。可以从父组件传递到子组件。
prop可以传递的类型:
名称 | Type | default |
---|---|---|
字符串 | String | “” |
数字 | Number | 0,任何数字 |
布尔类型 | Boolean | true或者false |
数组 | Array | function() { return [] } |
对象 | Object | function() { return [] } |
函数 | Function |
数组和对象必须使用函数进行返回
- 传出内容的模板需要:
<MyComponent :param1_in="param1" :param2_in="param2"/>
- 传入的模板需要:
props:{
param1_in:{
type:String,
default:"",
},
param2_in:{
type:Number,
default:0,
}
}
完整交互过程如下:
//App.vue
<template>
<img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" />
<div class="wrapper">
<MyComponent :titleMC="title" :yearMC="year" :monthMC="month"/> //此处传入的是内容
<HelloWorld/>
<TheWelcome />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue';
import TheWelcome from './components/TheWelcome.vue';
import MyComponent from './components/MyComponent.vue';
export default{
name:'App',
data(){
return{
title:'我是一个标题', //此处定义传入数据
year:2023,
}
},
components:{
HelloWorld,
TheWelcome,
MyComponent
}
}
</script>
注意:
- 不加
:
传递的是固定的字符串,<MyComponent title="title"/>
。 - 加
:
传递的是内容<MyComponent :title="title"/>
。
//MyComponent.vue
<template>
<h1>单文件组件</h1>
<h3>prop传递数据</h3>
<p>{{ titleMC }}</p> //传入数据显示
<p>{{ yearMC }}</p>
<ul>
<li v-for="(item,index) in monthMC" :key="index">{{ item }}</li>
</ul>
</template>
<script>
export default{
name:"MyComponent",
props:{ //props固定格式
titleMC:{ //传入的变量名
type:String, //传入的数据类型
default:"未传入值的情况下的默认值", //默认值
},
yearMC:{
type:Number,
default:1997,
},
monthMC:{
type:Array,
default:function(){
return []
}
}
},
}
</script>
7.2 自定义事件组件交互——反向传递数据
自定义事件可以在组件中反向传递数据,用$emit
实现。
在子组件和父组件中需要构建两个methods:
- 子组件在触发事件后的函数内使用
this.$emit
传递eventName
和需要传递的数据。 - 父组件监听
eventName
,并接入一个新函数来处理这个事件。
子组件示例:
// MyComponent.vue
<template>
<button @click="sendClickHandle">点击反向传递</button>
</template>
<script>
export default{
name:"MyComponent",
data(){
return{
message:"我是MyComponent数据",
}
},
methods:{
sendClickHandle(){
// 参数1:字符串,自定义事件,参数2:传递的数据
this.$emit("onEvent",this.message);
console.log("mycomponent.vue下 " + this.message);
}
}
}
</script>
父组件示例:
// App.vue
<template>
<MyComponent @onEvent="getDataHandle"/>
<p>{{ recvData }}</p>
</template>
<script>
import MyComponent from './components/MyComponent.vue';
export default{
name:'App',
data(){
return{
recvData:'null',
}
},
components:{
MyComponent
},
methods:{
getDataHandle(data){
this.recvData = data;
console.log("app.vue下 " + this.recvData);
}
}
}
</script>
注意:<script>
内给变量赋值或调用需要使用this.
,<template>
内不需要使用this.
。
8 Vue状态管理(Vuex)
上一节的数据传递方式,支持父子组件之间的数据传递,如果多个组件之间不存在直接的关系,则采用vuex库来集中式存储管理应用的所有组件的状态。状态管理更方便的管理组件之间的数据交互,任何组件都可以按照指定的方法读取和改变数据。
包括:State(存储状态)、Getter(获取、计算、过滤)、Mutation(修改)、Action(异步操作)。
8.1 简单数据传递 State
8.1.1安装Vuex
选择文件夹位置,终端输入:
npm install --save vuex
8.1.2 配置Vuex文件
新建文件夹src/store
,新建文件index.js
,代码如下:
//index.js
import { createStore } from "vuex";
// vuex的作用就是帮我们管理组件之间的状态的
export default createStore({
// 所有的状态/数据都放在这里
state: {
counter:2024,
name:'vuexSolution',
}
})
8.1.3主文件中引入Vuex
进入/src/main.js
文件,引入:
//main.js
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
import store from './store/index.js'
const app = createApp(App);
app.use(router);
app.use(store);
app.mount('#app');
也可以使用:createApp(App).use(router).use(store).mount('#app')
来设置。
8.1.4数据读取
1、方法1:普通读取方式
在.vue
文件的template中使用$store.state.xxxxx
来读取对应名称的数据,script中使用this.$store.state.xxxxx
来读取数据代码如下:
//App.vue
<template>
<p>counter = {{ $store.state.counter }}</p>
<p>name = {{ $store.state.name }}</p>
<button @click="vuexParamCheck">alert</button>
</template>
<script>
export default{
methods:{
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.$store.state.name);
}
}
}
</script>
2、方法2:mapState快捷读取方式
使用vuex内的mapState
方式,能够快捷读取数据。放入computed
内,...
为扩展运算符。
import { mapState } from 'vuex';
//计算属性,专门来读取vuex的数据
coumputed:{
...mapState(["counter"])
}
示例代码如下:
// App.vue
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
</template>
<script>
import { mapState } from "vuex";
export default{
methods:{
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
}
},
computed:{
...mapState(["name"])
}
}
</script>
界面如下:
点击按钮后可以看到调试界面如下:
8.2 获取过滤计算 Getter
能够获取state内的数据,并加以过滤/计算后再输出。
8.2.1 配置vuex文件
在/src/store/index.js
中设置getters
,新建函数getCounter()
,代码如下:
//index.js
import { createStore } from "vuex";
// vuex的作用就是帮我们管理组件之间的状态的
export default createStore({
// 所有的状态/数据都放在这里
state: {
counter:2024,
name:'vuexSolution',
},
getters: {
getCounter(state){
return state.counter > 2024 ? state.counter:"还没到2024年"
},
getName(state){
return state.name == "vuex" ? state.name: "name error"
}
}
})
8.2.2 主文件中引入Vuex
同8.1.3,略。
8.2.3 处理过的数据读取
1、方法1:普通读取方法
在.vue
文件内使用$store.getters.函数名
来引用经过过滤/计算的数据。
//App.vue
<template>
<p>Getter:{{ getName }}</p>
</template>
2、方法2:mapGetters快捷读取方法(类似于8.1.4方法2)
<template>
<p>Getter:{{ getName }}</p>
</template>
<script>
import { mapGetters } from 'vuex';
export default{
//计算属性,专门来读取vuex的数据
coumputed:{
...mapGetters(["getName"])
}
}
</script>
完整代码:
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
<p>Getter:{{ $store.getters.getCounter }}</p>
<p>Getter:{{ getName }}</p>
</template>
<script>
import { mapState,mapGetters } from "vuex";
export default{
methods:{
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
}
},
computed:{
...mapState(["name"]),
...mapGetters(["getName"])
}
}
</script>
8.3 修改参数 Mutation
更改Vuex的store中的状态的唯一方法就是提交mutation。Mutation都有一个字符串的事件类型(type)和一个回调函数(handler),这个回调函数就是我们实际进行状态更改的地方,并且他会接受state作为第一个参数。
8.3.1 配置vuex文件
在src/store/index.js
中添加mutations方法:
//index.js
import { createStore } from "vuex";
// vuex的作用就是帮我们管理组件之间的状态的
export default createStore({
// 所有的状态/数据都放在这里
state: {
counter:2024,
name:'vuexSolution',
},
getters: {
getCounter(state){
return state.counter > 2024 ? state.counter:"counter数据异常"
},
getName(state){
return state.name == "vuex" ? state.name: "name error"
}
},
mutations:{
addCounter(state){
state.counter ++;
}
}
})
8.3.2 主文件中引入Vuex
同8.1.3,略。
8.3.3 调用数据修改函数
在/src/App.vue
中添加按钮及其事件addClickHandle
,在事件中添加mutation的固定调用方式this.$store.commit("addCounter")
。
代码修改如下:
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
<p>Getter:{{ $store.getters.getCounter }}</p>
<p>Getter:{{ getName }}</p>
<button @click="addClickHandle">counter加1</button>
</template>
<script>
import { mapState,mapGetters } from "vuex";
export default{
methods:{
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
},
addClickHandle(){
this.$store.commit("addCounter"); // 固定调用方式
}
},
computed:{
...mapState(["name"]),
...mapGetters(["getName"])
}
}
</script>
点击按钮可以发现前面两个关联counter的文本数据显示都发生了变化。
8.3.4 数据输入反馈
当我们在页面输入数据,对store中state的数据产生修改时,需要代码进行如下修改。
以下是src/store/index.js
的代码:
//index.js
import { createStore } from "vuex";
export default createStore({
mutations:{
addCounter(state, num){
state.counter = state.counter + num;
}
}
})
1、方法1:this.$store.commit("xxxxxxx",this.inputNumber)
参考第4节的v-model数据绑定,添加输入文本框以便进行数据传入,以下是src/App.vue
的代码:
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
<p>Getter:{{ $store.getters.getCounter }}</p>
<p>Getter:{{ getName }}</p>
<input type="number" v-model="inputNumber">
<button @click="addClickHandle">Add</button>
</template>
<script>
import { mapState,mapGetters } from "vuex";
export default{
data(){
return{
inputNumber:0,
}
},
methods:{
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
},
addClickHandle(){
this.$store.commit("addCounter",this.inputNumber);
}
},
computed:{
...mapState(["name"]),
...mapGetters(["getName"])
}
}
</script>
2、方法2:使用mapMutations
,这里要注意的是,...mapMutations(["xxxxxxxx"]),
需要放在methods
内,而不是computed
内!
代码如下:
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
<p>Getter:{{ $store.getters.getCounter }}</p>
<p>Getter:{{ getName }}</p>
<input type="number" v-model="inputNumber">
<button @click="addClickHandle">Add</button>
</template>
<script>
import { mapState,mapGetters,mapMutations } from "vuex";
export default{
data(){
return{
inputNumber:0,
}
},
methods:{
...mapMutations(["addCounter"]), // 注意!!!
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
},
addClickHandle(){
// 调用方式2
this.addCounter(this.inputNumber);
},
},
computed:{
...mapState(["name"]),
...mapGetters(["getName"]),
}
}
</script>
输入框内输入数字,点击add就可以看到上方的counter发生了改变
8.4 异步操作 Action
Action类似于Mutation,不同的是Action提交的是mutation,而不是直接变更状态,Action可以调用mutation中的方法、包含任意异步操作(能够添加网络请求),mutation只能同步操作。
8.4.1 配置vuex文件
在src/store/index.js
中添加actions方法,actions方法内必须使用异步处理。此处函数为asyncAddCounter
,函数内调用mutations内的addCounter
函数。asyncAddCounter
函数的功能是将网络请求到的值传入addCounter
函数内,以修改counter
的值。
//index.js
import { createStore } from "vuex";
import axios from "axios";
export default createStore({
mutations:{
addCounter(state, num){
state.counter = state.counter + num;
}
},
actions:{
asyncAddCounter({commit}){
axios.get("http://iwenwiki.com/api/generator/list.php")
.then(res =>{
console.log(res.data);
commit("addCounter", res.data[0]);
})
}
}
})
8.4.2 调用函数
调用方法为:this.$store.dispatch("xxxx")
。此处点击按钮的响应函数内调用actions。
//App.vue
<template>
<p>方法1:counter = {{ $store.state.counter }}</p>
<p>方法2:name = {{ name }}</p>
<button @click="vuexParamCheck">console</button>
<p>Getter:{{ $store.getters.getCounter }}</p>
<p>Getter:{{ getName }}</p>
<input type="number" v-model="inputNumber">
<button @click="addClickHandle">Add</button>
<button @click="addAsyncClickHandle">异步增加</button>
</template>
<script>
import { mapState,mapGetters,mapMutations } from "vuex";
export default{
data(){
return{
inputNumber:0,
}
},
methods:{
...mapMutations(["addCounter"]),
vuexParamCheck(){
console.log(this.$store.state.counter);
console.log(this.name);
},
addClickHandle(){
console.log("inputNumber: " + this.inputNumber);
//this.$store.commit("addCounter",this.inputNumber);
// 固定调用方式
this.addCounter(this.inputNumber);
},
addAsyncClickHandle(){
this.$store.dispatch("asyncAddCounter");
}
},
computed:{
...mapState(["name"]),
...mapGetters(["getName"]),
}
}
</script>
点击异步增加后,counter会每次增加1001。
9 生命周期
每个组件在被创建时都要经过一系列的初始化过程。例如,需要设置数据监听、编译模板、将实例挂载到DOM,并在数据变化时更新DOM等。同时在这个过程中也会运行一些叫做生命周期钩子的函数。这给了用户在不同阶段添加自己代码的机会。
自动化调用,无需手动写。
生命周期 | 名称 | 功能 |
---|---|---|
beforeCreate | 创建前 | |
created | 创建时 | |
beforeMount | 渲染前 | |
mounted | 渲染时 | 网络请求放在此函数内 |
beforeUpdate | 更新前 | |
updated | 更新时 | |
beforeUnmount | 卸载前 | 卸载消耗性能的处理 |
uomunted | 卸载时 |
<template>
<p>---------------------------</p>
<h3>生命周期函数</h3>
<p>年龄:{{ lifetime }}</p>
<button @click="lifetime ++">点击改变</button>
</template>
<script>
export default{
name:"MyComponent",
data(){
return{
lifetime:0,
}
},
beforeCreate(){
console.log("beforeCreate");
},
created(){
console.log("created");
},
beforeMount(){
console.log("beforeMount")
},
mounted(){
console.log("mounted")
// 把网络请求放到这里
},
beforeUpdate(){
console.log("beforeUpdate")
},
updated(){
console.log("updated")
},
beforeUnmount(){
console.log("beforeUnmount")
// 卸载之前,把消耗性能的处理都干掉,比如定时器
},
unmounted(){
console.log("unmounted")
}
}
可以在调试窗口看到生命周期函数按照顺序执行。
10 Vue引入第三方
10.1 轮播图——Swpier
Swpier是触摸滑动插件,纯js打造的,面向手机、平板电脑等移动终端。
官方文档:
https://swiperjs.com/vue
1、首先下载Swiper,命令行内输入:
npm install --save swiper
2、添加Swiper、Pagination(页码)和Autoplay(自动轮播),实现多张图片自动轮播。
<template>
<div>
<swiper :modules="modules" :pagination="{clickable:true}" :autoplay="{autoplay: true, delay: 3000}">
<swiper-slide><img src="../assets/1.jpeg" alt=""></swiper-slide>
<swiper-slide><img src="../assets/3.jpeg" alt=""></swiper-slide>
<swiper-slide><img src="../assets/6.jpeg" alt=""></swiper-slide>
</swiper>
</div>
</template>
<script>
import {Pagination, Autoplay} from 'swiper/modules';
import {Swiper,SwiperSlide} from 'swiper/vue';
import 'swiper/css';
import 'swiper/css/pagination';
import 'swiper/css/autoplay';
export default{
name:"helloworld",
components:{
Swiper,
SwiperSlide,
},
data(){
return{
modules:[Pagination,Autoplay]
}
},
}
</script>
<style scoped>
img{
width:100%
}
</style>
三张图片能够以3秒间隔循环播放。
10.2 Axios网络请求库
Axios是基于promise的网络请求库。
1、安装:
npm intall --save axios
2、引入:
import axios from ‘axios’
<template>
<div>
<p>res_data:{{ res_data }}</p>
<p>error_data:{{ error_data }}</p>
</div>
</template>
<script>
import axios from 'axios';
export default{
name:'TheWelcome',
data(){
return{
res_data:'',
error_data:'',
}
},
mounted(){
console.log("mounted");
// 网络请求
axios({
method:'get',
url:'http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php',
// 使用http可以连接,使用https无法连接
}).then(res =>{
console.log(res.data);
this.res_data = res.data;
}).catch(error =>{
console.log(error.data);
this.error_data = error.data;
})
}
}
</script>
连接HTTP正常,连接HTTPS可能会出现跨域问题。
10.3 Axios网络请求封装
1、在src下新建api文件夹,新建index.js
和path.js
。
// index.js
import axios from "../utils/request";
import path from "./path";
const api = {
// 成品详情地址
getChenpin(){
return axios.get(path.baseUrl + path.chengpin)
}
}
export default api;
path.js
文件下输入地址。
//path.js
const base = {
baseUrl:"http://iwenwiki.com/",
chengpin:"api/blueberrypai/getChengpinDetails.php",
}
export default base;
2、在src文件下新建utils文件夹,新建request.js
,用于网络请求打包。
// request.js
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 =>{ // 包含网络请求的所有信息
if(config.method === "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;
3、主文件内引用刚才的封装。
<template>
<div>
</div>
</template>
<script>
import api from '../api/index.js'
export default{
name:"helloworld",
data(){
return{
}
},
methods:{
},
mounted(){ // 渲染完成后,调用网络请求
api.getChenpin().then(res =>{
console.log(res.data);
}).catch(error => {
console.log(error.data);
});
}
}
</script>
可以再控制台内看到如下信息:
10.4 网络请求的跨域问题
JS采用的是同源策略。浏览器只允许JS代码请求和当前所在服务器域名、端口、协议相同的数据接口上的数据,这就是同源策略。当协议、域名、端口任意一个不相同时,都会产生跨域问题。
Access to XMLHTTPRequest at ‘https://www.baidu.com
/’ from origin ‘http://localhost:5173’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource
两种主流解决方案:
1、后台解决:cros
2、前台解决:proxy(代理)
这里主要讲解前台处理方法:进入vite.config.js
文件,添加server设置(新版本的Vue3必须是server,devServer无法连接)。
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server:{
//port:5173,
//open:true,
//cors:true,
proxy:{
'/api':{
target:'http://iwenwiki.com',
changeOrigin:true
}
}
}
})
然后修改HelloWorld.vue中的网址。
// HelloWorld.vue
<template>
<div>
<h3>跨域解决方案proxy</h3>
</div>
</template>
<script>
import axios from 'axios'
export default{
name:'HelloWorld',
mounted(){
axios.get('/api/FingerUnion/list.php') // 前面相同的域名不用谢了,只需要写后面的/......
.then(res =>{
console.log(res.data);
});
}
}
</script>
vite.config.js配置完成后需要重启服务器。
可以看到调试界面显示了返回的数据。
经过试验,这似乎也不能完全解决所有跨域问题。
11 路由Router
11.1 Router路由配置
通过vue-router
路由管理页面之间的跳转。Vue Router是Vue.js的官方路由。
router可以管理多个页面,并方便进行多个页面的跳转。
11.1.1 安装路由
npm install --save vue-router
11.1.2 配置独立的路由文件
在src文件夹下,新建router文件夹,新建index.js文件,配置如下:
- 导入路由库
- 导入页面,这里导入两个HomeView.vue和AboutView .vue
- 配置routes,设置多个页面的路径path与组成component。
component:() => import("../views/xxxxx.vue")
为异步执行,如果不显示相应页面,则不执行相应代码(不创建渲染页面,节约资源)。
component: xxxxxx
为同步执行。一般首页直接引入component,其他页使用异步执行。
- 使用createRouter()函数管理。
- 导出router,以便其他文件使用。
import { createRouter, createWebHashHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import AboutView from "../views/AboutView.vue";
const routes = [
{
path:"/home",
component:HomeView,
},
{
path:"/about",
component:AboutView,
}
]
// 配置信息中需要页面的相关配置
const router = createRouter({
history: createWebHashHistory(),
routes,
})
export default router;
注意:
createWebHashHistory()
网址内带/#/
,不需要后台配合做重定向。原理:a标签锚点链接。createWebHistory()
网址更简单,不带/#/
,需要后台配合做重定向,否则会出现404问题。原理:H5 pushState()。
11.1.3 创建网页(这一步可以放在10.1.2之前)
在src文件夹下创建views文件夹,在文件夹内创建AboutView.vue和HomeView.vue两个文件。
代码如下:
// AboutView.vue
<template>
<h3>关于页面</h3>
<div>
你好世界!
</div>
</template>
// HomeView.vue
<template>
<h3>首页</h3>
<div>
Hello, World!
</div>
</template>
11.1.4 引入路由到项目内
修改main.js文件
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index.js'
createApp(App).use(router).mount('#app')
11.1.5 指定路由显示入口
在App.vue的template内添加<router-view></router-view>
或者<router-view />
。
11.1.6 指定路由跳转
使用<router-link to="/home"></router-link>
来设置路由跳转链接。
代码如下:
// App.vue
<script setup>
import HelloWorld from './components/HelloWorld.vue';
</script>
<template>
<HelloWorld />
<router-link to="/home">首页</router-link> |
<router-link to="/about">关于页面</router-link>
<router-view></router-view>
</template>
11.2 路由传递参数
通过路由链接点击时,能传递一定的信息到新的页面。包括params传参和query传参。
params传参:/localhost:5173/userInfo/username/pwd
query传参:/localhost:5173/userInfo?username=root&pwd=root
11.2.1 params传参
11.2.1.1 创建下级页面
在NewsView.vue下创建多个新闻类别,在views文件夹下新建NewsDetails.vue
。
代码如下:
//NewsDetails.vue
<template>
<h3>新闻详情</h3>
</template>
11.2.1.2 添加路由信息和指定参数key
进入src/router/index.js
,添加routes,并在path最后添加/:param1
,表示参数的名称为param1。
//index.js
{
path:"/news/details/:param1",
name:"details",
component:() => import("../views/NewsDetails.vue"),
}
11.2.1.3 添加路由链接和需要携带的参数
修改src/views/NewsView.vue
,添加无序列表,列表项内添加路由链接,并在链接后添加/ABCD
,ABCD为携带的参数。
//NewsView.vue
<template>
<h3>新闻</h3>
<ul>
<li><router-link to="/news/details/国内新闻">国内新闻</router-link></li>
<li><router-link to="/news/details/国际新闻">国际新闻</router-link></li>
<li><router-link to="/news/details/经济新闻">经济新闻</router-link></li>
<li><router-link to="/news/details/军事新闻">军事新闻</router-link></li>
</ul>
</template>
<script>
export default{
mounted(){
console.log("NewsView.vue mounted!")
},
unmounted() {
console.log("NewsView.vue unmounted!")
},
}
</script>
也可以用router.push()
方法进行路由跳转:
<template>
<button @click="jump">路由跳转</button>
</template>
<script setup>
import router from '@/router';
function jump(){
router.push({
name: 'NewsView',
params: {
param1: "国际新闻"
}
})
}
</script>
11.2.1.4 跳转页读取路由携带的参数
使用{{ $route.params.name }}
获取参数。
$route.params.
是固定的,后面的name要根据src/router/index.js
内的path: "/news/details/:param1"
来,这里为param1
。
下方代码在进入页面渲染完成后,会输出param1的信息,点击按钮会将param1信息显示在Info1后面。
// NewsDetails.vue
<template>
<h3>新闻详情</h3>
<p>{{ $route.params.param1 }}</p>
<button @click="readParam">读取</button>
<p>Info1: {{ trans1 }}</p>
</template>
<script>
export default{
data(){
trans1: "",
},
methods: {
readParam(){
this.trans1 = this.$route.params.param1;
},
},
mounted(){
console.log("NewsDetails.vue mounted!");
console.log(this.$route.params.param1);
},
unmounted(){
console.log("NewsDetails.vue unmounted!");
}
}
<script>
注意:如果需要传递更多的参数,
- 则在
src/router/index.js
中使用/news/details/:param1/:param2
。 - 在
src/views/NewsView.vue
中使用<router-link to="/news/details/军事新闻/ABCDEFG">
。 - 在
src/views/NewsDetails.vue
的template
中读取参数使用{{ $route.params.param1 }}
和{{ $route.params.param1 }}
,script
中读取参数使用this.route.params.param1
和this.route.params.param2
。
11.2.2 query传参
11.2.2.1 添加路由信息
进入src/router/index.js
,添加routes,并在path后面不需要添加东西了。
//index.js
{
path:"/userInfo",
name:"userInfo",
component:() => import("../views/NewsDetails.vue"),
}
11.2.2.2 传递参数
用router.push()
方法进行路由跳转,使用query
参数
// UserInfo.vue
<template>
<button @click="jump">路由跳转</button>
</template>
<script setup>
import router from '@/router';
function jump(){
router.push({
name: 'UserInfo',
query: {
username: "root",
pwd: "root",
}
})
}
</script>
11.2.2.3 跳转页面读取参数
$route.query.username
和$route.query.pwd
就可读取。
<template>
<div>username: {{ $route.query.username}}</div>
<div>pwd: {{ $route.query.pwd}}</div>
</template>
<script setup>
import { useRoute } from 'vue-router';
const route = useRoute();
const name = route.query.username;
console.log(name);
</script>
11.3 嵌套路由配置
主导航目录下的项目有多个子导航目录。
在About下设置子导航。
11.3.1 新建子页面
新建文件夹src/views/AboutSubview
,新建文件AboutInfo.vue
和AboutUs.vue
。
//AboutUs.vue
<template>
<div>
我们是来自M78星云的咸蛋超人。
</div>
</template>
//AboutInfo.vue
<template>
<div>
如果你想要打怪兽,请随时联系我们,我们电话是:114514
</div>
</template>
11.3.2 设置子网页路由
/src/router/index.js
在about路径下设置children
路由,代码如下:
// index.js
const routes = [
{
path:"/about",
name:"about",
component:() => import("../views/AboutView.vue"),
children:[
{
//二级导航的路径不要加斜杠
path:"us",
component:() => import("../views/AboutSubview/AboutUs.vue"),
},
{
path:"info",
component:() => import("../views/AboutSubview/AboutInfo.vue"),
},
]
},
]
11.3.3 对应页面下设置路由
在src/views/AboutView.vue
下添加路由链接和显示入口。
//AboutView.vue
<template>
<h3>关于</h3>
<router-link to="/about/us">我们</router-link> |
<router-link to="/about/info">信息</router-link>
<router-view></router-view>
</template>
11.3.4 设置默认界面
点击主导航栏后,进入子页面,需要设置一个子页面的子导航栏的默认页面。这里需要用到重定向redirect
。
在/src/router/index.js
中about路径下添加redirect:"/about/xxx"
,代码如下:
// index.js
const routes = [
{
path:"/about",
name:"about",
redirect:"/about/us",
component:() => import("../views/AboutView.vue"),
children:[
{
//二级导航的路径不要加斜杠
path:"us",
component:() => import("../views/AboutSubview/AboutUs.vue"),
},
{
path:"info",
component:() => import("../views/AboutSubview/AboutInfo.vue"),
},
]
},
]
如下图所示,一点击“关于页面”,就默认显示“我们”。
12 局域网内打开网页
首先找到文件夹下的package.json文件,将"dev":"vite"
修改为"dev": "vite --host 0.0.0.0"
。
重新启动服务器,然后就可以看到调试窗口内出现了新的网址,在局域网内输入该网址就可以打开该网页。
手机上显示网页。