<!-- file: /pages/index/index.vue --> <template><view class="container"><!-- 1. 自定义导航栏组件使用,title是这里透传给子组件的变量,@counterOver是子组件暴露出来的函数事件,ref可以作为选择器,当父组件通过ref选择到子组件时,可以调用子组件里通过defineExpose暴露出的方法 --><navbar :title="pageTitle" @navBarAttached="onNavBarAttached" @counterOver="onCounterOver" ref="nav-bar"/><scroll-view scroll-y class="content"><!-- 2-1. 两种事件传参方式,绑定到data属性传参,移动端推荐将@click事件都替换为@tap,因为click会有300ms的延迟 --><view class="card" @tap="showShareModal" :data-id="currentItem.id"><text>点我分享 (使用data属性传参)</text></view><!-- 2-2. 两种事件传参方式,大家常用的直接传参 --><view class="card" @tap="showShareModal(currentItem.id)"><text>点我分享 (直接传参)</text></view><!-- 3. 组件市场安装的组件使用 --><!--通过组件市场安装的组件和普通组件引用方式差不多,只是选择器可能不一样,比如这个弹窗组件的选择器就是ref,通过ref绑定事件对象--><uni-popup ref="QRCodePopup"></uni-popup><!-- 4. 页面跳转示例 --><view class="card" @tap="navigateToSearch"><text>跳转到搜索页面</text></view><!-- 5. Tab切换示例 --><view class="card" @tap="switchToOrderTab"><text>切换到订单Tab页</text></view></scroll-view></view> </template><script setup> import { ref, reactive, onLoad, watch } from 'vue';// 1. 响应式数据定义 const pageTitle = ref('首页'); const currentItem = reactive({ id: 123, name: '测试项目' });// 2. 获取应用实例和组件引用 const app = getApp(); const QRCodePopup = ref(); //uni_modules插件市场组件引用 const nav-bar = ref(''); //子组件引用// 3. 页面生命周期 - 加载 onLoad((params) => {console.log('页面加载,参数:', params);// 使用全局方法示例,这里是对uni.request的一个封装app.globalData.utils.request({url: '/app/user_info',success: (res) => {const { token } = res.data;//这里是vue3的结构语法,可以从data中提取对应的元素//存储登录数据到storage,获取时把set改成get就行uni.setStorageSync('token', token);}});// 根据URL参数设置通用组件的页面标题if (params.act === 'search') {uni.setNavigationBarTitle({ title: '搜索页' });} else {uni.setNavigationBarTitle({ title: '列表页' });} });// 4. 常用弹窗提醒演示 const showShareModal = (id) => {console.log('分享项目ID:', id || currentItem.id);uni.showToast({title: `分享项目 ${id || currentItem.id}`,icon: 'none'}); };//5 对子组件暴露出来的事件做处理 const onCounterOver = (e) => {//这里可以接收子组件在事件上的传值console.log(e.detail.value)//5.1这里可以调用子组件里通过defineExpose暴露出的方法nav-bar.value.resetCount();//重置当前组件的计数 };// 6. 组件市场下载的插件里会有对应的使用方法,按照文档使用即可 const showQRCodePopup = () => {QRCodePopup.value.open(); };// 7. 常用的页面导航 const navigateToSearch = () => {uni.navigateTo({url: '/pages/search/index'}); };//8. 常用的tab切换 const switchToOrderTab = () => {uni.switchTab({url: '/pages/order/index'}); };// 9. 监听数据变化示例,watch函数可以监听响应式变量的变化,发生变化时可以在里面触发自定义事件 watch(() => order.payStatus, (newValue, oldValue) => {console.log(`支付状态从 ${oldValue} 变为 ${newValue}`); });// 10. 全局事件监听,当业务需要跨页面流转时,比如跳转到另一个页面去付款,可以在另一个页面暴露事件,跳转回来时事件会被成功监听。 uni.$on('orderStatusChange', (data) => {console.log('收到订单状态变更:', data);order.payStatus = data.payStatus; });</script><!-- file: /components/demo-component.vue --> <template><view class="demo-component"><!-- 1. 组件属性接收 --><text class="title">{{ title }}</text><!-- 2. 组件事件发射 --><button @tap="handleButtonClick">点击我</button><!-- 3. 使用插槽 --><slot name="content"></slot><!-- 4. 条件渲染 --><view v-if="isVisible" class="message">这是条件渲染的内容</view><!-- 5. 列表渲染 --><view v-for="(item, index) in items" :key="item.id" class="list-item"><text>{{ index + 1 }}. {{ item.name }}</text></view><!-- 6. 样式绑定 --><view :class="['status', statusClass]" :style="customStyle">状态: {{ statusText }}</view></view> </template><script setup> import { ref, reactive, computed, watch, onMounted, defineProps, defineEmits, toRaw } from 'vue';// 1. 定义组件属性 const props = defineProps({title: {type: String,default: '默认标题'} });// 2. 定义组件事件 const emit = defineEmits(['counterOver']);// 3. 响应式数据 const isVisible = ref(true); const items = reactive([{ id: 1, name: '项目一' },{ id: 2, name: '项目二' },{ id: 3, name: '项目三' } ]);// 4.1 计算属性,使用计算属性可以动态处理响应式数据,比如常用的格式化和一些单位换算 const statusText = computed(() => {switch (props.status) {case 'normal': return '正常';case 'warning': return '警告';case 'error': return '错误';default: return '未知';} });//4.2这样可以从父组件给子组件传递class属性,方便基于类的样式管理 const statusClass = computed(() => `status-${props.status}`);//4.3也可以直接传style行内样式 const customStyle = computed(() => ({color: props.status === 'error' ? 'red' : 'green',fontWeight: 'bold' }));// 5. 调用暴露到父组件的方法并传参 const handleButtonClick = () => {emit('counterOver', {detail: {value: count.value}}); };// 6. 监听属性变化 watch(count, (newValue, oldValue) => {console.log(`计数从 ${oldValue} 变为 ${newValue}`); });// 7. 组件挂载生命周期 onMounted(() => {console.log('组件挂载完成'); });onBeforeMount(() => {console.log('组件挂载前'); });// 8. 暴露方法给父组件,父组件可直接调用 defineExpose({resetCount: () => { count.value = 0; }, }); </script>#################坑############################## ## UniApp/Vue 开发实用小技巧1. **侦听器使用**:`watch()` 用于监听数据变化并做出处理。每当被监听的数据变更时会自动触发更新。2. **模板引用选择DOM**:```vue<input ref='input'/>``````javascriptconst input = ref(null);onMounted(() => {input.value.focus();});```3. **Tab菜单切换**:可以使用 `:is` 动态组件在多个组件之间进行切换。4. **ES6对象解构** - 在 Vue 和 React 中极其常见:```javascriptconst person = { name: 'Alice', age: 30 };const { name, age } = person; // name = 'Alice', age = 30// 函数参数解构function greet({ name, age }) {console.log(`Hello, ${name}. You are ${age}.`);}```5. **默认参数**:`function (a, b = 10) {...}`6. **剩余/扩展运算符**:`...` (用于函数参数或数组/对象操作)7. **增强的对象字面量**:可以直接在对象中写变量和函数8. **v-slot简写**:`v-slot` 可以简写为 `#`9. **EasyCom组件免导入**:符合 easycom 语法的组件可以免导入直接使用。10. **array.reduce 使用**:对数组内容逐个处理,通过回调函数接收累加器和当前值,累加器会在每次累加后更新。11. **微信胶囊按钮**:微信右上角的胶囊块称为胶囊按钮。12. **Flex布局技巧**:`style flex=1` 可以让元素自动填充可用空间。13. **uni.request 数据封装**:`uni.request` 会在外层多包一层 data,如果封装请求,记得返回响应对象时加上 `.data`。14. **插件安装后重启**:安装 UniApp 插件后需要重启模拟器,否则插件可能加载不成功。15. **npm 包安装前提**:如果项目需要通过 npm 安装包,需要先在根目录新建 `package.json` 并输入 `{}` 默认值。16. **动态属性绑定**:Vue 中如果有动态属性,属性名前面记得加 `:`,如 `:class`、`:data` 等。17. **v-if 和 v-for 避免共用**:`v-if` 和 `v-for` 不要放在同一个元素上,会影响性能。18. **样式作用域**:使用 `scoped` 属性可以限制样式只作用于当前组件。19. **响应式数据更新**:直接修改数组或对象时,需要使用特定方法或重新赋值来触发视图更新。20. **生命周期钩子**:合理使用 `onMounted`、`onUpdated`、`onUnmounted` 等生命周期钩子函数。