模板语法
{{ }}
动态绑定文本,可以在{{}}
使用单个表达式
<template>
<div>{{text}}</div>
<div>{{num + 10}}</div>
<div>{{flag ? "true" : "false"}}</div>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
text: 'hello',
num: 10,
flag: true
}
}
}
</script>
v-html
动态绑定网页
<template>
<div v-html="url"/>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
url: "<a href='http://www.xxx.com'>xxx</a>",
}
}
}
</script>
v-bind
动态绑定属性,可以简写成: <----> v-bind:
<template>
<div v-bind:id="div1"/>
<div :id="div2"/>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
div1: '1',
div2: '2',
}
}
}
</script>
条件渲染
v-if — v-else
根据结果只渲染其中的一个div
<template>
<div v-if="flag">true</div>
<div v-else>false</div>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
flag: true,
}
}
}
</script>
v-show
<template>
<div v-show="flag">true</div>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
flag: true,
}
}
}
</script>
v-show与v-if
区别!!!
两者都可以条件渲染
v-if
:在渲染时会直接删除v-else
组件,同时v-if
是惰性的,即初始渲染时不会渲染v-if
,只有v-if
第一次为true
时才渲染,基于js
,切换开销大
v-show
:初始化时就被渲染,与true
和false
无关,只是显示与不显示的问题,基于css <style="display:none">
,初始化开销大
使用建议:频繁切换使用v-show
,否则使用v-if
列表渲染
v-for
动态绑定渲染列表
节省性能,当动态修改数据时,不会重新渲染不变的数据,只会渲染变化的数据,即就地更新,该功能需要搭配:key
判断哪些数据发生变化
<template>
<ul>
<li v-for="item in list" :key="item.id">{{item.title}}</li>
</ul>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
list:[
{ id: 1,
title: "1"
},
{ id: 2,
title: "2"
},
]
}
}
}
</script>
事件处理
v-on
监听事件,在触发事件时执行js
, v-on:click="method" <-----> @click="method"
<template>
<button @click="onClick">点击</button>
<button @click="say('hello')">hello</button>
<button @click="say('hi')">hi</button>
<p>{{message}}</p>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
message: 'helloMessage',
}
},
methods: {
onClick(event) {
// 在事件中,读取data中的属性,需要通过this.属性
this.message = "byeMessage";
// event是原生DOM event
event.target.innerHTML = "点击了";
},
// 同一个方法打印不同的参数 hi hello
say(data) {
console.log(data);
}
}
}
</script>
表单输入绑定
v-model
数据双向绑定,可用于<input> <textarea> <select>
v-model.lazy
在change
事件后同步 v-model.trim
过滤输入的首尾空白字符
<template>
<input type="text" v-model="username">
<p>{{username}}</p>
</template>
<script>
export default {
name: 'helloVue',
data() {
return {
username: "",
}
}
}
</script>
组件基础
单文件组件
由模板<html>
、逻辑<js>
、样式<css>
封装成的单个文件
<template>
</template>
<script>
</script>
<style>
</style>
加载组件
<template>
// 显示组件
<xxxComponent></xxxComponent>
</template>
<script>
// 引入组件
import xxxComponent from './xxxComponent.vue'
export default {
name: 'helloVue',
// 挂载组件
components: {
xxxComponent,
},
}
</script>
// scoped: 该样式只在当前组件生效
<style scoped>
</style>
Props组件交互
实现父组件向子组件传递数据
子组件
<template>
<p>{{title}}</p>
<ul>
<li v-for="(item, index) in names" :key="index">{{item}}</li>
</ul>
</template>
<script>
export default {
name: 'sonVue',
props: {
title: {
type: String,
default: "this is sonTitle",
},
names: {
type: Array,
default: function(){ return [] },
},
}
}
</script>
<style scoped>
</style>
父组件
<template>
<sonVue :title="title"/>
</template>
<script>
import sonVue from './sonVue.vue'
export default {
name: 'fatherVue',
components: {
sonVue,
},
data() {
return {
title: "this is fatherTitle"
names: ["xiaozhang", "xiaowang", "xiaoli"]
}
}
}
</script>
<style scoped>
</style>
自定义事件组件交互
实现子组件向父组件传递数据
子组件
<template>
<button @click="sendToFather">sendToFather</button>
</template>
<script>
export default {
name: 'sonVue',
data() {
return {
message: "son--->father",
}
},
methods {
sendToFather() {
// 参数一,字符串,随便写,有意义即可
// 参数二,传递的数据
this.$emit("onEvent", this.message)
}
}
}
</script>
<style scoped>
</style>
父组件
<template>
<sonVue @onEvent="getSonMessage"/>
<p>{{message}}</p>
</template>
<script>
import sonVue from './sonVue.vue'
export default {
name: 'fatherVue',
components: {
sonVue,
},
data() {
return {
message: "",
}
},
methods: {
getSonMessage(data) {
this.message = data;
},
},
}
</script>
<style scoped>
</style>
组件生命周期
八个生命周期函数,自动调用,不需要用户调用
创建时:beforeCreate
、created
渲染时:beforeMount
、mounted
mounted
:组件渲染完成后再进行网络请求,然后将数据渲染到页面
更新时:beforeUpdate
、updated
卸载时:beforeUnmount
、unmounted
beforeUnmount
:卸载之前,清理掉消耗性能的处理,比如定时器
Axios网络请求
安装
npm install --save axios
引入
// 组件中引入
import axios from "axios"
// 全局引入 main.js
const app = createApp(App);
app.config.globalProperties.$axios = axios
app.mount('#app')
// 组件中调用
this.$axios
使用
<template>
</template>
<script>
import axios from "axios"
export default {
name: 'axiosTest',
mounted() {
// get
axios.get('http://www.xxx.com').then(res => {
console.log(res.data);
})
//post
axios.post('http://www.xxx.com', {
id: 1
}).then(res => {
console.log(res.data);
})
}
}
</script>
<style scoped>
</style>
Axios网络请求封装
import { createApp } from 'vue'
import axios from 'axios'
const app = createApp(App)
app.use(store).use(router).mount('#app')
// axios拦截器
axios.interceptors.request.use(
function (config) {
console.log('请求参数:', config);
return config;
}, error => {
return Promise.reject(error);
}
);
axios.interceptors.response.use(
function (response) {
console.log('返回结果:', response);
return response;
}, error => {
console.log('返回错误:', error);
const status = error.response.status;
if (status == 401) {
console.log("访问超时");
}
return new Promise((resolve, reject) => { }).catch((error) => { })
}
);
export default axios;
路由
vue-router
管理页面之间的关系
安装
npm install --save vue-router
配置路由文件 router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{
path: '/',
component: () => import('../views/indexView.vue'),
children: [
{
path: 'welcome',
component: () => import('../views/main/welcomeView.vue')
},
]
},
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router;
引入路由 main.js
import router from './router'
const app = createApp(App)
app.use(router).mount('#app')
指定路由显示入口
<template>
<router-view />
</template>
<script>
</script>
<style>
</style>
携带参数路由
{
path: '/index/:name',
component: () => import('../views/indexView.vue'),
}
<template>
<router-link to="/index/hello"></router-link>
</template>
<p>{{ $router.params.name }}</p>
Vuex
管理组件之间的状态
安装
npm install --save vuex
引入vuex main.js
import vuex from './store'
const app = createApp(App)
app.use(vuex).mount('#app')
state
配置vuex
文件 store/index.js
import { createStore } from "vuex"
export default createStore({
state: {
counter: 0
}
})
读取数据
//方案一
<template>
<p>{{$store.state.counter}}</p>
</template>
// 方案二
<template>
<p>{{counter}}</p>
</template>
<script>
import { mapState } from "vuex"
export default {
name: 'storeTest',
computed: { ...mapState(["counter"]) }
}
</script>
<style scoped>
</style>
getter
import { createStore } from "vuex"
export default createStore({
// state 用于存储数据
state: {
counter: 1
},
//getter 用于过滤数据
getters: {
getCount(state) { return state.counter > 0 ? state.counter: "error" }
}
})
读取过滤后的数据
// 方案一
<template>
// 读取过滤后的数据
<p>{{$store.getters.getCount}}</p>
</template>
// 方案二
<template>
<p>{{getCount}}</p>
</template>
<script>
import { mapGetters } from "vuex"
export default {
name: 'storeTest',
computed: { ...mapGetters(["getCount"]) }
}
</script>
<style scoped>
</style>
mutation
用于修改数据,只能同步操作
import { createStore } from "vuex"
export default createStore({
state: {
counter: 1
},
getters: {
getCount(state) { return state.counter > 0 ? state.counter: "error" }
},
mutations: {
setCount(state, num) { state.counter += num }
}
})
修改数据
<template>
<p>{{getCount}}</p>
<button @click="onClick">click</button>
</template>
// 方案一
<script>
import { mapGetters } from "vuex"
export default {
name: 'storeTest',
computed: { ...mapGetters(["getCount"]) },
methods: {
onClick() {
// 固定调用方式
this.$store.commit("setCount", 2)
}
}
}
</script>
// 方案二
<script>
import { mapGetters, mapMutations } from "vuex"
export default {
name: 'storeTest',
computed: { ...mapGetters(["getCount"]) },
methods: {
...mapMutations(["setCount"]),
onClick() { this.setCount(2) }
}
}
</script>
<style scoped>
</style>
action
异步操作时才需要action,action提交的是mutation,不是直接变更状态
import { createStore } from "vuex"
import axios from "axios"
export default createStore({
state: {
counter: 1
},
getters: {
getCount(state) { return state.counter > 0 ? state.counter: "error" }
},
mutations: {
setCount(state, num) { state.counter += num }
},
actions: {
asyncSetCount({ commit }) {
// 异步操作,获取到后端数据,然后调用mutation修改数据
axios.get('http://www.xxx.com').then(res => {
commit("setCount", res.data)
})
}
}
})
修改数据
<template>
<p>{{getCount}}</p>
<button @click="onClick">click</button>
<button @click="onAsyncClick">asyncClick</button>
</template>
// 方案一
<script>
import { mapGetters } from "vuex"
export default {
name: 'storeTest',
computed: {
...mapGetters(["getCount"])
},
methods: {
onClick() {
// 固定调用方式
this.$store.commit("setCount", 2);
},
onAsyncClick() {
this.store.dispatch("asyncSetCount");
}
}
}
</script>
// 方案二
<script>
import { mapGetters, mapMutations,mapActions } from "vuex"
export default {
name: 'storeTest',
computed: {
...mapGetters(["getCount"])
},
methods: {
...mapMutations(["setCount"]),
...mapActions(["asyncSetCount"]),
onClick() {
// 固定调用方式
this.setCount(2)
},
onAsyncClick() {
this.asyncSetCount();
}
}
}
</script>
<style scoped>
</style>
vue3新特性
组合API、更优秀的Ts支持
ref&reactive
<template>
<p>{{message}}</p>
<ul>
<li v-for="(item, index) in names.list" :key="index">{{item}}</li>
</ul>
<button @click="onClick">click</button>
</template>
<script>
import { ref, reactive } from "vue"
export default {
name: "hello ref&reactive",
//组合式API
setup() {
// ref
const message = ref("hello ref&reactive")
// reactive
const names = reactive({
list: ["xiaozhang", "xiaowang", "xiaoli"]
})
function onClick() {
message.value="hello click";
console.log("click");
}
return {
message,
names,
onClick
}
}
}
</script>
props&context
子组件
<template>
<p>{{title}}</p>
</template>
<script>
import { ref, reactive } from "vue"
export default {
name: "hello ref&reactive",
props: {
title:String
}
// setup中不能使用this, 而是被context代替
// this.title也被淘汰,直接使用title
setup(props, ctx) {
console.log(ctx);
const title = props.title;
return {
title,
}
}
}
</script>
父组件
<template>
<sonVue title="FatherTitle"/>
</template>
<script>
import sonVue from './sonVue.vue'
export default {
name: 'fatherVue',
components: {
sonVue,
},
}
</script>
<style scoped>
</style>