最新要闻
- 当猛男遇上脱毛仪:用前抗拒、用后真香
- 终身质保成笑话?女车主购入威马新车三年维保无配件
- Win11不支持拖动任务栏 强行修改注册表后:画面尴尬了
- 快播:爱吃辣的人不容易得糖尿病?是真的吗?
- 天天观焦点:你的护照又升值了!我国与马尔代夫互免签生效 浏览量暴增200%
- 环球时讯:凌云B股(900957)3月8日主力资金净卖出558.00元
- 今日聚焦!锐龙7000无缘单条48GB DDR5内存!点亮后却无法启动
- 每日热门:卖断货!湖北最强汽车补贴火了 有人“从业十年没见过”
- 每日热门:4.5级后广东河源再次发生3.4级地震:官方科普地震来了怎么办
- 全球观察:全年出货量仅2.6亿 PC电脑透心凉:复苏要等Win12
- 全球通讯!ChatGPT版佛祖爆火出圈:施主、说出你的烦恼
- 全球速看:平板电脑怎么连接wifi
- 8元保号没了!中国移动广东出手:最便宜4G套餐撤掉 同步下架5G全家享套餐
- 319元 小米米家智能直流变频塔扇2上市:吹一夏天电费仅0.65元
- 快看点丨燃油、纯电、混动:买轻卡你会选择谁?
- 柳宗元最著名的十首诗是什么?柳宗元在柳州的故事
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
每日报道:qiankun 的使用
qiankun 的使用
1.前言
许多项目搭建的方法不一致,故qiankun改造的方式也不一致,但是从目前的情况看,基本的步骤和些思路还是大抵相同,在改造中遇到的最多问题就是 路径不一致、配置的代理不正确、跨域等,后面有问题也优先往这方面靠近。
参考文档:
乾坤官网:https://qiankun.umijs.org/zh
vite vue3配置:https://www.cnblogs.com/Mr-Rshare/p/16571760.html
(相关资料图)
angular 配置:https://www.cnblogs.com/wangyongping/p/16788537.html
2.主应用
vue2 (公司平台)
这里的配置完全可以参考乾坤官网上来配置,这里我用公司平台举例:
如果子应用存在angular那么首先要安装 zone.js,不用的话就不用安装。
npm i zong.jsnpm i qiankun
修改路由 ,在路由表的根部添加要配置的子应用路径:如flink,后面的*号一定要有。
# src/common/router/index.jsexport const constantRouterMap = [ { path: "/license", component: LicenseComponent, hidden: true }, +{ + path: "/flink/*", + component: componentsObj.Layout + }, { path: "*", component: NotFoundComponent, hidden: true }, // ...];export default new Router({ mode: "history", routes: constantRouterMap});
在要渲染子应用的地方添加id容器
# src/common/views/layout/components/AppMain.vue // ... + // ...
设置qiankun的启动
# src/common/views/layout/Layout.vue+ import { start } from "qiankun";export default { mounted() { + start(); }, methods: { }};</script>
设置qiankun的基础配置,如果有anglue项目需要引入zone.js
# src/common/config/sys.jsimport "zone.js"; // 如果有anglue项目,一定要在qiankun的前面引入import { registerMicroApps,} from "qiankun";...registerMicroApps( [ { name: "flink_web", entry: "//localhost:4200", container: "#appContainer", activeRule: "/flink" }, // { // name: "datainsight", // entry: "//localhost:5002", // container: "#appContainer", // activeRule: "/datainsight" // } ], { beforeLoad: [ app => { // console.log("before load", app); } ], beforeMount: [ app => { // console.log("before mount", app); } ], afterUnmount: [ app => { // console.log("after unload", app); } ] } // { // fetch: request // });...
配置代理 ,这里路径一定要正确,后面报错的话不好定位到这里
# setting.js"/api/flinkdashbaord/*": { target: "http://flink.com/api/flinkdashbaord", // 本地测试环境 logLevel: "debug", changeOrigin: true, autoRewrite: true, cookieDomainRewrite: true, pathRewrite: { "^/api/flinkdashbaord": "" } },
3.微应用
vue3 + vite
因为官网里面没有提供方法,且不支持vite, 所以需要在引入一个包,在子应用
npm i vite-plugin-qiankun
在改造后发现路由不匹配的问题,后经过测试发现是history没有在离开时销毁造成,所以要 history.destroy();
修改路由,这里简写,并把路由返回的方式
# src/router/index.tsimport { createRouter } from "vue-router"import routes from "./routes"...let routerIn:any=nullfunction setRouter(history: any) { routerIn = createRouter({ history, routes }) ... return routerIn}export {setRouter, routerIn as router}
修改主配置,引入插件 vite-plugin-qiankun
# src/main.ts import {createApp} from "vue"import App from "./App"import {QiankunProps, qiankunWindow, renderWithQiankun} from "vite-plugin-qiankun/dist/helper"import {setRouter} from "@/router";import {createWebHistory} from "vue-router";let app:any = null;let routerIn: any = nulllet historyIn: any = nullfunction render(props:any) { historyIn = createWebHistory( qiankunWindow.__POWERED_BY_QIANKUN__? "/dolphinscheduler/":(import.meta.env.MODE === "production" ? "/dolphinscheduler/" : "/") ) routerIn = setRouter(historyIn) const { container } = props; app = createApp(App); app.use(routerIn); app.mount(container ? container.querySelector("#dolphinschedulerApp"): "#dolphinschedulerApp");}renderWithQiankun({ mount(_props) { render(_props); }, bootstrap() { console.log("bootstrap"); }, unmount(_props: any) { app.unmount(); app = null; routerIn= null; historyIn.destroy(); }, update: function (props: QiankunProps): void | Promise { console.log("update"); }});if (!qiankunWindow.__POWERED_BY_QIANKUN__) { render({container:""});}
修改 vite配置 ,因为vite 不支持qiankun 使用插件后,打包时候要提前配置好 base
# vite.config.ts import {defineConfig, } from "vite"+ import qiankun from "vite-plugin-qiankun"+ const { name } = require("./package.json");export default defineConfig({ base: "http://dolphinscheduler.com/", // base: process.env.NODE_ENV === "production" ? "/dolphinscheduler/" : "/", plugins: [ + qiankun(name, { + useDevMode: true, + }), ... ], ... server: { + headers: { + "Access-Control-Allow-Origin": "*", + }, proxy: { "^/api/inner/dolphinscheduler": { target: loadEnv("development", "./").VITE_APP_DEV_WEB_URL, changeOrigin: true } } }})
angular12 + single-spa
angular整体结构有所不同,这里的项目有用到 single-spa 才可以,执行命令
npm i single-spa -Sng add single-spa-angular
执行完后,项目的一部分路径文件也会有所变化,创建 public-path.js 文件,在 main.single-spa.ts 内最上面引入
# public-path.js if (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}
修改入口文件
# main.single-spa.tsimport "./public-path";import { enableProdMode, NgZone } from "@angular/core";import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";import { Router } from "@angular/router";import { singleSpaAngular, getSingleSpaExtraProviders } from "single-spa-angular";import { AppModule } from "./app/app.module";import { environment } from "./environments/environment";import { singleSpaPropsSubject } from "./single-spa/single-spa-props";if (environment.production) { enableProdMode();}// enableProdMode();// 微应用单独启动时运行if (!(window as any).__POWERED_BY_QIANKUN__) { platformBrowserDynamic() .bootstrapModule(AppModule) .catch(err => console.error(err));}const lifecycles = singleSpaAngular({ bootstrapFunction: singleSpaProps => { singleSpaPropsSubject.next(singleSpaProps); return platformBrowserDynamic(getSingleSpaExtraProviders()).bootstrapModule(AppModule); }, template: " ", Router, NgZone: NgZone});export const bootstrap = lifecycles.bootstrap;export const mount = lifecycles.mount;export const unmount = lifecycles.unmount;
控制zone.js 的引入,确保本地和qiankun都能引入
# index.htmlhead标签添加<script src="https://unpkg.com/zone.js" ignore></script>
# polyfills.ts// import "zone.js 把这里引入注释掉
修改路由的配置
# app-routing.module.ts+ import { APP_BASE_HREF } from "@angular/common";@NgModule({ exports: [RouterModule], imports: [RouterModule.forRoot(routes)], + providers: [{ provide: APP_BASE_HREF, useValue: (window as any).__POWERED_BY_QIANKUN__ ? "/flink/" : "/" }]})
修改angular配置文件
# extra-webpack.config.jsconst singleSpaAngularWebpack = require("single-spa-angular/lib/webpack").default;const {merge } = require("webpack-merge");const appName = require("./package.json").name;module.exports = (config, options) => { const singleSpaWebpackConfig = singleSpaAngularWebpack(config, options); const singleSpaConfig = { devServer: { headers: { "Access-Control-Allow-Origin": "*", }, }, output: { library: `${appName}-[name]`, libraryTarget: "umd", }, externals: { "zone.js": "Zone", }, }; const mergedConfig = merge ( singleSpaWebpackConfig, singleSpaConfig ); return mergedConfig;};
如果还有其它报错,基本上是路径匹配,端口NaN等造成
react16.8
一部分的引入的方式可参考官网,可能项目不同,webpack的引入方式不正确,需要单独处理。
修改打包配置文件
# internals/webpack/webpack.prod.babel.jsmodule.exports = require("./webpack.base.babel")({ mode: "production", output: { // filename: "[name].[chunkhash].js", // chunkFilename: "[name].[chunkhash].chunk.js" + library: `datainsight`, + filename: `[name].${timeStamp}.js`, + libraryTarget: "umd", jsonpFunction: `webpackJsonp_${name}` }, ...})
修改引入
# app/app.tsxif (window.__POWERED_BY_QIANKUN__) { __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__}import React from "react"import ReactDOM from "react-dom"import { translationMessages } from "./i18n"...const MOUNT_NODE = document.getElementById("datainsightApp")const render = (messages, props) => { const { container } = props ReactDOM.render( , container ? container.querySelector("#datainsightApp") : MOUNT_NODE )}if (!window.__POWERED_BY_QIANKUN__) { if (module.hot) { module.hot.accept(["./i18n", "containers/App"], () => { ReactDOM.unmountComponentAtNode(MOUNT_NODE) render(translationMessages, {}) }) } else { render(translationMessages, {}) }}export async function bootstrap() { console.log("react app bootstraped")}export async function mount(props) { await render(translationMessages, props)}export async function unmount(props) { const { container } = props; await ReactDOM.unmountComponentAtNode(container ? container.querySelector("#datainsightApp") : MOUNT_NODE)}if (process.env.NODE_ENV === "production") { // disable react developer tools in production if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { window.__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = () => void 0 }}
修改路由
# app/containers/App/index.tsx... public render() { const __qiankun__ = window.__POWERED_BY_QIANKUN__ return ( {/*basename={"/datainsight"} basename={__qiankun__ ? "/datainsight" : "/"}*/} ) }...
vue2
这里不做详细介绍,参考官网
https://qiankun.umijs.org/zh/guide/tutorial#vue-%E5%BE%AE%E5%BA%94%E7%94%A8
4.nginx配置
qiankun 官网:
https://qiankun.umijs.org/zh/cookbook#%E5%9C%BA%E6%99%AF-2%E4%B8%BB%E5%BA%94%E7%94%A8%E5%92%8C%E5%BE%AE%E5%BA%94%E7%94%A8%E9%83%A8%E7%BD%B2%E5%9C%A8%E4%B8%8D%E5%90%8C%E7%9A%84%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%BD%BF%E7%94%A8-nginx-%E4%BB%A3%E7%90%86%E8%AE%BF%E9%97%AE
通用方式
线上采用同一个服务器,不同的端口实现
server { listen 86; server_name localhost; location / { root /aTinyApp/appbase; index index.html index.htm; try_files $uri $uri/ /index.html; } location /applims { proxy_pass http://localhost:88/; proxy_set_header Host $host:$server_port; } location /appcost { proxy_pass http://localhost:89/; proxy_set_header Host $host:$server_port; } location /api/ { proxy_pass http://gateway/; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 300; client_max_body_size 1024m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 88; server_name localhost; location / { root /aTinyApp/applims; index index.html index.htm; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://gateway/; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 300; client_max_body_size 1024m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } server { listen 89; server_name localhost; location / { root /aTinyApp/appcost; index index.html index.htm; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://gateway/; proxy_set_header X-Real-IP $remote_addr; proxy_read_timeout 300; client_max_body_size 1024m; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
本地需要考虑到跨域等因素,做相应处理
server { listen 80; server_name flink.com; #access_log logs/host.access.log main; location / { root D:/baseServer/app/flink; index index.html index.htm; try_files $uri $uri/ /index.html; # 允许 所有头部 所有方法 域 add_header "Access-Control-Allow-Headers" "*"; add_header "Access-Control-Allow-Methods" "*"; add_header "Access-Control-Allow-Origin" "$http_origin"; add_header "Access-Control-Allow-Credentials" "true"; } location /api/ { proxy_pass http://172.18.50.187; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
同一域名下部署
多数也是参照乾坤的例子
主应用配置
egisterMicroApps( [ { name: "flink-dashboard", entry: "/child/flinkdashboard/", // 重点 container: "#appContainer", activeRule: "/flinkdashboard" // 重点 }, { name: "dolphinscheduler", entry: "/child/dolphinscheduler/", // 重点 container: "#appContainer", activeRule: "/dolphinscheduler" // 重点 }, ],
子应用history配置
historyIn = createWebHistory( qiankunWindow.__POWERED_BY_QIANKUN__? "/dolphinscheduler/":"/child/dolphinscheduler/")
子应用跟路径 配置
base:"/child/dolphinscheduler/"
服务器目录
└── app/ # 根文件夹 | ├── child/ # 存放所有微应用的文件夹 | ├── flinkdashboard/ // flinkdashboard | ├── dolphinscheduler/ // dolphinscheduler ├── index.html # 主应用的index.html ├── css/ # 主应用的css文件夹 ├── js/ # 主应用的js文件夹
nginx配置
server { listen 80; server_name app.com; #access_log logs/host.access.log main; location / { root D:/baseServer/app; index index.html index.htm; try_files $uri $uri/ /index.html; } location /child/flinkdashboard { root D:/baseServer/app; index index.html index.htm; try_files $uri $uri/ /child/flinkdashboard/index.html; } location /child/dolphinscheduler { root D:/baseServer/app; index index.html index.htm; try_files $uri $uri/ /child/dolphinscheduler/index.html; } location /api/ { proxy_pass http://172.18.50.187; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } }
配置成功后,主应用访问地址不变,单独访问子应用只需要加上 http://xxx.com/child/zi/ 即可。
5.常见问题
多数问题qiankun已经整合,可以从中作为参考:
https://qiankun.umijs.org/zh/faq
a. 如果安装了zone.js 在项目运行中,可能有不相关问题也会发出报错提示,不是angular项目时候可以先关掉引用,方便快速定位问题
b. 项目部署后,vite项目与其他项目切换中,发现路径回退,可能是vite项目的history没有销毁,在乾坤生命周期中销毁。
c. angular项目在执行完 ng add single-spa-angular 后,可能会遇到,端口变成NaN问题,路径不匹配的问题
// 报路径错的时候修改这里# tsconfig.app.json"files":["main.single-spa.ts"]// 端口要一致# angular.json"projects"->"flink"->"architect"->"build"->"options"->"deployUrl":"/""projects"->"flink"->"architect"->"serve"->"options"->"deployUrl":"http://localhost:4200/"
d. 任何项目部署后运行,刷新后子应用变成主应用消失,可以先检查主应用的entry和activeRule是不是配置成一样的了
e. angular项目有一个跟路径:
当出现白屏,路径不匹配,配置了好几种方案都不成功的时候,可以尝试将其注释掉。
f. 目前在vite 和vue3的项目上遇到一个问题,配置都正确,但是访问二级微应用的子路由的时候,将整个页面都渲染成白屏,后改路径等匹配规则都不成功,最后使用的hash 路由模式得以解决,如果要继续使用history 模式,可以尝试从子应用上检查,现在已经定位到是子应用路由渲染上有影响,具体原因还在查找。
。。。
后续待补充
关键词:
每日报道:qiankun 的使用
当前热议!Linux常用的20个命令(下)
【天天播资讯】Linux网卡驱动程序
讯息:(数据库系统概论|王珊)第十一章并发控制-第一节:并发控制概述
【环球速看料】如何轻松学习网页设计和网页编程?
当猛男遇上脱毛仪:用前抗拒、用后真香
终身质保成笑话?女车主购入威马新车三年维保无配件
Win11不支持拖动任务栏 强行修改注册表后:画面尴尬了
快播:爱吃辣的人不容易得糖尿病?是真的吗?
天天观焦点:你的护照又升值了!我国与马尔代夫互免签生效 浏览量暴增200%
环球时讯:凌云B股(900957)3月8日主力资金净卖出558.00元
全球观察:跨境电商卖家如何应对拒付、盗卡
热推荐:前端设计模式——观察者模式
热消息:代码审计之旅之百家CMS
环球头条:Paxos算法理解与java实现
环球消息!5、Redis慢日志和key有效期
今日聚焦!锐龙7000无缘单条48GB DDR5内存!点亮后却无法启动
每日热门:卖断货!湖北最强汽车补贴火了 有人“从业十年没见过”
每日热门:4.5级后广东河源再次发生3.4级地震:官方科普地震来了怎么办
全球观察:全年出货量仅2.6亿 PC电脑透心凉:复苏要等Win12
全球通讯!ChatGPT版佛祖爆火出圈:施主、说出你的烦恼
GO语言学习笔记-数据篇 Study for Go ! Chapter four - Data
全球速读:Go 数据结构
精彩看点:如何搞定MySQL锁(全局锁、表级锁、行级锁)?这篇文章告诉你答案!太TMD详细了!!!
最新资讯:vue组件更新引起组件更新的原因,如何引发组件的更新
播报:【JavaScript UI库和框架】上海道宁与Webix为您提供用于跨平台Web应用程序开发的JS框架及UI小部件
全球速看:平板电脑怎么连接wifi
8元保号没了!中国移动广东出手:最便宜4G套餐撤掉 同步下架5G全家享套餐
319元 小米米家智能直流变频塔扇2上市:吹一夏天电费仅0.65元
快看点丨燃油、纯电、混动:买轻卡你会选择谁?
柳宗元最著名的十首诗是什么?柳宗元在柳州的故事
天天通讯!基德谈欧文末节独砍17分:这就是他 他喜欢帮助他的球队赢球
天天微速讯:3张思维导图读懂 《钢铁是怎样炼成的》
VUE定时器任务(每天12点执行)
信息:mysql invalid conn排查
全球观速讯丨CNStack 多集群服务:基于 OCM 打造完善的集群管理能力
即时看!关于docker中-容器的管理操作-删除
韩国西江大学留学条件和费用是什么?韩国西江大学怎么样?
代课老师的养老保险什么时候启动?代课教师养老保险政策有哪些?
焦点热门:可抵抖音干半年!TVB淘宝直播间首播销售额达2350万
全球看点:一年脱轨1000次!美国俄亥俄州再发生铁路事故 卡车撞上火车
满满正能量!小学生拾得价值16万黄金后续:物归原主、获助学礼包
向残疾熊猫福菀泼水3游客身份未确定:初步断定为3女娃
一键开盖 耐热抗摔:哈尔斯Tritan材质单手开盖水杯15.9元发车
光棍节的由来和含义是什么?光棍节活动策划书
办公室副主任是什么级别?办公室副主任年度述职报告
手机厂商钟情的黄色配色 原来诺基亚十年前就有了
大小仅3.7GB:大佬基于Win10魔改经典WinXP系统
每日快报!为眼睛降低ISO感光度!万新偏光太阳镜大促:39.4到手 原价139元
焦点速递!跑车底盘+大电池!开了两天哪吒S 想把我的油车卖了
行走的27寸超大平板!小度推出添添闺蜜机 首发4999元
win7电脑怎么开启telnet命令?telnet命令的作用是什么?
暖暖环游世界怎么看收集度?暖暖环游世界兑换码2023
Win10系统怎么安装杜比音效驱动?杜比音效和普通音效有什么区别
中兴天机7哪个版本音质最好?中兴天机7手机参数
iphone怎么设置勿扰模式?iphone灵动岛怎么养宠物?
Liunx Vim常用命令
天天看点:C++笔记--控制语句
Windows 11提示“无法枚举容器中的对象。”
环球速读:A股异动 | 上海电影涨7% 拟收购上影元文化51%股权 拓展IP运营业务
视讯!国产CPU龙芯3A6000上半年流片明年出货 已评估7nm工艺
泰国电动车市场被国产车包了!2月销量哪吒、比亚迪双霸榜
5499元 华硕无畏15i轻薄本开卖:12核i5、2.8K 120Hz OLED好屏
不得杀疯了?曝比亚迪海鸥4月上市:仅6.58万起
世界快消息!苹果等级森严:标准版iPhone 15将不支持全天候显示功能
【世界速看料】无穷大符号
Spring Boot + MybatisX = 王炸!!
每日消息!(数据库系统概论|王珊)第十章数据库恢复技术:习题
焦点速读:前端设计模式——发布订阅模式
微资讯!《寂静岭2:重制版》新版护士形象曝光!身材依旧火辣
今热点:苹果、谷歌抢市场 Windows份额创美国史低:绝对垄断没了
NVIDIA紧急推送531.26修复补丁:解决N卡CPU占用异常问题
2月销量3863台 长安马自达CX-50本月下线:还能救市吗?
24岁高颜值女孩回应大学毕业养猪:父母支持 年薪10万
世界热讯:一次惨痛教训让我写了个Windows定期备份文件脚本
天天微速讯:模块简介、模块的两种导入语句、导入文件的补充、判断文件类型、模块的查找顺序
全球热点!自动化离线交付在云原生的应用和思考
今日要闻!Python常见面试题009. 元组和列表有什么区别
每日速递:地图标准先行 自动驾驶识途
大疆发布Ronin 4D Flex分体拓展系统:手持重量仅1/3 实现运镜自由
环球速看:你真离不开苹果!全球最畅销手机Top 10:iPhone无敌 安卓阵营被摩擦
全球热讯:落后中国几十年!H3运载火箭发射失败自毁 日本首相社交平台谢罪
环球新消息丨妇女节快乐!《中国妇女报》:妇女节不是什么女神节 不放假有加班费吗?
当前消息!12万就有自动上电 埃安AION Y Younger上市:续航430km
世界看热讯:江苏一男子醉驾用脚刹车 竟然“刹”住了
世界速读:苹果推出黄色款iPhone 14:对比小米13飓风黄 哪个好看?
15万特斯拉要来了!马斯克自曝新车:成本降50% 自动驾驶
成人教育大专
焦点短讯!读Java性能权威指南(第2版)笔记10_原生内存
我国多地取消中考男女生长跑 800米对健康不利:教育部喊话不得停止体育教学
强烈建议收藏,python库大全
js数据类型判断、unll和undefined
全球通讯!女足来了!FIFA23将加入15个女足联赛
李杰:一加最擅长做旗舰 同等价格段我们能提供最优秀产品
景区回应瀑布源头是水管放水:看破不说破 不要在意细节
全球速递!《阿凡达2》宣布3月28日上线数字平台:收录3小时额外内容
在网上口述一生:86岁老奶奶成了年轻人的“偶像”
世界速读:埃及出土古罗马时期笑脸迷你版狮身人面像:脸颊还有酒窝
“90后”小伙画下长江泸州段!目标是画遍中国
全球热推荐:那年夏天 电影