vue3 组件常用属性及写法
vue文件基础结构
<template>
<!-- template 此处只能包含一个子标签,一般在 template 下嵌套一层div, 所有的页面内容都写在 div 内 -->
<Layout>
<div>
<!-- 此处为具体的页面内容 -->
</div>
</Layout>
</template>
<!-- vue 组合式写法 -->
<script setup>
/** 1. setup 必须加,vue3 组合式写法
* 2. 每个vue文件都是单独的模块
* 3. 这里定义的 变量及方法 只能在当前文件使用
*/
</script>
<!-- script 选项式 写法-->
<script>
export default {
// data,methods,created,props,emits...
}
</script>
<style scoped>
/* 当前组件的css */
/* scoped 必须加, 确保不同文件间 css 互不影响*/
</style>
组件内 template 中常用命令
v-on
: 绑事件,可简写为 @
v-bind
: 绑数据,可简写为 :
v-model
: 绑定当前值
v-if
v-else
v-else-if
: 组合使用,页面元素的显示隐藏(相当于display: none)
v-show
: 页面元素是否显示(相当于 visibility: hidden)
v-for
: 循环, 必须绑定 key
组件内 script 包含的内容
data
: 定义数据. 直接使用 let const 定义变量,需监听数据实现双向数据绑定时,参数使用ref,reactive模块声明
<script setup>
// const - 关键字, 声明只读数据,不可修改
const user = "admin"; // 不能实时监听
const username = ref("admin") // 可实时监听,实现双向数据绑定
// let - 关键字, 声明可读可写数据
let user = "admin"; // 不能实时监听
let username = ref("admin") // 可实时监听,实现双向数据绑定
/**
使用ref定义的data
script 中访问值需通过 .value 来获取
template 可直接访问
*/
console.log(user, username.value)
</script>
computed
: 实时计算. 必须将计算后的值 return,只能使用不可被赋值. 根据 data, props 数据 计算得到新的数据,与 data 使用方式一致(支持传参计算)
<template>
<div><span v-for="(item, index) in costArr" :key="index">{{ cost(item)}}<span></div>
</template>
<script setup>
import { computed } from 'vue'
const costArr = ["112.34", "1", "0", "133"]
const cost = computed(() => (val) => {
return val.toFixed(2)
})
</script>
props
: 接收父组件传的数据。可根据需要使用 computed watch 实时监听该数据
<!-- 子组件 SubAction.vue -->
<template>
<div>{{ text }}</div>
</template>
<script setup>
const props = defineProps({
text:{
/**
* type可选值: String|Number|Object|Array|Function
* 支持多种数据格式时, String || Number
*/
type: String,
default: "" // 默认值
}
});
</script>
<!-- 父组件 -->
<template>
<SubAction :text="message"></SubAction>
</template>
<script setup>
import {ref} from 'vue'
import SubAction from "SubAction.vue"
const message = ref("This is a text from parent")
</script>
emit
: 抛出事件给父组件。可带参
<!-- 子组件 SubAction.vue -->
<template>
<el-button @click="updateCycle">Update Cycle</el-button>
</template>
<script setup>
import { onMounted, ref } from 'vue'
const emit = defineEmits(['update'])
ley id = ref(1);
function updateCycle() {
emit('update', id++)
}
</script>
<!-- 父组件 -->
<template>
<div>
<span>{{ curId }}</span>
<SubAction @update="getId"></SubAction>
</div>
</template>
<script setup>
import {ref} from 'vue'
import SubAction from "SubAction.vue"
const curId = ref(0)
function getId(val) {
curId.value = val
}
</script>
watch
: 监听页面数据(data,props中)变化. 一般处理需实时变化的的业务逻辑
<script setup>
let loading = true;
watch(loading , (newVal) => {
if (newVal) {
//业务逻辑
}
})
const props = defineProps({
index: {
type: Number
}
})
watch(() => props.index, (val) => {
//业务逻辑
})
</script>
methods
: 定义方法。 可以访问 data, props, computed,及其他function
<template>
<el-table :data="list">
<el-table-column prop="name" label="Username"/>
<el-table-column prop="email" label="Email"/>
</el-table>
</template>
<script setup>
import { watch } from 'vue'
let list = ref([])
const props = definedProps({
id: {
type: String
}
})
watch(() => props.id, ()=> {
getData()
})
function getData() {
list.value = [{name:"1", email: "ooo"}]
}
</script>
生命周期函数
<script setup>
import { onBeforeMount, onMounted, onBeforeUnmount, onUnmounted } from "vue";
onBeforeMount(() => {
console.log("组件挂载前");
});
onMounted(() => {
console.log("组件挂载完成");
});
onBeforeUnmount(() => {
console.log("组件卸载之前");
});
onUnmounted(() => {
console.log("组件卸载完成");
});
</script>
父子组件传参(多层级数据传参)
-
props
-
emit
-
provide
和inject
(多层级数据传参)
<!-- 存值 -->
<script setup>
import { provide } from 'vue'
provide('update', {id: "11", text: "provide"})
</script>
<!-- 取值 -->
<script setup>
import { inject } from 'vue'
const { id, text } = inject('update')
</script>
store
(当前页面公用数据)
// /stores/common.js
import { defineStore } from 'pinia'
import { httpPost } from "@/api/http";
export const commonStore = defineStore('common', {
state: () => {
return {
username: ""
}
},
getters: {
USERNAME() {
if (this.username) return this.username
this.username = JSON.parse(getStorage("USER") || "{}").username
return this.username
}
},
actions: {
userLogin(data) {
return httpPost("/login", data, level).then(suc => {
this.username = suc
return suc
}).catch(err => {
return err
})
},
}
})
<!-- 使用 store -->
<template>
<div>
<span>{{username}}</span>
<el-button class="light-btn" type="primary" @click="toLogin">Log In</el-button>
</div>
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { commonStore } from "@stores/common.js";
const useCommon = commonStore();
let { username } = storeToRefs(useCommon)
function toLogin() {
useCommon.userLogin({loginId: "admin", password:"123" }).then(suc => {
// 页面处理
console.log(username.value)
}).catch(err => {
// 错误处理
})
}
</script>
<style scoped>
</style>
vue 插槽(slot)
默认插槽(无名)
-
示例1:
<!-- Layout.vue --> <template> <div> <div>Header</div> <div> <!-- 插槽出口 --> <slot></slot> </div> <div>Footer</div> </div> </template> <script setup> </script> <!-- 使用 Layout.vue --> <template> <Layout> <div>插槽内容</div> </Layout> </template> <script setup> import Layout from "@components/Layout.vue"; </script>
- 示例2:
<!-- element Form 组件 --> <template> <el-form :inline="true" :model="formInline" class="demo-form-inline"> <el-form-item label="User"> <!-- el-input 就是默认插槽的内容 #default 可不写 --> <el-input #default v-model="formInline.user"/> </el-form-item> </el-form> </template> <script setup> import { reactive } from 'vue' const formInline = reactive({ user: '' }) </script>
具名插槽
- 示例1:
<!-- Layout.vue -->
<template>
<div>
<div>Header</div>
<div>
<!-- 插槽出口 -->
<slot name="left"></slot>
<slot></slot>
<slot name="right"></slot>
</div>
<div>Footer</div>
</div>
</template>
<script setup>
</script>
<!-- 使用 Layout.vue -->
<template>
<Layout>
<div>默认中间内容</div>
<!-- # 为 v-slot 的简写, #left 等价于 v-slot:header 两种写法都可 -->
<template #left>
<span>左侧内容</span>
</template>
<template #right>
<span>右侧内容</span>
</template>
</Layout>
</template>
<script setup>
import Layout from "@components/Layout.vue";
</script>
- 示例2:
<!-- element Form 组件 -->
<template>
<el-form :inline="true" :model="formInline" class="demo-form-inline">
<el-form-item label="User">
<!-- el-input 就是默认插槽的内容 #default 可不写 -->
<el-input #default v-model="formInline.user" />
<!-- 具名插槽 #label 不可省略 -->
<template #label>
<el-checkbox v-model="formInline.checked"></el-checkbox>
</template>
</el-form-item>
</el-form>
</template>
<script setup>
import { reactive } from 'vue'
const formInline = reactive({
user: '',
checked: false
})
</script>
插槽传参
<!-- Layout.vue -->
<template>
<div>
<div>Header</div>
<div>
<!-- 插槽出口 -->
<slot :text="text" :type="type"></slot>
<slot name="left" :data="LeftData"></slot>
</div>
<div>Footer</div>
</div>
</template>
<script setup>
import {ref} from "vue"
const text = ref("text")
const type = ref("1")
const LeftData = ref({
class: "left-container",
name: "#333",
text: "LEFT"
})
</script>
<!-- 使用 Layout.vue -->
<template>
<Layout>
<div #default="{text, type}">获取参数 {{text}}</div>
<div #left="{data}" :class="data.class">获取参数{{data.name}} {{data.text}} </div>
</Layout>
</template>
<script setup>
import Layout from "@components/Layout.vue";
</script>