一.vue3语法
1.关于computed的小案例
使用demo7制作的案例,加上价格以及价格的统计:
首先把checkboxgroup加在外层
,加上@change事件
,checkbox中加上:value
,id值换成字符串
实现选择一个选项就输出对应的数组位置
<template>
<view>
<view class="out">
<checkbox-group @change="itemChange">
<view class="item" v-for="(item,index) in goods" :key="item.id">
<checkbox :value="item.id"></checkbox>
<text class="title">{{item.name}}</text>
<text class="money">¥{{item.price}}</text>
<text class="del" @click="remove(index)">删除</text>
</view>
</checkbox-group>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue';
const goods=ref([
{id:"1",name:"小米",price:3000},
{id:"2",name:"华为",price:4000},
{id:"3",name:"oppo",price:5000},
{id:"4",name:"苹果",price:6000},
])
function remove(index){
goods.value.splice(index,1)
}
function itemChange(e){
console.log(e);
}
</script>
<style lang="scss" scoped>
.out {
margin:10px 0;
.item {
padding: 10px 0;
.del {
padding-left:30px;
color: red;
}
.money {
padding-left:30px;
}
}
}
</style>
增加计算选中总个数和总价格,这里对数组的操作要熟练,用到了forEach,includes,reduce
<template>
<view>
<view class="out">
<checkbox-group @change="itemChange">
<view class="item" v-for="(item,index) in goods" :key="item.id">
<checkbox :value="item.id" :checked="item.checked"></checkbox>
<text class="title">{{item.name}}</text>
<text class="money">¥{{item.price}}</text>
<text class="del" @click="remove(index)">删除</text>
</view>
</checkbox-group>
<view class="card">选中{{selectNum.length}}个,总价{{selectPrice}}元</view>
</view>
</view>
</template>
<script setup>
import { ref ,computed} from 'vue';
const goods=ref([
{id:"1",name:"小米",price:3000,checked:false},
{id:"2",name:"华为",price:4000,checked:false},
{id:"3",name:"oppo",price:5000,checked:false},
{id:"4",name:"苹果",price:6000,checked:false},
])
const selectNum=ref([]);
const selectPrice=computed(()=>{
return goods.value.reduce((total,item)=>{
if(item.checked){
total+=item.price;
}
return total;
},0)
});
function remove(index){
goods.value.splice(index,1)
}
function itemChange(e){
selectNum.value=e.detail.value;
goods.value.forEach(item=>{
item.checked=selectNum.value.includes(item.id)
})
}
</script>
<style lang="scss" scoped>
.out {
margin:10px 0;
.item {
padding: 10px 0;
.del {
padding-left:30px;
color: red;
}
.money {
padding-left:30px;
}
}
}
</style>
实现效果:
2. watch
默认是浅层监听:
<template>
<view>
<input type="text" v-model="person" />
</view>
{{person}}
</template>
<script setup>
import {ref,watch} from 'vue';
const person=ref("");
watch(person,(newValue)=>{
console.log(newValue);
})
</script>
<style lang="scss">
</style>
换成对象的数据:watch里面就不能只写一个person了,要换成person.value.name,用箭头函数
<template>
<view>
<input type="text" v-model="person.name" />
</view>
{{person}}
</template>
<script setup>
import {ref,watch} from 'vue';
const person=ref({
name:"张三",
age:20
});
watch(()=>person.value.name,(newValue)=>{
console.log(newValue);
})
</script>
<style lang="scss">
</style>
使用deeptrue:
<template>
<view>
<input type="text" v-model="person.name" />
</view>
{{person}}
</template>
<script setup>
import {ref,watch} from 'vue';
const person=ref({
name:"张三",
age:20
});
// watch(()=>person.value.name,(newValue)=>{
// console.log(newValue);
// })
watch(person,(newValue)=>{
console.log(newValue);
},{deep:true})
</script>
<style lang="scss">
</style>
实现监听:(不加的话是没有显示的,也就是监听不到)
3.组件创建
uniapp和vue官方的组件创立是有区别的
引入组件只需要在建component文件夹,然后在下面建组件就可以用了
<template>
<view class="content">
<component1 v-for="item in 3"></component1>
</view>
</template>
<script>
</script>
<style>
</style>
<template>
<view>
张三
</view>
</template>
<script>
export default {
name:"component1",
data() {
return {
};
}
}
</script>
<style>
</style>
实现效果:
4.组件中使用props进行数据传递
具体看vue官网的cn.vuejs.org/guide/compo…
基本使用(字符串的传递):
主页:(图片路径选用../相对路径)
<template>
<view class="content">
<UserInfo username="xiaoming" pic="../../static/pic1.png"></UserInfo>
<UserInfo></UserInfo>
<UserInfo :username="name"></UserInfo>
</view>
</template>
<script setup>
import {ref} from "vue";
const name=ref("xiaolan");
</script>
<style lang="scss">
</style>
组件:
<template>
<view class="userinfo">
<image :src="pic" class="pic"></image>
<view class="username">{{username}}</view>
</view>
</template>
<script setup>
const props=defineProps({
username:{
type:String,
default:"匿名"
},
pic:{
type:String,
default:"../../static/logo.png"
}
});
</script>
<style lang="scss" scoped>
.userinfo {
width: 100%;
height: 200px;
background-color: #ccc;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
image {
width: 100px;
height: 100px;
}
}
</style>
props中换成传入的是数组对象的写法:
组件:
<template>
<view class="userinfo">
<image :src="obj.pic" class="pic"></image>
<view class="username">{{obj.name}}</view>
</view>
</template>
<script setup>
defineProps({
obj:{
type:Object,
default(){
return {name:"匿名",pic:"../../static/logo.png"}
}
}
});
</script>
<style lang="scss" scoped>
.userinfo {
width: 100%;
height: 200px;
background-color: #ccc;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
image {
width: 100px;
height: 100px;
}
}
</style>
主页:
<template>
<view class="content">
<UserInfo v-for="(item,index) in userinfo" :obj="item"></UserInfo>
</view>
</template>
<script setup>
import {ref} from "vue";
const userinfo=ref([
{
name:"张三",
pic:"../../static/pic1.png"
},
{
name:"李四",
pic:"../../static/pic2.png"
},
{
name:"王五",
pic:"../../static/pic3.png"
}
])
</script>
<style lang="scss">
</style>
实现效果:
5.Slots
为没有定义组件的地方预留一个大小不限的空间
layout组件:
<template>
<view class="layout">
<view class="header">头部</view>
<view class="main">
<slot></slot>
</view>
<view class="footer">底部</view>
</view>
</template>
<script setup>
</script>
<style lang="scss">
.layout {
.header {
height:100px;
background: #cfcfcf;
}
.main {
min-height: 200px;
}
.footer {
height: 120px;
background-color: orange;
}
}
</style>
demo1:不同的地方就在页面中写上
<template>
<view>
<lyt-layout>
<view class="row" v-for="item in 20">每一行{{item}}</view>
</lyt-layout>
</view>
</template>
<script setup>
</script>
<style lang="scss">
</style>
demo2:
<template>
<view>
<lyt-layout></lyt-layout>
</view>
</template>
<script setup>
</script>
<style lang="scss">
</style>
两个页面区别:
具名插槽: 如果除了中心有插槽,头部或者底部也有,就要使用具名插槽了,否则插入的东西位置就会乱。
使用方法:(用template)
<template>
<view>
<lyt-layout>
<template v-slot:header>demo2的头部</template>
<template #main>demo2的中心</template>
</lyt-layout>
</view>
</template>
<script setup>
</script>
<style lang="scss">
.box1 {
width:50px;
height: 50px;
background-color: pink;
}
.box2 {
width:50px;
height: 50px;
background-color: skyblue;
}
</style>
6.组件中的emit的声明和触发
前面学的是props是父组件给子组件传, 现在学习怎么让子组件给父组件传
场景:比如说在搜索栏是一个子组件,我们输入内容的时候相当于子组件的数据变化了,那么就需要让搜索页面(父组件)做出相应的变化。
子组件: @click="$emit('add',123)"
<template>
<view>
子组件
<button @click="$emit('add',123)">按钮</button>
</view>
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>
父页面:@add="onAdd"
<template>
<view>
<component-child @add="onAdd"></component-child>
<view>{{num}}</view>
</view>
</template>
<script setup>
import {ref} from "vue";
const num=ref("");
const onAdd=function(e){
console.log(e);
num.value=e;
}
</script>
<style lang="scss">
</style>
点击前:
点击后:(收到子组件传来的数据了)
实现随机色:(子组件传来的是随机数)
<template>
<view>
<component-child @add="onAdd"></component-child>
<view class="box" :style="{background:color}">{{num}}</view>
</view>
</template>
<script setup>
import {ref} from "vue";
const num=ref("");
const color=ref("")
const onAdd=function(e){
console.log(e);
num.value=e;
color.value='#'+String(e).substring(3,6);
}
</script>
<style lang="scss">
.box {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
一般子组件是在script的代码块中传的: const emit=defineEmits(["add"])
和使用defineProps是类似的
<template>
<view>
子组件
<button @click="onClick">按钮</button>
</view>
</template>
<script setup>
const emit=defineEmits(["add"]);
function onClick(){
emit("add",Math.random());
}
</script>
<style lang="scss" scoped>
</style>
input的emit:实现在input框输入数据的同时,把数据传给父组件
<template>
<view>
子组件
<button @click="onClick">按钮</button>
<input @input="onInput"/>
</view>
</template>
<script setup>
const emit=defineEmits(["add","change"])
function onClick(){
emit("add",Math.random());
}
function onInput(e){
// console.log(e.detail.value);
emit("change",e.detail.value)
}
</script>
<style lang="scss" scoped>
input {
border: 1px solid #fcfcfc;
height: 40px;
}
</style>
<template>
<view>
<component-child @add="onAdd" @change="onChange"></component-child>
<view class="box" :style="{background:color,fontSize:size+'px'}">{{num}}</view>
</view>
</template>
<script setup>
import {ref} from "vue";
const num=ref("");
const color=ref("");
const size=ref(10);
const onAdd=function(e){
console.log(e);
num.value=e;
color.value='#'+String(e).substring(3,6);
}
const onChange=function(e){
console.log(e);
size.value=e;
}
</script>
<style lang="scss">
.box {
width: 100px;
height: 100px;
background-color: pink;
}
</style>
7.组件生命周期
8.使用defineExpose暴露子组件的属性和方法
暴露属性:
子组件:用defineExpose
<template>
<view class="out">
子组件
</view>
</template>
<script setup>
import {ref} from "vue";
const count=ref(100);
defineExpose({
count,
str:"lyt"
})
</script>
<style lang="scss" scoped>
</style>
父页面:必须要使用在onMounted中写,因为这个时候组件才挂载完成
<template>
<view>
<demo-child ref="child"></demo-child>
</view>
</template>
<script setup>
import {onMounted, ref} from "vue";
const child=ref(null);
onMounted(()=>{
console.log(child.value);
})
</script>
<style>
</style>
暴露方法:这个时候组件已经渲染完毕,可以直接调用它暴露出来的函数,所以不用在onMounted中写了
<template>
<view class="out">
子组件{{count}}
</view>
</template>
<script setup>
import {ref} from "vue";
const count=ref(100);
const updateCount=function (){
count.value++;
}
defineExpose({
count,
str:"lyt",
updateCount
})
</script>
<style lang="scss" scoped>
</style>
<template>
<view>
<demo-child ref="child" ></demo-child>
<button @click="update">点击修改子元素的值</button>
</view>
</template>
<script setup>
import {onMounted, ref} from "vue";
const child=ref(null);
const update=function (){
child.value.updateCount();
}
onMounted(()=>{
console.log(child.value);
})
</script>
<style>
</style>
9.页面生命周期
onLoad: 可以用来接收上一个页面的参数:
demo5中跳转的时候传递参数:
<template>
<view>
<demo-child ref="child" ></demo-child>
<button @click="update">点击修改子元素的值</button>
<navigator url="/pages/demo6/demo6?name=王五&age=20"><button>跳转到demo6</button></navigator>
</view>
</template>
<script setup>
import {onMounted, ref} from "vue";
const child=ref(null);
const update=function (){
child.value.updateCount();
}
onMounted(()=>{
console.log(child.value);
})
</script>
<style>
</style>
demo6:
<template>
<view>
姓名:{{name}}
年龄:{{age}}
</view>
</template>
<script setup>
import {onLoad} from "@dcloudio/uni-app";
import {ref} from "vue";
const name=ref("张三");
const age=ref(10)
onLoad((e)=>{
name.value="李四"
console.log("onLoad函数");
console.log(e);
name.value=e.name;
age.value=e.age;
})
</script>
<style lang="scss" scoped>
</style>
显示结果: