(iOS)模仿斗魚的部分界面介紹一(部分使用RxSwift, MVVM)

前言:

之前閑著的時候就隨便模仿斗魚的界面寫了一些界面, 最初的時候在網(wǎng)上找到的獲取直播的sign加密方式還是可用的, 當時還使用IJKMediaFramework, 集成了直播視頻的獲取和播放, 當時的項目也就還是挺龐大的, 不過大約在7.21 左右斗魚的api升級了, 然后就不能獲取到直播了, 所以現(xiàn)在把項目中的直播相關(guān)的全部都刪除了

目前項目中就只能看到部分的界面和一些網(wǎng)絡(luò)的請求了, 項目是使用swift來實現(xiàn)的, 但是如果你是最初接觸swift的話, 有一些地方可能可以參考一下. 項目地址

一些頁面的效果如下
douyu1.gif
douyu2.gif
douyu3.gif
douyu4.gif
douyu5.gif
douyu6.gif
douyu7.gif
關(guān)于項目的一些解釋

一. 最初是使用MVC來設(shè)計的項目的, 最近開始接觸MVVM設(shè)計模式,在網(wǎng)上找到的各種MVVM的相關(guān)的資料, 就把先前的這個項目拿來改動試試, 然后在改的時候發(fā)現(xiàn), 很多時候不可能做到理想的MVVM架構(gòu)的, 因為可能使用到第三方的東西導(dǎo)致不能很方便的使用MVVM, 另外就是, 個人覺得簡單的界面使用MVVM就是在浪費時間

這里關(guān)于MVVM就簡單的提一下了
  • MVVM = model, view(viewController), viewModel
  • 在MVVM中, 每個view(viewController)理論上對應(yīng)一個viewModel, view(viewController)負責界面的布局, 和響應(yīng)用戶的點擊, 以及展示頁面...
  • viewModel用于處理view的所有的展示邏輯(請求網(wǎng)絡(luò), 操作數(shù)據(jù)庫, 格式化字符串...), 而且完美的viewModel里面是不應(yīng)該引入UIKit的, 所以viewModel就擁有view所需要的所有的數(shù)據(jù), viewModel中只進行數(shù)據(jù)的加工, 能夠?qū)@些數(shù)據(jù)進行必要的操作, 然后讓對應(yīng)的view更新數(shù)據(jù).
  • 因為view是擁有viewModel的, 所以要實現(xiàn)view和viewModel的通信(view更新的時候同步更新viewModel中的數(shù)據(jù))很簡單, 但是要實現(xiàn)viewModel和view的綁定就很難得, 有時候你可以選擇(kvo, 代理, 通知, block...), 但是很多時候?qū)崿F(xiàn)都是非常的麻煩的, 因為你需要做到在viewModel中更新的時候同步更新對應(yīng)的view的狀態(tài).
  • 所以這個時候你就需要一個響應(yīng)式編程的框架,來實現(xiàn)view和viewModel的(單)雙向綁定, 比如OC中你可以用ReactiveCocoa, 在swift中, 你可以使用ReactiveCocoa, RxSwift, Bond...(推薦RxSwift, 號稱是符合RX官方的設(shè)計, 跨平臺的設(shè)計理念, RxJava, RxJS...可以類似的使用)
  • 另外有人提出更符合MVVM的是viewModel只暴露一些輸入和輸出信號給view, 通過將這些信號綁定到view上面實現(xiàn)和view的同步更新, 而viewModel不暴露方法給view, 比如按鈕的點擊和viewModel的一個按鈕點擊的信號綁定, 在viewModel中通過訂閱這個信號處理按鈕的點擊, 而不是在view中調(diào)用viewModel的響應(yīng)按鈕點擊的方法... 不過個人更傾向于暴露方法, 因為感覺使用信號的話對第三方的框架依賴太大了
  • model和MVC中的model基本相似的角色, 這里就不介紹了, 關(guān)于MVVM的更多的介紹, 推薦看這一系列的博客

二. 項目最初是集成了IJKMediaFramework并且實現(xiàn)了直播的一些功能, 不過由于斗魚Api的變動, 就全部給移除了

Snip20160808_1.png

三. 項目使用純swift寫的, 所以很多的第三方的依賴就選擇了使用swift的版本的, 比如字典和模型的互轉(zhuǎn)沒有使用Mantle了, 取而代之的是使用了ObjectMapper, ObjectMapper的開發(fā)者為了更符合swift風格的編程, 沒有在基于OC的運行時來實現(xiàn)了, 因為使用OC的運行時只能獲取到繼承自NSObject的class的屬性的類型和值, 不能夠獲取到純swift的class, struct, enum等的屬性的類型和值了, 因為目前大家使用swift的時候更喜歡用struct來作為model, 所以基于運行時就不現(xiàn)實了, 不過帶來的一點不方便就是: 需要手動的建立映射關(guān)系(這也有一個好處, 可以多個key映射json的同一個key), 當然隨著swift的進步, 他的Reflect功能增強的話就可以方便的實現(xiàn)自動映射(雖然現(xiàn)在也可以實現(xiàn), 不過不被推薦)

Snip20160808_2.png

不過在使用上也是很簡單的, 只需要這樣, 如下調(diào)用這個map就將服務(wù)器返回的resultJson轉(zhuǎn)換為了TagModel模型了

Snip20160808_3.png

四. 網(wǎng)絡(luò)請求的方面沒有使用AFNetworking了, 而是使用出自同一個作者的Alamofire, 使用也是更加的簡單和方便, 作者利用swift的優(yōu)勢使得Alamofire能讓開發(fā)者更方便的實現(xiàn)各種需要的自定義配置

這里我只是簡單的使用了GET和POST請求

    /// get
    class func GET(URLString: String, parameters: [String: AnyObject]? = nil, successHandler:((result: AnyObject?) -> Void)?, failureHandler: ((error: NSError?) -> Void)?) {
        
        Alamofire.request(.GET, URLString, parameters: parameters, encoding: .URL, headers: nil).responseJSON { (response) in
            
            if response.result.isSuccess {
                print("初始請求:\(response.request)")
                successHandler?(result: response.result.value)
            } else {
                failureHandler?(error: response.result.error)
            }
            
        }
        
    }
    
    /// post
    class func POST(URLString: String, parameters: [String: AnyObject]? = nil, successHandler:((result: AnyObject?) -> Void)?, failureHandler: ((error: NSError?) -> Void)?) {
        
        Alamofire.request(.POST, URLString, parameters: parameters, encoding: .URL, headers: nil).responseJSON { (response) in
            
            if response.result.isSuccess {
                successHandler?(result: response.result.value)
            } else {
                failureHandler?(error: response.result.error)
            }
            
        }
        
    }}

如你所見, 使用就是如下的這么簡單

use

五. 圖片的加載方面沒有使用SDWebimage, 而是使用了王巍Kingfisher, 其中的接口設(shè)計以及原理和SDWebimage相類似, 所以你可以很快的就上手Kingfisher的使用了

        /// 使用分類來加載圖片, 同時提供進度和加載完成后的handler, 在這個handler里可以處理請求完成的圖片
            imageView.kf_setImageWithURL(NSURL(string: data.room_src)!, placeholderImage: nil, optionsInfo: nil, progressBlock: nil, completionHandler: nil)
            /// 先下載載設(shè)置圖片
            KingfisherManager.sharedManager.retrieveImageWithURL(NSURL(string: data.room_src)!, optionsInfo: nil, progressBlock: nil) {[weak self] (image, error, cacheType, imageURL) in
                guard let validSelf = self where image != nil else {
                    return
                }
                validSelf.imageView.zj_setCircleImage(image, radius: 20.0)
                
                
            }

六. 自動布局上面沒有使用masonry, 而是使用了同一個團隊開發(fā)的SnapKit, 所以使用的方法幾乎一樣, 不過因為swift更適合函數(shù)式編程, 所以語法看上去也是自然了許多

Snip20160808_6.png

七.關(guān)于RxSwift, 如果要使用MVVM的設(shè)計模式的話, 必須得解決view和viewModel的綁定問題, 那么最方便的就是使用第三方的響應(yīng)式編程的框架, 這里推薦使用RxSwift, 這個學(xué)習的路線確實是很陡峭, 不是很容易就掌握了, 所以在項目中, 我只是在RecommendController簡單的示例了一下RxSwift的使用, 另外RxSwift不單是方便MVVM, 更重要的是, 他把所有的(kvo, delegate, action- target, block, notification...)統(tǒng)一為了一種簡單的使用方式, 真正的實現(xiàn)了高聚合, 低耦合. 同時RxSwift里面還有很多的用處, 比如實現(xiàn)搜索需求的時候, 需要在用戶輸入后實時的請求服務(wù)器, 這個時候, 就可以使用RxSwift和簡單的實現(xiàn), 在用戶輸入停留一段時間后請求服務(wù)器, 同時當輸入的內(nèi)容不變的時候不請求服務(wù)器... 總之很多的方便的功能, 絕對超乎你的想象, 等待你去發(fā)現(xiàn)...

rxSwift1
rxSwift2

八. 關(guān)于項目中文件的說明

  • main文件夾下主要是項目中通用的一些東西
Snip20160808_23.png
  • MainNavigationController主要是用來統(tǒng)一配置項目中所有的Navigationtroller的一些屬性, 比如在這個項目中, 我只是統(tǒng)一開啟了全屏滑動返回的功能, 和攔截了彈出新控制器的方法, 你需要的各種其他自定義的, 建議也集中放在這里
class MainNavigationController: UINavigationController {

    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 開啟全屏pop手勢
        zj_enableFullScreenPop(true)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
    

    // 攔截 統(tǒng)一處理
    override func showViewController(vc: UIViewController, sender: AnyObject?) {
        vc.hidesBottomBarWhenPushed = true
        super.showViewController(vc, sender: sender)
    }

}
  • MainTabBarController 是用來統(tǒng)一處理項目中的Tabbarcontroller的一些屬性, 當然很多人都是直接放在Appdelegate中來設(shè)置的, 個人還是喜歡全部分離開來
 override func viewDidLoad() {
        super.viewDidLoad()
        /// 設(shè)置子控制器
        setupChildVcs()
        /// 設(shè)置item的字體顏色
        setTabBarItemColor()
    }
    
    func setTabBarItemColor() {
        UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.orangeColor()], forState: .Selected)
        UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.lightGrayColor()], forState: .Normal)
    }
    
    func setupChildVcs() {
        let homeVc = addChildVc(HomeController(), title: "首頁", imageName: "btn_home_normal_24x24_", selectedImageName: "btn_home_selected_24x24_")
        let liveVc = addChildVc(LiveColumnController(), title: "直播", imageName: "btn_column_normal_24x24_", selectedImageName: "btn_column_selected_24x24_")
        let concernVc = addChildVc(ConcernController(), title: "關(guān)注", imageName: "btn_live_normal_30x24_", selectedImageName: "btn_live_selected_30x24_")
        let profileVc = addChildVc(ProfileController(), title: "我的", imageName: "btn_user_normal_24x24_", selectedImageName: "btn_user_selected_24x24_")
        viewControllers = [homeVc, liveVc, concernVc, profileVc]

    }
    
    func addChildVc(childVc: UIViewController, title: String, imageName: String, selectedImageName: String) -> UINavigationController {
        let navi = MainNavigationController(rootViewController: childVc)
        
        let image = UIImage(named: imageName)?.imageWithRenderingMode(.AlwaysOriginal)
        let selectedImage = UIImage(named: selectedImageName)?.imageWithRenderingMode(.AlwaysOriginal)

        let tabBarItem = UITabBarItem(title: title, image: image, selectedImage: selectedImage)
        navi.tabBarItem = tabBarItem
        
        return navi
    }
  • BaseViewController 是用來作為所有控制器的基類, 在里面統(tǒng)一處理一些設(shè)置, 在OC中, 我一般不喜歡使用基類來處理, 都是使用分類 +load()來統(tǒng)一設(shè)置一些, 比如設(shè)置view.backgroundColor, 但在swift中目前, mock不方便, 所以就使用了基類, 這也是很多朋友都喜歡使用的方式
class BaseViewController: UIViewController {
    /// 用于RxSwift
    var disposeBag = DisposeBag()
    /// 標記是否更新了布局
    private var didUpdateConstraints = false
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view.backgroundColor = UIColor.whiteColor()

    }
    
    /// 重寫方法
    override func updateViewConstraints() {
        if !didUpdateConstraints {
            addConstraints()
            didUpdateConstraints = true
        }
        super.updateViewConstraints()
    }
    /// 子類重寫, 用于添加自動布局
    func addConstraints() {
        /// default do nothing
    }
}
  • lib文件夾下主要是使用的一些封裝好的東西, 不過在這個項目中, lib里面的全是用的我自己寫的一些東西, 一些之前已經(jīng)放在了github上了, 這里簡單介紹一下, 給自己一個廣告??
    • FullScreenPopNavigationController -> 是為了方便navigationController實現(xiàn)全屏側(cè)滑返回的功能的, 如你所見, 打開和關(guān)閉都只需一行代碼// zj_enableFullScreenPop(true) (true)開啟全屏pop手勢, false關(guān)閉
      Snip20160808_16.png
    • ZJPullToRefresh -> 是我用swift寫的一個和MJRefresh基本功能和使用相似的上下拉刷新控件
     let normalAnimator = NormalAnimator.loadNormalAnimatorFromNib()
      normalAnimator.isAutomaticlyHidden = true
      normalAnimator.lastRefreshTimeKey = "recommondHeader"
      collectionView.zj_addRefreshHeader(normalAnimator) { [weak self] in
        /// 這里是加載過程
      }
      ```
    

Snip20160808_14.png

* PPTView -> 是一個簡單的圖片輪播, 這個實現(xiàn)沒什么難度, 可以使用鏈式調(diào)用, 幾個鏈式調(diào)用的設(shè)置和tableView的幾個代理方法的功能類似,在網(wǎng)絡(luò)加載完畢的時候調(diào)用self.pptView.reloadData()可以像tableview一樣重新加載數(shù)據(jù)
let pptView = PPTView.PPTViewWithImagesCount {[weak self] in guard let `self` = self else { return 0 } return self.viewModel.pptData.count } .setupImageAndTitle({[weak self] (titleLabel, imageView, index) in guard let `self` = self else { return } // let model = self.viewModel.pptData.value[index] let model = self.viewModel.pptData[index] titleLabel.textAlignment = .Left titleLabel.text = " " + "\(model.title)" imageView.image = UIImage(named: "2") imageView.kf_setImageWithURL(NSURL(string: model.pic_url), placeholderImage: UIImage(named: "1")) }) .setupPageDidClickAction({[weak self] (clickedIndex) in guard let `self` = self else { return } let playerVc = PlayerController() playerVc.title = "播放" playerVc.roomID = String(self.viewModel.pptData[clickedIndex].id) self.showViewController(playerVc, sender: nil) }) pptView.frame = CGRect(x: 0, y: 0, width: Constant.screenWidth, height: ConstantValue.pptViewHeight) pptView.pageControlPosition = .BottomRight return pptView
Snip20160808_15.png

  • ScrollPageView -> 是用來實現(xiàn)類似網(wǎng)易新聞的頭部標簽欄等多種效果
Snip20160808_13.png
  • TypedTableView -> 是簡單封裝了一下"靜態(tài)"tableView的使用, 這個看個人的習慣
Snip20160808_17.png

        let row1Data = TypedCellDataModel(name: "開播提示", iconName: "1")
        let row2Data = TypedCellDataModel(name: "票務(wù)查詢", iconName: "1")
        let row3Data = TypedCellDataModel(name: "設(shè)置選項", iconName: "1")
        let row4Data = TypedCellDataModel(name: "手游中心", iconName: "1", detailValue: "玩游戲領(lǐng)魚丸")

        let row1 = CellBuilder<TitleWithLeftImageCell>(dataModel: row1Data, cellDidClickAction: {
            SimpleHUD.showHUD("未實現(xiàn)相關(guān)功能", autoHide: true, afterTime: 1.0)
        })
        let row2 = CellBuilder<TitleWithLeftImageCell>(dataModel: row2Data, cellDidClickAction: {
            SimpleHUD.showHUD("未實現(xiàn)相關(guān)功能", autoHide: true, afterTime: 1.0)
        })

        let row3 = CellBuilder<TitleWithLeftImageCell>(dataModel: row3Data, cellDidClickAction: {[unowned self] in
            
            self.showViewController(SettingController(), sender: nil)

            
        })
        
        let row4 = CellBuilder<TitleWithLeftImageAndDetailCell>(dataModel: row4Data, cellHeight: 50, cellDidClickAction: {[unowned self] in
            
            self.showViewController(TestController(), sender: nil)
            
        })
        
        let section1 = CommonTableSectionData(headerTitle: nil, footerTitle: nil, headerHeight: 10, footerHeight: nil, rows: [row1, row2, row3])
        
        let section2 = CommonTableSectionData(headerTitle: nil, footerTitle: nil, headerHeight: 10, footerHeight: 10, rows: [row4])
        data = [section1, section2]
  • PhotoBrowser -> 圖片瀏覽器, 可以支持瀏覽本地和網(wǎng)絡(luò)的圖片,很方便的簡單的實現(xiàn)類似空間, 朋友圈動態(tài)的多張圖片瀏覽, 已經(jīng)寫好各種手勢放大縮小, 保存等常用功能, 本項目中只是簡單的使用了, 瀏覽本地的圖片
    lazy var profileHeadView: ProfileHeadView =  {
        let profileHeadView = ProfileHeadView.LoadProfileHeadViewFormLib()
        profileHeadView.didTapImageViewHandler = {[weak self] imageView in
            guard let `self` = self else { return }
            /// 彈出圖片瀏覽器
            let photoModel = PhotoModel(localImage: imageView.image, sourceImageView: nil)
            let photoBrowser = PhotoBrowser(photoModels: [photoModel])
            photoBrowser.hideToolBar = true
            photoBrowser.show(inVc: self, beginPage: 0)
        }
        return profileHeadView
    }()
  • UsefulPickerView -> 簡單方便的彈出城市選擇, 日期選擇, 單列, 多列選擇的pickerView,
        let row1 = CellBuilder<TitleWithLeftImageCell>(dataModel: row1Data, cellDidClickAction: {
            UsefulPickerView.showDatePicker(row1Data.name, doneAction: { (selectedDate) in
                EasyHUD.showHUD("提示時間是---\(selectedDate)", autoHide: true, afterTime: 1.0)

            })
        })
        let row2 = CellBuilder<TitleWithLeftImageCell>(dataModel: row2Data, cellDidClickAction: {

            UsefulPickerView.showSingleColPicker(row2Data.name, data: ["是", "否"], defaultSelectedIndex: 0, doneAction: { (selectedIndex, selectedValue) in
                EasyHUD.showHUD("選擇了---\(selectedValue)", autoHide: true, afterTime: 1.0)
                
            })

        })

感覺這篇文章已經(jīng)很長了, 先就介紹到這里吧, 當然希望你也可以自己下載項目下來看看, 項目地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坠非,一起剝皮案震驚了整個濱河市递沪,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌帆阳,老刑警劉巖遇革,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡烘嘱,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門蝗蛙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蝇庭,“玉大人,你說我怎么就攤上這事捡硅∠冢” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵壮韭,是天一觀的道長北发。 經(jīng)常有香客問我,道長喷屋,這世上最難降的妖魔是什么琳拨? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮屯曹,結(jié)果婚禮上狱庇,老公的妹妹穿的比我還像新娘惊畏。我一直安慰自己,他們只是感情好密任,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布颜启。 她就那樣靜靜地躺著,像睡著了一般批什。 火紅的嫁衣襯著肌膚如雪农曲。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天驻债,我揣著相機與錄音乳规,去河邊找鬼。 笑死合呐,一個胖子當著我的面吹牛暮的,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淌实,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼冻辩,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拆祈?” 一聲冷哼從身側(cè)響起恨闪,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎放坏,沒想到半個月后咙咽,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡淤年,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年钧敞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片麸粮。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡溉苛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出弄诲,到底是詐尸還是另有隱情愚战,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布齐遵,位于F島的核電站凤巨,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏洛搀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一佑淀、第九天 我趴在偏房一處隱蔽的房頂上張望留美。 院中可真熱鬧,春花似錦、人聲如沸谎砾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽景图。三九已至较雕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間挚币,已是汗流浹背亮蒋。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留妆毕,地道東北人慎玖。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像笛粘,于是被迫代替她去往敵國和親趁怔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 由于最近兩個多月薪前,筆者正和小伙伴們忙于對公司新項目的開發(fā)润努,筆者主要負責項目整體架構(gòu)的搭建以及功能模塊的分工。...
    CoderMikeHe閱讀 27,032評論 74 271
  • 我正在認識自己內(nèi)心的不足 我正在遇見更好的自己的路上 路上遇見很多小伙伴 我也開始接受新的事物 今日任務(wù)清單打卡 ...
    悅洋行者閱讀 282評論 0 0
  • 當我發(fā)現(xiàn)鼻子開始不通氣、嗓子也開始疼的時候例诀,我就知道随抠,你又來了。 鼻塞繁涂、眩暈拱她、全身發(fā)熱,還伴隨著間歇性的惡心干嘔扔罪。...
    MOKY莫閱讀 1,162評論 0 2
  • 上大學(xué)快兩年了,回想一下全肮,卻發(fā)現(xiàn)自己沒有一點成就敞咧,沒有做幾件有意義的事。我在想為什么我會這樣辜腺,高中的自己是一直努力...
    兵氣閱讀 231評論 0 2