微信小程序> 微信小程序组件-微信小程序自定义组件的使用,来自项目的总结-小程序ui

微信小程序组件-微信小程序自定义组件的使用,来自项目的总结-小程序ui

浏览量:1803 时间: 来源:仇益阳
小程序自定义组件的使用

1.一直以来忙项目都没有什么时间来写博客,今天晚上刷了会儿csdn,知乎等平台,发现有很多人再问小程序自定义组件怎么写,如何编写一个自己的自定义组件?当然也有一些同行们对于这些问题都有解答。

2.今天就自己的项目经验给大家从构建自定义组件,调用自定义组件,传值给组件,组件传值出来,给大家讲解一下如何构造一个自定义视频组件

3.大家可能都刷过火山小视频,本次讲解的就是做的一款类似于火山小视频的视频播放效果的一款小程序软件,效果如下图所示

4.这个项目因为要用到视频播放这个功能,于是就用了小程序的video媒体播放。废话不多说,直接进入正题吧,首先微信小程序自定义组件出来这么长时间了,于是我在写这个项目的时候就行运用一下自定义组件,看了一下官方文档,官方文档有一些介绍但是都不怎么全,于是我就实验了一把,在这个项目中自定义了一个视频播放组件

要自定义一个组件,首先要新建一个文件夹,如图所示,我建了一个名为Component的文件夹在文件夹里点击右键新建了一个Component名为‘AuglyVideo’的自定义组件,组件的组成跟正常的页面文件接口一样。这是AuglyVideo.wxml文件viewclass='videoItem'wx:for="{{videoList}}"videoobjectFit='fill'show-center-play-btn='{{showPlay}}'id='myVideo{{item.id}}'data-index="{{index}}"src='{{item.videoUrl}}'wx:if="{{playIndex==index}}"/videoviewclass='myposter'bindtap="videoPlay"id="{{item.id}}"data-index="{{index}}"style="display:{{playIndex==index?'none':'block'}};"data-id='{{item.id}}'data-title='{{item.title}}'data-cover='{{item.cover}}'data-duration='{{item.duration}}'data-allnum="{{item.palyCnt+item.playInitCnt}}"imagesrc='{{item.cover}}'/imageformbindsubmit="submitInfo"report-submit='true'buttonclass='videoTitle'hover-class='none'form-type='submit'{{item.title}}/button/formformbindsubmit="submitInfo"report-submit='true'buttonclass='iconfonticon-bofang'hover-class='none'id="{{item.id}}"data-index="{{index}}"form-type='submit'/button/formviewclass='time'{{item.duration}}/view/viewviewclass='videoRes'viewclass='playnum'{{item.palyCnt+item.playInitCnt}}次播放/viewbuttonclass='iconfonticon-zhuanfa'hover-class='none'open-type='share'data-id='{{item.id}}'data-title='{{item.title}}'data-cover='{{item.cover}}'data-duration='{{item.duration}}'data-allnum="{{item.palyCnt+item.playInitCnt}}"/button/view/viewformbindsubmit="submitInfo"report-submit='true'wx:if="{{aps.isShow=='t'}}"navigatorclass='tominApp'hover-class='none'form-type='submit'style="background-image:url('{{aps.image}}');"open-type="navigate"target="miniProgram"app-id='{{aps.val}}'/navigator/form

5.这是wxss文件

/*Component/AuglyVideo.wxss*/@font-face{font-family:'iconfont';/*projectid724078*/src:url('//at.alicdn.com/t/font_724078_43qt7yvrrsk.eot');src:url('//at.alicdn.com/t/font_724078_43qt7yvrrsk.eot?#iefix')format('embedded-opentype'),url('//at.alicdn.com/t/font_724078_43qt7yvrrsk.woff')format('woff'),url('//at.alicdn.com/t/font_724078_43qt7yvrrsk.ttf')format('truetype'),url('//at.alicdn.com/t/font_724078_43qt7yvrrsk.svg#iconfont')format('svg');}.iconfont{font-family:"iconfont"!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;}.icon-bofang:before{content:"e606";}.icon-zhuanfa:before{content:"e627";}.videoItem{width:100%;height:auto;border-radius:0rpx0rpx10rpx10rpx;overflow:hidden;margin-top:20rpx;}.videoItemvideo{width:100%;height:398rpx;border-radius:10rpx10rpx0rpx0rpx;display:flex;align-items:center;justify-content:center;overflow:hidden;}.videoItem.myposter{width:100%;height:398rpx;/*border-radius:10rpx10rpx0rpx0rpx;*/position:relative;box-sizing:border-box;background-color:rgba(0,0,0,0.5);background-size:100%100%;}.videoItemimage{width:100%;height:100%;position:absolute;top:0;z-index:-1;/*border:10rpx10rpx0rpx0rpx;*/}.videoTitle{position:absolute;left:0rpx;width:100%;height:100rpx;font-size:34rpx;font-weight:bold;top:0rpx;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;padding:0rpx20rpx;background:linear-gradient(rgba(0,0,0,0.2),rgba(0,0,0,0));color:RGBA(254,254,254,0.9);}.icon-bofang{color:rgba(255,255,255,1);font-size:80rpx;line-height:80rpx;z-index:5;position:absolute;display:block;left:50%;margin-left:-40rpx;top:50%;margin-top:-40rpx;}.tominApp{position:fixed;width:103rpx;height:103rpx;background-color:rgba(255,255,255,1);border-radius:50%;display:flex;box-sizing:border-box;padding:18rpx;align-items:center;flex-wrap:wrap;justify-content:center;right:33rpx;bottom:240rpx;white-space:wrap;color:rgba(0,0,0,1);font-size:30rpx;line-height:35rpx;background-size:100%100%;}.time{position:absolute;width:112rpx;height:45rpx;background-color:rgba(0,0,0,0.5);right:11rpx;bottom:10rpx;font-size:28rpx;color:rgba(255,255,255,1);display:flex;align-items:center;justify-content:center;border-radius:22rpx;}.videoItem.videoRes{width:100%;height:81rpx;background-color:RGBA(46,39,67,1);box-sizing:border-box;padding:0rpx20rpx;display:flex;align-items:center;justify-content:space-between;}.playnum{font-size:28rpx;color:RGBA(215,215,215,1);}.icon-zhuanfa{color:rgba(255,255,255,1);font-size:40rpx;}

6.这是js文件

//Component/AuglyVideo.jsconstconfig=require('../utils/config.js')letapp=getApp();Component({/***组件的属性列表*/properties:{videoList:{type:Array,value:[]},aps:{type:Object,value:{isShow:null}},playIndex:{type:null,value:null},page:{type:String,value:'index'}},/***组件的初始数据*/data:{playIndex:null,showPlay:false,showShare:true},created:function(){console.log(this.data.aps)},/***组件的方法列表*/methods:{//播放视频相关方法videoPlay:function(e){//if(this.data.page=='share'){varvideoList=this.data.videoListvarindex=e.currentTarget.dataset.indexvarid=e.currentTarget.idconfig.ajax('POST',{id:id},config.videoPlay,(res)={if(res.data.statusMsg=="success"){videoList[index].videoUrl=res.data.dataif(!this.data.playIndex){//没有播放时播放视频this.setData({videoList:videoList,playIndex:index,playmid:id})varvideoContext=wx.createVideoContext('myVideo'+id,this)videoContext.play()}else{//有播放时先将prev暂停到0s,再播放当前点击的currentvarvideoContextPrev=wx.createVideoContext('myVideo'+this.data.playmid,this)videoContextPrev.seek(0)videoContextPrev.pause()this.setData({videoList:videoList,playIndex:index,playmid:id})varvideoContextCurrent=wx.createVideoContext('myVideo'+this.data.playmid,this)videoContextCurrent.play()}varmyEventDetail={playIndex:this.data.playIndex,playmid:this.data.playmid,videoContextCurrent:videoContextCurrent,videoContext:videoContext}//detail对象,提供给事件监听函数varmyEventOption={}//触发事件的选项this.triggerEvent('videoPlay',myEventDetail,myEventOption)}},(res)={})//}else{//varalldata={//id:e.currentTarget.dataset.id,//title:e.currentTarget.dataset.title,//cover:e.currentTarget.dataset.cover,//duration:e.currentTarget.dataset.duration,//allnum:e.currentTarget.dataset.allnum//}//wx.redirectTo({//url:'/pages/share/share?alldata='+JSON.stringify(alldata),//success:function(res){//},//fail:function(res){},//complete:function(res){},//})//}},submitInfo(e){if(app.globalData.isSubscibe){varparams={openId:app.globalData.openid,formId:e.detail.formId,status:'t'}}else{varparams={openId:app.globalData.openid,formId:e.detail.formId}}config.ajax('POST',params,config.wxformId,(res)={console.log(res)app.globalData.isSubscibe=true},(res)={})}}})

7.json文件

{"component":true,"usingComponents":{}}

8.wxml和wxss在这里就不做讲解了,都是小程序最基本的东西,着重给大家讲一下自定义组件的js文件当我们新建一个组件Component的时候,会自动生成4个文件,在新建的js文件里

properties:{videoList:{type:Array,value:[]},aps:{type:Object,value:{isShow:null}},playIndex:{type:null,value:null},page:{type:String,value:'index'}},

9.定义的是自定义组件的一些属性,效果同data是一样的,但是这个在对组件传值时有很大帮助

/***组件的初始数据*/data:{playIndex:null,showPlay:false,showShare:true},

10.这里是data数据组件也和page一样有生命周期函数这里就不做详细解释,官方文档里面都有组件有一个组件方法对象,如下所示

/***组件的方法列表*/methods:{//播放视频相关方法videoPlay:function(e){//if(this.data.page=='share'){varvideoList=this.data.videoListvarindex=e.currentTarget.dataset.indexvarid=e.currentTarget.idconfig.ajax('POST',{id:id},config.videoPlay,(res)={if(res.data.statusMsg=="success"){videoList[index].videoUrl=res.data.dataif(!this.data.playIndex){//没有播放时播放视频this.setData({videoList:videoList,playIndex:index,playmid:id})varvideoContext=wx.createVideoContext('myVideo'+id,this)videoContext.play()}else{//有播放时先将prev暂停到0s,再播放当前点击的currentvarvideoContextPrev=wx.createVideoContext('myVideo'+this.data.playmid,this)videoContextPrev.seek(0)videoContextPrev.pause()this.setData({videoList:videoList,playIndex:index,playmid:id})varvideoContextCurrent=wx.createVideoContext('myVideo'+this.data.playmid,this)videoContextCurrent.play()}varmyEventDetail={playIndex:this.data.playIndex,playmid:this.data.playmid,videoContextCurrent:videoContextCurrent,videoContext:videoContext}//detail对象,提供给事件监听函数varmyEventOption={}//触发事件的选项this.triggerEvent('videoPlay',myEventDetail,myEventOption)}},(res)={})//}else{//varalldata={//id:e.currentTarget.dataset.id,//title:e.currentTarget.dataset.title,//cover:e.currentTarget.dataset.cover,//duration:e.currentTarget.dataset.duration,//allnum:e.currentTarget.dataset.allnum//}//wx.redirectTo({//url:'/pages/share/share?alldata='+JSON.stringify(alldata),//success:function(res){//},//fail:function(res){},//complete:function(res){},//})//}},submitInfo(e){if(app.globalData.isSubscibe){varparams={openId:app.globalData.openid,formId:e.detail.formId,status:'t'}}else{varparams={openId:app.globalData.openid,formId:e.detail.formId}}config.ajax('POST',params,config.wxformId,(res)={console.log(res)app.globalData.isSubscibe=true},(res)={})}}

11.那么现在的重点来了,组件的wxml,wxss样式文件也有了,组件的方法也有了,那么怎么用组件呢我在首页运用了这个组件,即index,具体如下index.wxml文件

!--pages/index/index.wxml--!--广告位--viewclass='mywrap'/viewviewwx:if="{{mask}}"viewclass='aps'wx:if="{{!isSubscibe}}"viewclass='apsTitle'为你追踪每周热点视频/viewformbindsubmit="submittwo"report-submit='true'buttonclass='apsSure'hover-class='none'form-type='submit'点击订阅/button/form/viewviewclass='pageScroll'style="width:100%;{{isSubscibe?'padding-top:100rpx':''}}"viewclass='hotType'viewclass='hotTitle'每周热搜/viewviewclass='hotScroll'scroll-viewscroll-xstyle="width:100%"scroll-with-animationviewclass='hotyItem'wx:for="{{hotWord}}"style="background-image:url('{{item.bgsrc}}')"bindtap='tolist'data-id='{{item.id}}'data-name='{{item.name}}'data-bg='{{item.Bgsrc}}'data-ph="{{item.ph}}"data-num='{{index+1}}'viewclass='ph'style="background-image:url('{{item.ph}}')"{{index+1}}/viewviewclass='Item_main'#{{item.name}}#/view/view/scroll-view/view/viewviewclass='videoArr'viewclass='hotTitle'热点视频/view!--自定义视频组件--videoGroupid='videoGroup'page="{{page}}"playIndex="{{playIndex}}"videoList="{{videoList}}"aps="{{aps}}"bind:videoPlay="myvideoPlay"/videoGroup/viewviewclass='nodata'wx:if="{{nodata}}"我是有底线的~/viewviewclass='nodata'wx:if="{{!nodata}}"{{moretype}}imagewx:if="{{moretype=='正在加载中~'}}"src="http://daka.wx.bronet.cn/public/myimg/loading.gif"class="Load_icon"/image/view/view/view

12.index.wxss文件

/*pages/index/index.wxss*/page{background-color:RGBA(22,15,46,1);}.mywrap{position:fixed;top:100rpx;bottom:0rpx;width:100%;z-index:-1;background-color:RGBA(22,15,46,1);}.aps{width:100%;height:100rpx;background:linear-gradient(#7c42e6,#9d52e3);box-sizing:border-box;padding:0rpx33rpx;display:flex;align-items:center;justify-content:space-between;position:fixed;top:0;z-index:999;}.apsTitle{font-size:28rpx;color:rgba(255,255,255,1);display:flex;line-height:100rpx;}.apsSure{width:188rpx;height:68rpx;box-sizing:border-box;border:1rpxsolidrgba(255,255,255,1);/*background-color:red;*/border-radius:70rpx;margin:0;padding:0;display:flex;align-items:center;justify-content:center;color:rgba(255,255,255,1);font-size:30rpx;}.hotType{width:100%;height:auto;box-sizing:border-box;padding:0rpx0rpx0rpx30rpx;/*margin-top:50rpx;*/}.hotTitle{font-size:54rpx;font-weight:bold;color:rgba(255,255,255,1);}.hotScroll{position:relative;width:100%;height:auto;margin-top:41rpx;}.hotScrollscroll-view{/*width:100%;*/white-space:nowrap;}.hotyItem{width:326rpx;height:212rpx;border-radius:10rpx;display:inline-block;position:relative;margin-right:20rpx;background-size:100%100%;box-sizing:border-box;padding:0rpx24rpx;}.Item_main{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:34rpx;font-weight:bold;color:rgba(255,255,255,1);}.ph{width:44rpx;height:45rpx;position:absolute;top:0;left:12rpx;background-size:100%100%;font-size:26rpx;color:rgba(255,255,255,1);display:flex;line-height:35rpx;justify-content:center;}.videoArr{width:100%;height:auto;box-sizing:border-box;padding:0rpx30rpx;margin-top:96rpx;overflow:hidden;}.pageScroll{box-sizing:border-box;padding-top:180rpx;}.nodata{height:200rpx;width:100%;display:flex;align-items:center;justify-content:center;font-size:24rpx;color:rgba(255,255,255,1);}.tominApp{position:fixed;width:103rpx;height:103rpx;background-color:rgba(255,255,255,1);border-radius:50%;right:33rpx;bottom:81rpx;}

13.index.js文件

//pages/index/index.jsvarapp=getApp();varpage=1;constconfig=require('../../utils/config.js')Page({/***页面的初始数据*/data:{nodata:false,hotWord:[],videoList:[],playIndex:null,mask:false,isSubscibe:true,page:'index',moretype:'上拉查看更多哦~'},/***生命周期函数--监听页面加载*/onLoad:function(options){varthat=thiswx.login({success:(res)={config.ajax('POST',{wxcode:res.code},config.wxLogin,(res)={app.globalData.openid=res.data.data.openIdconfig.ajax('POST',{openId:res.data.data.openId},config.isSubscibe,(res)={that.setData({isSubscibe:res.data.data})app.globalData.isSubscibe=res.data.data},(res)={})},(res)={})},fail:function(res){},complete:function(res){},})page=1;wx.showLoading({title:'数据加载中...',mask:true,})this.videoGroup=this.selectComponent("#videoGroup");//this.getlistHot()this.getvideoList()this.getHotword()this.getAps()},/***获取热词*/getHotword(){varparams={}config.ajax('POST',params,config.hotWord,(res)={console.log(res.data.data[16])for(vari=0;ires.data.data.length;i++){if((i+4)%4==0){if(res.data.data[i]!=undefined){res.data.data[i].bgsrc='http://www.kiss-me.top/video/a.png';res.data.data[i].Bgsrc='http://www.kiss-me.top/video/aa.png';res.data.data[i].ph='http://www.kiss-me.top/video/1.png';}if(res.data.data[i+1]!=undefined){res.data.data[i+1].bgsrc='http://www.kiss-me.top/video/b.png';res.data.data[i+1].Bgsrc='http://www.kiss-me.top/video/bb.png';res.data.data[i+1].ph='http://www.kiss-me.top/video/2.png';}if(res.data.data[i+2]!=undefined){res.data.data[i+2].bgsrc='http://www.kiss-me.top/video/c.png';res.data.data[i+2].Bgsrc='http://www.kiss-me.top/video/cc.png';res.data.data[i+2].ph='http://www.kiss-me.top/video/3.png';}if(res.data.data[i+3]!=undefined){res.data.data[i+3].bgsrc='http://www.kiss-me.top/video/d.png';res.data.data[i+3].Bgsrc='http://www.kiss-me.top/video/dd.png';res.data.data[i+3].ph='http://www.kiss-me.top/video/4.png';}}if(i3){res.data.data[i].ph='http://www.kiss-me.top/video/4.png';}}console.log(res.data.data)this.setData({hotWord:res.data.data})},(res)={})},/***获取视频列表*/getvideoList(art){if(art==undefined||art==null||art==''){varhotWordsId=''}else{varhotWordsId=art}varparams={hotWordsId:hotWordsId,page:page,limit:config.limit}config.ajax('POST',params,config.videoList,(res)={if(this.data.videoList.length!=0){if(page==1){this.setData({videoList:res.data.data.list})}else{this.setData({videoList:this.data.videoList.concat(res.data.data.list)})}}else{this.setData({videoList:res.data.data.list,mask:true})}if(res.data.data.list.lengthconfig.limit){this.setData({nodata:true,allnum:res.data.data.totalCount})}wx.hideLoading()},(res)={})},/***获取是否显示广告*/getAps(){varparams={location:'index'}config.ajax('POST',params,config.aps,(res)={console.log(res.data.data)this.setData({aps:res.data.data})},(res)={})},/***播放事件*/myvideoPlay:function(e){console.log(e)},/***跳到detail列表*/tolist(e){varalldata={id:e.currentTarget.dataset.id,bg:e.currentTarget.dataset.bg,name:e.currentTarget.dataset.name,ph:e.currentTarget.dataset.ph,num:e.currentTarget.dataset.num,}wx.navigateTo({url:'/pages/detail/detail?alldata='+JSON.stringify(alldata),success:function(res){},fail:function(res){},complete:function(res){},})},/***生命周期函数--监听页面初次渲染完成*/onReady:function(){},/***生命周期函数--监听页面显示*/onShow:function(){},/***生命周期函数--监听页面隐藏*/onHide:function(){},/***生命周期函数--监听页面卸载*/onUnload:function(){},/***页面相关事件处理函数--监听用户下拉动作*/onPullDownRefresh:function(){wx.showNavigationBarLoading()page=1;wx.showLoading({title:'数据加载中...',mask:true,})this.videoGroup=this.selectComponent("#videoGroup");this.getvideoList()//this.getlistHot()this.getHotword()this.getAps()wx.hideNavigationBarLoading()wx.stopPullDownRefresh()this.setData({playIndex:null})},/***页面上拉触底事件的处理函数*/onReachBottom:function(){varthat=thispage++that.setData({moretype:'正在加载中~'})setTimeout(function(){that.getvideoList()that.setData({playIndex:null,})},2000)},submittwo(e){console.log(1)if(app.globalData.isSubscibe){varparams={openId:app.globalData.openid,formId:e.detail.formId,status:'t'}}else{varparams={openId:app.globalData.openid,formId:e.detail.formId}}config.ajax('POST',params,config.wxformId,(res)={this.setData({isSubscibe:true})app.globalData.isSubscibe=true},(res)={})},/***用户点击右上角分享*/onShareAppMessage:function(res){if(res.from==='button'){if(res.target.dataset.id=='分享好友'){return{title:'我是分享好友的',path:'/pages/index/index'}}else{config.ajax('POST',{id:res.target.dataset.id,openid:app.globalData.openid},config.videoShare,(res)={},(res)={})varalldata={id:res.target.dataset.id,title:res.target.dataset.title,cover:res.target.dataset.cover,duration:res.target.dataset.duration,allnum:res.target.dataset.allnum}return{title:alldata.title,path:'/pages/share/share?alldata='+JSON.stringify(alldata),imageUrl:alldata.cover}}}else{return{title:'我是分享好友的',path:'/pages/index/index'}}}})

14.index.json文件

{"navigationBarTitleText":"葫芦热点","usingComponents":{"videoGroup":"/Component/AuglyVideo"},"enablePullDownRefresh":true}

15.第一步我们需要在index.json里引入这个自定义组件

"usingComponents":{"videoGroup":"/Component/AuglyVideo"},

16.第二步,我们需要在index.wxml运用它即

!--自定义视频组件--videoGroupid='videoGroup'page="{{page}}"playIndex="{{playIndex}}"videoList="{{videoList}}"aps="{{aps}}"bind:videoPlay="myvideoPlay"/videoGroup

17.那么传值的方法怎么传呢?怎么向组件里传自己的数据之前我们在组件里的js自定义了属性,每一个属性都是一个对象,对象里包括这个属性的类型和属性的默认值当想要向自定义组件传值的时候直接在组件上把想要传的数据直接通过自定义属性向里面传就可以了,比如videoList是我获取的是视频列表,我将videoList传入了自定义组件的videoList属性,于是自定义视频组件就直接能videoList数据了。这些在官方文档和百度上几乎都能知道,但凡有小程序基础都能看明白。但是怎么从组件里面把值传出来呢,我们知道,当我操作播放视频的时候我可能需要进行一些处理,怎么办呢?通过阅读小程序的官方文档,我发现小程序自定义组件的这个

varmyEventDetail={playIndex:this.data.playIndex,playmid:this.data.playmid,videoContextCurrent:videoContextCurrent,videoContext:videoContext}//detail对象,提供给事件监听函数varmyEventOption={}//触发事件的选项this.triggerEvent('videoPlay',myEventDetail,myEventOption)

18.这个方法可以把组件里面的数据暴露出来给外面用

myEventDetail记录的是要传出来的具体的值,以对象的形式传出来myEventOption是选项,一般用不到'videoPlay'是一个自定义事件名字

19.在运用组件的时候

videoGroupid='videoGroup'page="{{page}}"playIndex="{{playIndex}}"videoList="{{videoList}}"aps="{{aps}}"bind:videoPlay="myvideoPlay"/videoGroup//这里有一个bind:videoPlay="myvideoPlay"

20.前一个videoPlay是自定义组件里的那个自定义事件名字后面的’myvideoPlay’是在我组件外的方法,这个方法在index.js里调用而这个方法,调用这个方法就能拿到自定义组件传出来的值如下拿值

myvideoPlay:function(e){console.log(e)},

21.基本内容就这些了,我会将源码放在git和码云上,欢迎大家留言与提问码云地址:https://gitee.com/Q_Augly/custom_component_demo.git点此查看github地址:https://github.com/Augly/demo.gitgit查看

22.建立了一个小程序技术交流群,欢迎大家来群讨论

版权声明

即速应用倡导尊重与保护知识产权。如发现本站文章存在版权问题,烦请提供版权疑问、身份证明、版权证明、联系方式等发邮件至197452366@qq.com ,我们将及时处理。本站文章仅作分享交流用途,作者观点不等同于即速应用观点。用户与作者的任何交易与本站无关,请知悉。

产品经理

手机 : 13312967497

擅长 : 小程序流量变现

扫码领取礼包

最新资讯

热门模板

  • 头条
  • 搜狐
  • 微博
  • 百家
  • 一点资讯
  • 知乎