vue3 setup 语法糖笔记

3,485 阅读2分钟
响应式数据的判断
  • isRef: 检查一个值是否为一个 ref 对象
  • isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
  • isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
  • isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
1.props传值
// 父组件中和之前vue2一样,子组件中接受
<template>
   <div>
      <h2>{{ msg }}</h2>
   </div>
</template>
// setup 语法糖中
<script setup>
import { defineProps,toRefs } from 'vue'
export interface IProps {
	msg: string;
	falg: boolean;
}
// 无默认值
const props = defineProps({ 
    msg: String, 
    falg:boolean,
})
// 有默认值
const props = withDefaults(defineProps<IProps>(), {
        msg:'hello world'
	falg: false,
});
const {msg,propsData} = props  // 这样会失去响应式
const {msg,propsData} = toRefs(props)  // 这样才可以,js中使用需要.value
</script>
// setup 中
<script>
import { defineComponent,toRefs } from 'vue'
export default defineComponent({
   props: {
      msg: {
         type: String
      }
   },
   setup(props, context) {
      const {msg,propsData} = toRefs(props)
      return {}
   }
})
</script>
2.$emit 自定义事件
// 父组件中和之前vue2 一样
<template>
   <div>
      <el-button @click="sonClick">Emit</el-button>
   </div>
</template>

// setup 语法糖
<script setup>
import { ref,defineEmits } from 'vue'
const count = ref('传递的数据')
const emits = defineEmits(['queryParent'])
function sonClick() {
   emits('queryParent', count)
}
</script>

// setup函数 中
setup(props, context) { 
    function change() { 
        context.emit('valueChange', 3) 
    } 
}
3.ref获取子组件实例
<template>
  <div id="app" ref="root">
    <p class="child"></p>
  </div>
</template>

<script>
import {ref, onMounted} from 'vue'
export default {
  setup() {
    const root = ref(null)
    onMounted(() => {  
      // 注意:在onMounted中才可以获取到
      console.log(root.value)
    })
  }
}
</script>
4.store 获取Vuex
<script>
import {onMounted} from 'vue'
import {useStore} from 'vuex'
export default {
  name: 'App',
  setup(props, context) {
    const store = useStore()
    onMounted(() => {
      console.log(store.state.info)
      store.commit('show')
    })
  }
}
</script>
5.直接在style中使用变量
<script setup>
import { ref, reactive, getCurrentInstance } from 'vue'
const boxWidth = ref('100px')
interface IProps {
    num: number;
    height: string;
}
defineProps<IProps>();
</script>

<style scoped>
.testBox{
  height: v-bind(height); // 直接使用props中的属性和template中一样
  width: v-bind(boxWidth);
  border: 1px solid #ccc;
}</style>
6.watch监听
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const tempObj={
    name:'jp',
    age:'18',
}
// 单个响应式数据监听
watch(count,(val)=>{console.log(val)},{immediate:true})
// watch监听非响应式数据的时候需要使用回调函数的形式
watch(()=>tempObj,(val)=>{console.log(val)},{immediate:true,deep:true})
// 多个数据同时监听,使用数组
watch([()=>tempObj,count],(val)=>{console.log(val)},{immediate:true,deep:true})
</script>
7.compouted 计算属性
<script setup>
import { reactive, computed } from 'vue'
const user=reactive({
    firstName:'J',
    lastName:'P'
})
const realName = compoted(()=>user.firstName + user.lastName)
// 计算属性的函数中可以传入一个对象,可以包含`set`和`get`函数,进行读取和修改的操作
const realName = computed({ 
    get() { 
        return user.firstName + '_' + user.lastName; 
    }, 
    set(val: string) { 
        const names = val.split('_');
        user.firstName = names[0]; 
        user.lastName = names[1]; 
    }, 
});
</script>
8.pinia 使用
  1. 创建pinia,stores中创建index.ts

image.png

// https://pinia.vuejs.org/
import { createPinia } from 'pinia';
// 创建
const pinia = createPinia();
// 导出
export default pinia;
  1. main.ts中引入,挂载到app
import pinia from '@/stores/index';
app.use(pinia)
  1. 创建模块

image.png

import { defineStore } from 'pinia';
interface IPovertyRelief {
    secondaryMenu: string;  // 二级菜单 一张图 | 五小产业
    pageType: string; // 页面类型
    pageName: string; // 页面名称
    showDetails:boolean; // 住户详情弹框
    residentId:string; // 住户id
}
/**
 * 后端返回原始路由(未处理时)
 * @methods setCacheKeepAlive 设置接口原始路由数据
 */
export const usePovertyRelief = defineStore('povertyRelief', {
    state: (): IPovertyRelief => ({
        secondaryMenu: 'main',
        pageType: 'garden',
        pageName:'',
        showDetails:false,
        residentId:'',
    }),
    actions: {

    },
});

4.页面中引入使用

import { storeToRefs } from 'pinia';  
import { usePovertyRelief } from '@/stores/povertyRelief';
const povertyRelief = usePovertyRelief();
const { secondaryMenu, showDetails } = storeToRefs(povertyRelief); // 直接结构会失去响应式
// secondaryMenu, pageType 同proxy代理ref,template中直接使用,script中需要使用`value`属性;
9.v-model多个数据绑定更新
// 父组件
<Editor v-model:get-html="state.editor.htmlVal" v-model:get-text="state.editor.textVal" />
// 子组件
const props = defineProps({
	getHtml: String,
        getText: String,
});
const emit = defineEmits(['update:getHtml', 'update:getText']);
const handleChange = (editor: IDomEditor) => {
	emit('update:getHtml', editor.getHtml());
	emit('update:getText', editor.getText());
};
10.vite项目 批量导入图片
<script setup lang="ts">
// 导入图片,这里的路径需要是相对路径
const imgList = import.meta.glob('../../assets/img/*.*',{eager:true})
console.log(imgList)
</script>
11.Teleport传送门使用
// 注意: Teleport,使用传送门组件做全屏页面路由跳转时外层必须包裹一层容器,否则返回其他页面都是空白; 
<div> 
    <Teleport to="#app"> 
        <div class="market_container"></div> 
    </Teleport> 
</div>