Vue开发
[1]Vue是什么?
Vue是前端优秀框架, 是一套用于构建用户界面的渐进式框架
[2]Vue开发步骤?
(1)安装Vue工具
Vue CLI
Vue CLI Vue.js 开发的标准工具,Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统
npm install -g @vue/cli
安装之后,你就可以在命令行中访问 vue 命令。你可以通过简单运行 vue,看看是否展示出了一份所有可用命令的帮助信息,来验证它是否安装成功。
vue --version
(2)创建一个项目
运行以下命令来创建一个新项目
vue create vue-demo
温馨提示
在控制台中,可以用上下按键调整选择项
在控制台中,可以用空格(spacebar)选择是否选中和取消选中
可以选择默认项目模板,或者选“手动选择特性”来选取需要的特性。
我们选择
Babel和Progressive Web App (PWA) Support 两个选项即可
温馨提示
在学习期间,不要选中
Linter / Formatter以避免不必要的错误提示
Vue目前有两个主流大版本vue2和vue3,我们本套课程选择vue3最新版本
配置放在哪里? In dedicated config files 专用配置文件或者 In package.json在package.json文件
将其保存为未来项目的预置? y代表保存,并添加名字,n不保存
项目创建成功如下提示信息
(3)运行项目
第一步:进入项目根目录cd vue-demo
第二步:运行npm run serve 启动项目
(4)安装Vue高亮插件
VSCode中安装vetur或者volar都可,前者针对Vue2版本,后者针对Vue3版本
1. 模板语法
<template>
<div class="hello">
<h3>学习Vue:模板语法</h3>
<p>{{ message }}</p>
<div>{{ rawHtml }}</div>
<div v-html="rawHtml"></div>
<div :id="dynamicId"></div>
<p>{{ num+10 }}</p>
<p>{{ flag ? "孙猴子" : "傻猴子" }}</p>
</div>
</template>
<script>
export default {
// innerHTML innerText
name: 'HelloWorld',
data() {
return {
message: "学习Vue",
rawHtml:"<a href='http://www.itbaizhan.com'>百战</a>",
dynamicId:10001,
num:10,
flag:false
}
}
}
</script>
[1]v-text
文本
文本-->{{}}
若使用JS表达式:
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
这些表达式会在当前活动实例的数据作用域下作为 JavaScript 被解析。有个限制就是,每个绑定都只能包含单个表达式.
<!-- 这是语句,不是表达式:-->
{{ var a = 1 }}
<!-- 流程控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
[2]v-html
原始HTML-->v-html
双大括号会将数据解释为普通文本,而非 HTML 代码。为了输出真正的 HTML,你需要使用v-html 指令
[4]v-bind
属性 Attribute
温馨提示
v-bind:可以简写成:
其中:
加冒号的,说明后面的是一个变量或者表达式; 没加冒号的后面就是对应的字符串常量(String)
2. 条件渲染
功能都为:控制显示
[1]v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true 值的时候被渲染。
<p v-if="flag">我是孙猴子</p>
data() {
return {
flag: true
}
}
v-else
你可以使用 v-else 指令来表示 v-if 的“else 块”
<p v-if="flag">我是孙猴子</p>
<p v-else>你是傻猴子</p>
data() {
return {
flag: false
}
}
[2]v-show
另一个用于条件性展示元素的选项是 v-show 指令
<h1 v-show="ok">Hello!</h1>
[3]区别
v-if 是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好
3.列表渲染
[1]v-for
功能:把一个数组映射为一组元素
其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。
<ul>
<li v-for="item in items">{{ item.message }}</li>
</ul>
data() {
return {
items: [{ message: 'Foo' }, { message: 'Bar' }]
}
}
[2]维护状态
当 Vue 正在更新使用 v-for 渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一的 key attribute:
<div v-for="(item,index) in items" :key="item.id|index">
<!-- 内容 -->
</div>
4.事件处理
[1]v-on
v-on作用:监听DOM事件
我们可以使用 v-on 指令 (通常缩写为 @ 符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"
<button @click="counter += 1">Add 1</button>
data() {
return {
counter: 0
}
}
5.表单输入绑定
[1]v-model
v-model:双向数据绑定
双向:既可以获取, 又可以设置
适用元素: <input>、<textarea> 及 <select>
作用:会根据控件类型自动选取正确的方法来更新元素。但 v-model 本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。
以下为修饰符
[2].lazy
在默认情况下,v-model 在每次 input 事件触发后将输入框的值与数据进行同步 。你可以添加 lazy 修饰符,从而转为在 change 事件之后进行同步
比如:失去焦点时进入同步
[3].trim
去输入首尾空格
6.组件基础
[1]单文件组件
单文件组件:.vue格式
vue文件组成:模版,逻辑,样式
App.vue:根组件
[2]加载组件
第一步:引入组件 import MyComponentVue from './components/MyComponent.vue'
第二步:挂载组件 components: { MyComponentVue }
第三步:显示组件 <my-componentVue />
引入,挂载,显示首字母都可以大写,其中显示组件可用‘-’形式
[3]组件的组织
通常一个应用会以一棵嵌套的组件树的形式来组织
7.父传子
Prop类型
Prop传递参数其实是没有类型限制的
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function
}
温馨提示
数据类型为数组或者对象的时候,默认值是需要返回工厂模式(使用函数进行返回)
anArray:{
type:Array,
default:function(){
return[]
}
}
8.子传父
自定义事件组件交互
this.$emit(‘事件’,数据)
9.组件生命周期
每个组件在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会
为了方便记忆,我们可以将他们分类:
创建时:beforeCreate、created
渲染时:beforeMount、mounted
更新时:beforeUpdate、updated
卸载时:beforeUnmount、unmounted
10.Vue引入第三方
寻找第三方
vue2的资源列表里的Awesome Vue
注意:检查第三方支持vue2还是vue3
Swiper:
Swiper 开源、免费、强大的触摸滑动插件
Swiper 是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端
Swiper 能实现触屏焦点图、触屏Tab切换、触屏轮播图切换等常用效果
温馨提示
官方文档:swiperjs.com/vue
安装指定版本:
npm instal --save swiper@8.1.6
11.Axios网络请求
[1]介绍与安装
Axios 是一个基于 promise 的网络请求库
官方文档地址: www.axios-http.cn/docs/intro
以下,具体看文档
安装
npm install axios
温馨提示
post请求参数是需要额外处理的
- 安装依赖:
npm install --save querystring- 转换参数格式:
qs.stringify({})
[2]使用
1.内容包括:
1.局部引入和全局引入
2.post参数格式转换
3.普通写法与快捷方案
2.代码包括:’HelloWorld.vue’ 与 ‘main.js’
[1]HelloWorld.vue
<template>
<div class="hello">
<p>{{ chengpin.title }}</p>
</div>
</template>
<script>
import axios from "axios"
import qs from "querystring"
export default {
name: 'HelloWorld',
data() {
return {
chengpin: {}
}
},
mounted() {
// //1.局部axios用-->axios
// // 1.1 get请求方式
// axios({
// method: "get",
// url: "http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php"
// }).then(res => {
// console.log(res.data);
// this.chengpin = res.data.chengpinDetails[0]
// })
// // 1.2 post请求方式
// axios({
// method: "post",
// url: "http://iwenwiki.com/api/blueberrypai/login.php",
// data: qs.stringify({
// user_id: "iwen@qq.com",
// password: "iwen123",
// verification_code: "crfvw"
// })
// }).then(res =>{
// console.log(res.data);
// })
// 2.全局axios用-->this.$axios
this.$axios.get("http://iwenwiki.com/api/blueberrypai/getChengpinDetails.php")
.then(res => {
console.log(res.data);
})
this.$axios.post("http://iwenwiki.com/api/blueberrypai/login.php", qs.stringify({
user_id: "iwen@qq.com",
password: "iwen123",
verification_code: "crfvw"
})).then(res => {
console.log(res.data);
})
}
}
</script>
[2]main.js设置
import { createApp } from 'vue'
import App from './App.vue'
import './registerServiceWorker'
import axios from "axios"
// 将Axios挂载到全局
const app = createApp(App)
app.config.globalProperties.$axios = axios
app.mount('#app')
12.Axios网络请求封装
封装步骤
安装: npm install axios querystring
- 创建文件:src/utils/request.js:在用来存储网络请求对象
axios - 在src/api创index.js:存放网络请求方法,创path.js:存放请求路径
- import引入后直接使用
1.在src/utils/request.js
import axios from "axios"
import qs from "querystring"
// 参考文档:https://www.kancloud.cn/yunye/axios/234845
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.methods === "post"){
config.data = qs.stringify(config.data)
}
// config:包含着网络请求的所有信息
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;
2.src/api/path.js
const base = {
baseUrl:"http://iwenwiki.com",
chengpin:"/api/blueberrypai/getChengpinDetails.php"
}
export default base;
3.src/api/index.js
import axios from "../utils/request"
import path from "./path"
const api = {
// 诚品详情地址
getChengpin(){
return axios.get(path.baseUrl + path.chengpin)
}
}
export default api
4.组件中直接调用网络请求
import api from "../api/index"
export default {
mounted(){
api.getChengpin().then(res =>{
console.log(res.data);
})
}
}
13.网络请求跨域解决方案
JS采取的是同源策略
同源策略是浏览器的一项安全策略,浏览器只允许js 代码请求和当前所在服务器域名,端口,协议相同的数据接口上的数据,这就是同源策略.
也就是说,当协议、域名、端口任意一个不相同时,都会产生跨域问题,所以又应该如何解决跨域问题呢
解释
- 域名:http
- 端口:默认8080
- 协议:baidu.com
[1]跨域错误提示信息
[2]目前主流的跨域解决方案有两种:
- 后台解决:cors
- 前台解决:proxy
devServer: {
proxy: {
'/api': {
target: '<url>',
changeOrigin: true
}
}
}
温馨提示
解决完跨域配置之后,要记得重启服务器才行哦!
(1)组件使用
import axios from "axios"
export default{
mounted(){
// http://iwenwiki.com/api/FingerUnion/list.php跨域
axios.get("/api/FingerUnion/list.php")
.then(res =>{
console.log(res.data);
})
}
(2)vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
devServer: {
proxy: {
'/api': {
target: 'http://iwenwiki.com',
changeOrigin: true
}
}
}
})
(3)重启服务器
14.Vue引入路由配置
Vue是单页面应用
在Vue中,我们可以通过vue-router路由管理页面之间的关系
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举
步骤:
第一步:安装路由 npm install --save vue-router
第二步:配置独立的路由文件
// index.js
import { createRouter, createWebHashHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const routes = [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
}
]
const router = createRouter({
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>
15.路由传递参数
页面跳转过程中,是可以携带参数的
步骤:
第一步:在路由配置中指定参数的key
{
path:"/list/:name",
name:"list",
//这是异步加载方式:如果页面没有显示出来,代码不会执行,节省空间,让首页加载速度更快一些
component:() => import("../views/ListView.vue")
}
第二步:在跳转过程中携带参数
<li><router-link to="/list/内蒙">内蒙旅游十大景区</router-link></li>
<li><router-link to="/list/北京">北京旅游十大景区</router-link></li>
<li><router-link to="/list/四川">四川旅游十大景区</router-link></li>
第三步:在详情页面读取路由携带的参数
<p>{{ $route.params.name }}城市旅游景区详情</p>
16.嵌套路由配置
(1)二级路由代码:
{
path: '/about',
name: 'about',
// 重定向配置:默认打开哪个二级导航
redirect:"/about/us",
component: () => import('../views/AboutView.vue'),
children:[
{
// 二级导航的路径不要加 /
path:"us",
component:() => import("../views/AboutSub/AboutUS.vue")
},
{
path:"info",
component:() => import("../views/AboutSub/AboutInfo.vue")
}
]
}
(2)路由使用
- 指定子路由显示位置
<router-view></router-view> - 添加子路由跳转链接
<!-- to后地址是完整地址 -->
<router-link to="/news/baidu">百度新闻</router-link> |
<router-link to="/news/wangyi">网易新闻</router-link>
17.Vue状态管理(Vuex)
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
Vuex的核心作用:帮我们管理组件之间的状态.
引入Vuex的步骤:
第一步:安装Vuex npm install --save vuex
第二步:配置Vuex文件 |路径:src/store/index.js
import { createStore } from "vuex"
// Vuex的核心作用就是帮我们管理组件之间的状态的
export default createStore({
// 所有的状态都放在这里(数据)
state:{
counter:0
}
})
第三步:在主文件中引入Vuex |路径:main.js
import store from "./store"
createApp(App).use(store).mount('#app')
第四步:在组件中读取状态
//方法1
<p>counter:{{ $store.state.counter }}</p>
// 方法2
// 1.vuex提供的state快捷读取方式
import { mapState } from "vuex"
// 2.专门来读取vuex的数据
computed:{
...mapState(["counter"])
}
18.Vue状态管理核心(Vuex)(未完成)
最常用的核心概念包含: State、Getter、Mutation、Action
1.Getter
对Vuex中的数据进行过滤
import { createStore } from 'vuex'
export default createStore({
state: {
counter: 0
},
getters: {
getCount(state){
return state.counter > 0 ? state.counter : "counter小于0,不符合要求"
}
}
})
//方法1,多次引用用这个
import { mapGetters } from 'vuex';
computed:{
...mapGetters(["getCount"])
}
//方法2
{{ $store.getters.getCounter }}
2.Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)和一个回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数
mutation同时修改数据
同步操作
import { createStore } from 'vuex'
export default createStore({
state: {
counter: 0
},
getters: {
},
mutations: {
setCounter(state, num) {
state.counter += num
}
}
})
import { mapMutations } from 'vuex';
methods:{
...mapMutations(["setCounter"]),
clickHandler(){
// this.$store.commit("setCounter",20)
// 或者
// this.setCounter(10)
}
}
3.Action
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态
- Action 可以包含任意异步操作
异步操作:网络请求
import { createStore } from 'vuex'
import axios from "axios"
export default createStore({
state: {
counter: 0
},
getters: {
getCount(state){
return state.counter > 0 ? state.counter : "counter小于0,不符合要求"
}
},
mutations: {
setCounter(state, num) {
state.counter += num
}
},
actions: {
asyncSetCount({ commit }){
axios.get("http://iwenwiki.com/api/generator/list.php")
.then(res =>{
commit("setCounter",res.data[0])
})
}
}
})
import { mapState,mapMutations,mapGetters,mapActions } from 'vuex';
methods:{
...mapActions(["asyncSetCount"]),
clickAsyncHandler(){
// this.$store.dispatch("asyncSetCount")
// 或者
// this.asyncSetCount()
}
}
19.Vue3新特性1
(1)六大亮点
- Performance:性能更比Vue 2.0强。
- Tree shaking support:可以将无用模块“剪辑”,仅打包需要的。
- Composition API:组合API
- Fragment, Teleport, Suspense:“碎片”,Teleport即Protal传送门,“悬念”
- Better TypeScript support:更优秀的Ts支持
- Custom Renderer API:暴露了自定义渲染API
(2)ref或者reactive
在2.x中通过组件data的方法来定义一些当前组件的数据
data() {
return {
name: 'iwen',
list: [],
}
}
在3.x中通过ref或者reactive创建响应式对象
import { ref,reactive } from "vue"
export default {
name: 'HelloWorld',
setup(){
const name = ref("iwen")
const state = reactive({
list:[]
})
return{
name,
state
}
}
}
(3)methods中定义的方法写在setup()
在2.x中methods来定义一些当前组件内部方法
methods:{
http(){}
}
在3.x中直接在setup方法中定义并return
setup() {
const http = ()=>{
// do something
}
return {
http
};
}
(4)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)
ctx.emit('event')
},
}
20.Vue3新特性2
(1)在setup中使生命周期函数
你可以通过在生命周期钩子前面加上 “on” 来访问组件的生命周期钩子。
下表包含如何在 setup () 内部调用生命周期钩子
| Options API | Hook inside setup |
|---|---|
| beforeCreate | Not needed* |
| created | Not needed* |
| beforeMount | onBeforeMount |
| mounted | onMounted |
| beforeUpdate | onBeforeUpdate |
| updated | onUpdated |
| beforeUnmount | onBeforeUnmount |
| unmounted | onUnmounted |
export default {
setup() {
// mounted
onMounted(() => {
console.log('Component is mounted!')
})
}
}
(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
}
}
(3)Fragment
Fragment翻译为:“碎片”
- 不再限于模板中的单个根节点
<template>
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App" />
</template>
\