GLOBAL_DATA_USAGE.md 13 KB

在插件组件中获取 App 全局数据

📖 概述

在微信官方阅读器插件的自定义组件中,可以通过 getApp() 方法获取小程序的 App 实例,从而访问在 App 中定义的全局数据(globalData)。

🔧 实现步骤

步骤 1:在 app.tsx 中定义 globalData

// src/app.tsx
class App extends Component {
  // 定义全局数据
  globalData = {
    isShow: false,           // 控制是否显示全屏组件
    customParams: null,     // 自定义参数
    userInfo: null,         // 用户信息
    vipLevel: 0,           // VIP 等级
    readingMode: 'normal',  // 阅读模式:normal/immersive
    adConfig: {
      enabled: true,        // 是否启用广告
      frequency: 5,         // 广告频率(每几章显示一次)
      type: 'fullscreen'    // 广告类型:fullscreen/banner
    }
  }

  onLaunch(options) {
    console.log("apponLaunch", options)
    
    // 初始化全局数据
    this.globalData.isShow = true
    this.globalData.customParams = {}
    
    // 监听进入插件页事件    
    novelPlugin.onPageLoad(this.onNovelPluginLoad)
  }
  
  // ... 其他代码
}

步骤 2:在插件组件中获取 globalData

// components/novelPlugin/fullScreen/index.js
Component({
  lifetimes: {
    attached() {
      // ========== 获取 App 全局数据 ==========
      const app = getApp()
      console.log('获取 App 实例:', app)
      console.log('App globalData:', app.globalData)
      
      // 读取你在 app.tsx 中定义的参数
      if (app.globalData) {
        const isShow = app.globalData.isShow
        const customParams = app.globalData.customParams
        const vipLevel = app.globalData.vipLevel
        const adConfig = app.globalData.adConfig
        
        console.log('isShow:', isShow)
        console.log('customParams:', customParams)
        console.log('vipLevel:', vipLevel)
        console.log('adConfig:', adConfig)
        
        // 根据 isShow 决定是否显示全屏组件
        if (isShow === false) {
          console.log('根据配置不显示全屏组件')
          // 可以在这里调用关闭逻辑
          // this.handleClose()
        }
        
        // 根据 VIP 等级显示不同的推荐内容
        if (vipLevel >= 3) {
          // 显示 VIP 专属推荐
          this.loadVipRecommendations()
        } else {
          // 显示普通推荐
          this.loadNormalRecommendations()
        }
        
        // 检查广告是否启用
        if (!adConfig.enabled) {
          console.log('广告已禁用,不显示全屏组件')
          return
        }
      }
      // ====================================
      
      // ... 其他初始化逻辑
    },
  },
  
  methods: {
    loadVipRecommendations() {
      // 加载 VIP 专属推荐
    },
    
    loadNormalRecommendations() {
      // 加载普通推荐
    }
  }
})

💡 常见使用场景

场景 1:根据全局配置控制显示

app.tsx:

class App extends Component {
  globalData = {
    showFullScreenAd: true,  // 全局控制是否显示全屏广告
    adFrequency: 5          // 广告频率
  }
}

组件中:

attached() {
  const app = getApp()
  
  if (!app.globalData.showFullScreenAd) {
    console.log('全屏广告已禁用')
    return
  }
  
  // 继续显示逻辑...
}

场景 2:根据 VIP 等级显示不同内容

app.tsx:

class App extends Component {
  globalData = {
    userInfo: {
      isVip: true,
      vipLevel: 3,
      userId: 'user-123'
    }
  }
}

组件中:

attached() {
  const app = getApp()
  const { isVip, vipLevel, userId } = app.globalData.userInfo
  
  if (isVip) {
    // VIP 用户显示专属推荐
    this.setData({
      recommendList: this.getVipBooks(vipLevel)
    })
  } else {
    // 非 VIP 用户显示普通推荐
    this.setData({
      recommendList: this.getNormalBooks()
    })
  }
  
  // 记录用户行为
  this.reportAnalytics('fullscreen_show', {
    userId,
    isVip,
    vipLevel
  })
}

场景 3:动态配置广告策略

app.tsx:

class App extends Component {
  globalData = {
    adStrategy: {
      enableChapterEnd: true,    // 章节末尾显示
      enableBookEnd: true,       // 书籍末尾显示
      minChapterInterval: 3,     // 最小章节间隔
      maxDailyShows: 5,          // 每日最大展示次数
      blacklistedUsers: []       // 黑名单用户
    }
  }
}

组件中:

attached() {
  const app = getApp()
  const strategy = app.globalData.adStrategy
  
  // 检查是否在黑名单中
  if (strategy.blacklistedUsers.includes(currentUserId)) {
    console.log('用户在黑名单中,不显示广告')
    return
  }
  
  // 检查今日展示次数
  const todayShows = Taro.getStorageSync('todayAdShows') || 0
  if (todayShows >= strategy.maxDailyShows) {
    console.log('今日展示次数已达上限')
    return
  }
  
  // 继续显示逻辑...
}

场景 4:多语言支持

app.tsx:

class App extends Component {
  globalData = {
    language: 'zh-CN',  // zh-CN / en-US
    translations: {
      'zh-CN': {
        close: '关闭',
        recommend: '推荐阅读'
      },
      'en-US': {
        close: 'Close',
        recommend: 'Recommended'
      }
    }
  }
}

组件中:

attached() {
  const app = getApp()
  const lang = app.globalData.language
  const t = app.globalData.translations[lang]
  
  this.setData({
    i18n: {
      closeText: t.close,
      recommendTitle: t.recommend
    }
  })
}

🎯 完整示例

app.tsx 完整代码

// src/app.tsx
import Taro from '@tarojs/taro'

const novelPlugin = Taro.requirePlugin('novel-plugin')

class App extends Component {
  // 定义全局数据
  globalData = {
    // 基础配置
    isShow: true,
    customParams: null,
    
    // 用户信息
    userInfo: null,
    vipLevel: 0,
    
    // 阅读设置
    readingMode: 'normal',
    fontSize: 16,
    theme: 'light',
    
    // 广告配置
    adConfig: {
      enabled: true,
      frequency: 5,
      type: 'fullscreen',
      strategies: {
        showInChapterEnd: true,
        showInBookEnd: true,
        minInterval: 3
      }
    },
    
    // 多语言
    language: 'zh-CN',
    translations: {
      'zh-CN': { close: '关闭', recommend: '推荐阅读' },
      'en-US': { close: 'Close', recommend: 'Recommended' }
    }
  }

  onLaunch(options) {
    console.log("apponLaunch", options)
    
    // 初始化全局数据
    this.initGlobalData()
    
    // 监听进入插件页事件
    novelPlugin.onPageLoad(this.onNovelPluginLoad)
  }
  
  initGlobalData() {
    // 从本地缓存读取配置
    const config = Taro.getStorageSync('appConfig')
    if (config) {
      this.globalData = {
        ...this.globalData,
        ...config
      }
    }
    
    // 从服务器获取最新配置
    this.fetchRemoteConfig()
  }
  
  async fetchRemoteConfig() {
    try {
      const response = await Taro.request({
        url: 'https://api.example.com/config'
      })
      
      // 更新全局配置
      this.globalData = {
        ...this.globalData,
        ...response.data
      }
      
      // 保存到本地缓存
      Taro.setStorageSync('appConfig', this.globalData)
    } catch (error) {
      console.error('获取远程配置失败:', error)
    }
  }
  
  // 更新全局数据的方法
  updateGlobalData(key, value) {
    this.globalData[key] = value
    
    // 同步到本地缓存
    Taro.setStorageSync('appConfig', this.globalData)
  }
  
  // ... 其他代码
}

组件中完整使用

// components/novelPlugin/fullScreen/index.js
const novelPlugin = requirePlugin('novel-plugin')

Component({
  properties: {
    novelManagerId: Number,
    bookId: String,
    chapterIndex: Number,
    ext: String,
  },

  data: {
    recommendList: [],
    i18n: {},
    isVip: false,
  },

  lifetimes: {
    attached() {
      // 获取 App 全局数据
      const app = getApp()
      const { 
        userInfo, 
        vipLevel, 
        adConfig, 
        language, 
        translations 
      } = app.globalData
      
      console.log('全局配置:', {
        userInfo,
        vipLevel,
        adConfig,
        language
      })
      
      // 检查广告是否启用
      if (!adConfig.enabled) {
        console.log('广告已禁用')
        this.handleClose()
        return
      }
      
      // 检查用户 VIP 等级
      const isVip = !!userInfo && vipLevel > 0
      this.setData({ isVip, i18n: translations[language] })
      
      // 根据 VIP 等级加载不同内容
      if (isVip) {
        this.loadVipContent(vipLevel)
      } else {
        this.loadNormalContent()
      }
      
      // 解析 ext 参数
      this.parseExtParams()
      
      // 上报展示数据
      this.reportImpression({
        userId: userInfo?.id,
        isVip,
        vipLevel,
        chapterIndex: this.properties.chapterIndex
      })
    },
  },

  methods: {
    loadVipContent(vipLevel) {
      // VIP 专属内容
      const vipBooks = [
        {
          id: 'vip-1',
          title: 'VIP 专享书籍 1',
          description: '仅限 VIP 阅读',
          coverUrl: 'https://example.com/vip1.jpg'
        }
      ]
      
      this.setData({ recommendList: vipBooks })
    },
    
    loadNormalContent() {
      // 普通内容
      const normalBooks = [
        {
          id: 'normal-1',
          title: '热门推荐 1',
          description: '大家都在看',
          coverUrl: 'https://example.com/normal1.jpg'
        }
      ]
      
      this.setData({ recommendList: normalBooks })
    },
    
    parseExtParams() {
      if (this.properties.ext) {
        try {
          const extData = JSON.parse(this.properties.ext)
          if (extData.recommendList) {
            this.setData({ recommendList: extData.recommendList })
          }
        } catch (e) {
          console.error('解析 ext 失败:', e)
        }
      }
    },
    
    reportImpression(data) {
      // 上报展示数据到后台
      console.log('上报展示:', data)
    },
    
    handleClose() {
      const novelManager = novelPlugin.getNovelManager(this.properties.novelManagerId)
      if (novelManager) {
        novelManager.setFullScreenComponentStatus({ show: false })
      }
    }
  }
})

⚠️ 注意事项

1. getApp() 的时机

// ✅ 正确:在 lifetimes 中使用
lifetimes: {
  attached() {
    const app = getApp()
    console.log(app.globalData)
  }
}

// ❌ 错误:在 properties 定义时使用
Component({
  properties: {
    test: getApp().globalData.test  // 此时可能无法获取
  }
})

2. 数据同步问题

// app.tsx
class App extends Component {
  globalData = {
    count: 0
  }
  
  // 提供更新方法
  updateCount(newCount) {
    this.globalData.count = newCount
  }
}

// 组件中
attached() {
  const app = getApp()
  console.log('初始值:', app.globalData.count)
  
  // 注意:组件中的数据不会自动更新
  // 需要在合适的时机重新获取
}

3. 类型安全(TypeScript)

// types/global.d.ts
declare interface CustomApp {
  globalData: {
    isShow: boolean
    customParams: any
    userInfo: UserInfo | null
    vipLevel: number
    // ... 其他字段
  }
}

// 组件中使用
const app = getApp<CustomApp>()
console.log(app.globalData.isShow) // 有类型提示

📊 最佳实践

1. 集中管理配置

// config/global.ts
export default {
  adConfig: {
    enabled: true,
    frequency: 5
  },
  vipConfig: {
    levels: [1, 2, 3, 4, 5],
    benefits: ['专属内容', '去广告', '折扣']
  }
}

// app.tsx
import globalConfig from './config/global'

class App extends Component {
  globalData = globalConfig
}

2. 提供 getter/setter

class App extends Component {
  globalData = {
    isShow: true
  }
  
  // 提供访问方法
  getIsShow() {
    return this.globalData.isShow
  }
  
  setIsShow(value: boolean) {
    this.globalData.isShow = value
    // 触发更新逻辑
    this.notifyComponents()
  }
}

3. 监听变化

// 组件中监听全局数据变化
attached() {
  const app = getApp()
  
  // 定期检查或使用事件监听
  setInterval(() => {
    if (app.globalData.isShow !== this.lastIsShow) {
      this.lastIsShow = app.globalData.isShow
      this.handleIsShowChange(app.globalData.isShow)
    }
  }, 1000)
}

🔗 相关文档