uniapp

<!-- 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'/>
    ```
    ```javascript
    const input = ref(null);
    onMounted(() => {
      input.value.focus();
    });
    ```

3.  **Tab菜单切换**:可以使用 `:is` 动态组件在多个组件之间进行切换。

4.  **ES6对象解构** - 在 Vue 和 React 中极其常见:
    ```javascript
    const 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` 等生命周期钩子函数。

  

posted @ 2025-09-26 22:10  CrossPython  阅读(15)  评论(0)    收藏  举报