HarmonyOS NEXT應(yīng)用開發(fā)之@State裝飾器:組件內(nèi)狀態(tài)

@State裝飾的變量阔馋,或稱為狀態(tài)變量玛荞,一旦變量擁有了狀態(tài)屬性,就和自定義組件的渲染綁定起來呕寝。當(dāng)狀態(tài)改變時(shí)勋眯,UI會(huì)發(fā)生對(duì)應(yīng)的渲染改變。

在狀態(tài)變量相關(guān)裝飾器中下梢,@State是最基礎(chǔ)的客蹋,使變量擁有狀態(tài)屬性的裝飾器,它也是大部分狀態(tài)變量的數(shù)據(jù)源孽江。

說明:

從API version 9開始讶坯,該裝飾器支持在ArkTS卡片中使用。

概述

@State裝飾的變量岗屏,與聲明式范式中的其他被裝飾變量一樣辆琅,是私有的,只能從組件內(nèi)部訪問这刷,在聲明時(shí)必須指定其類型和本地初始化婉烟。初始化也可選擇使用命名參數(shù)機(jī)制從父組件完成初始化。

@State裝飾的變量擁有以下特點(diǎn):

  • @State裝飾的變量與子組件中的@Prop裝飾變量之間建立單向數(shù)據(jù)同步,與@Link崭歧、@ObjectLink裝飾變量之間建立雙向數(shù)據(jù)同步隅很。

  • @State裝飾的變量生命周期與其所屬自定義組件的生命周期相同。

裝飾器使用規(guī)則說明

@State變量裝飾器 說明
裝飾器參數(shù)
同步類型 不與父組件中任何類型的變量同步。
允許裝飾的變量類型 Object叔营、class屋彪、string、number绒尊、boolean畜挥、enum類型,以及這些類型的數(shù)組婴谱。
支持Date類型蟹但。
API11及以上支持Map、Set類型谭羔。
支持undefined和null類型华糖。
支持類型的場(chǎng)景請(qǐng)參考觀察變化
API11及以上支持上述支持類型的聯(lián)合類型瘟裸,比如string | number, string | undefined 或者 ClassA | null客叉,示例見@State支持聯(lián)合類型實(shí)例
注意
當(dāng)使用undefined和null的時(shí)候话告,建議顯式指定類型兼搏,遵循TypeScipt類型校驗(yàn),比如:@State a : string | undefined = undefiend是推薦的沙郭,不推薦@State a: string = undefined佛呻。

支持AkrUI框架定義的聯(lián)合類型Length、ResourceStr病线、ResourceColor類型吓著。
類型必須被指定。
不支持any氧苍。
被裝飾變量的初始值 必須本地初始化夜矗。

變量的傳遞/訪問規(guī)則說明

傳遞/訪問 說明
從父組件初始化 可選,從父組件初始化或者本地初始化让虐。如果從父組件初始化將會(huì)覆蓋本地初始化紊撕。
支持父組件中常規(guī)變量(常規(guī)變量對(duì)@State賦值,只是數(shù)值的初始化赡突,常規(guī)變量的變化不會(huì)觸發(fā)UI刷新对扶,只有狀態(tài)變量才能觸發(fā)UI刷新)、@State惭缰、@Link浪南、@Prop、@Provide漱受、@Consume络凿、@ObjectLink、@StorageLink、@StorageProp絮记、@LocalStorageLink和@LocalStorageProp裝飾的變量摔踱,初始化子組件的@State。
用于初始化子組件 @State裝飾的變量支持初始化子組件的常規(guī)變量怨愤、@State派敷、@Link、@Prop撰洗、@Provide篮愉。
是否支持組件外訪問 不支持,只能在組件內(nèi)訪問差导。

圖1 初始化規(guī)則圖示

觀察變化和行為表現(xiàn)

并不是狀態(tài)變量的所有更改都會(huì)引起UI的刷新试躏,只有可以被框架觀察到的修改才會(huì)引起UI刷新。本小節(jié)將介紹什么樣的修改才能被觀察到设褐,以及觀察到變化后冗酿,框架的是怎么引起UI刷新的,即框架的行為表現(xiàn)是什么络断。

觀察變化

  • 當(dāng)裝飾的數(shù)據(jù)類型為boolean、string项玛、number類型時(shí)貌笨,可以觀察到數(shù)值的變化。

    // for simple type
    @State count: number = 0;
    // value changing can be observed
    this.count = 1;
    
  • 當(dāng)裝飾的數(shù)據(jù)類型為class或者Object時(shí)襟沮,可以觀察到自身的賦值的變化锥惋,和其屬性賦值的變化,即Object.keys(observedObject)返回的所有屬性开伏。例子如下膀跌。
    聲明ClassA和Model類。

      class ClassA {
        public value: string;
      
        constructor(value: string) {
          this.value = value;
        }
      }
      
      class Model {
        public value: string;
        public name: ClassA;
        constructor(value: string, a: ClassA) {
          this.value = value;
          this.name = a;
        }
      }
    

    @State裝飾的類型是Model

    // class類型
    @State title: Model = new Model('Hello', new ClassA('World'));
    

    對(duì)@State裝飾變量的賦值固灵。

    // class類型賦值
    this.title = new Model('Hi', new ClassA('ArkUI'));
    

    對(duì)@State裝飾變量的屬性賦值捅伤。

    // class屬性的賦值
    this.title.value = 'Hi';
    

    嵌套屬性的賦值觀察不到。

    // 嵌套的屬性賦值觀察不到
    this.title.name.value = 'ArkUI';
    
  • 當(dāng)裝飾的對(duì)象是array時(shí)巫玻,可以觀察到數(shù)組本身的賦值和添加丛忆、刪除、更新數(shù)組的變化仍秤。例子如下熄诡。
    聲明Model類。

    class Model {
      public value: number;
      constructor(value: number) {
        this.value = value;
      }
    }
    

    @State裝飾的對(duì)象為Model類型數(shù)組時(shí)诗力。

    // 數(shù)組類型
    @State title: Model[] = [new Model(11), new Model(1)];
    

    數(shù)組自身的賦值可以觀察到凰浮。

    // 數(shù)組賦值
    this.title = [new Model(2)];
    

    數(shù)組項(xiàng)的賦值可以觀察到。

    // 數(shù)組項(xiàng)賦值
    this.title[0] = new Model(2);
    

    刪除數(shù)組項(xiàng)可以觀察到。

    // 數(shù)組項(xiàng)更改
    this.title.pop();
    

    新增數(shù)組項(xiàng)可以觀察到袜茧。

    // 數(shù)組項(xiàng)更改
    this.title.push(new Model(12));
    

    數(shù)組項(xiàng)中屬性的賦值觀察不到菜拓。

    // 嵌套的屬性賦值觀察不到
    this.title[0].value = 6;
    
  • 當(dāng)裝飾的對(duì)象是Date時(shí),可以觀察到Date整體的賦值惫周,同時(shí)可通過調(diào)用Date的接口setFullYear, setMonth, setDate, setHours, setMinutes, setSeconds, setMilliseconds, setTime, setUTCFullYear, setUTCMonth, setUTCDate, setUTCHours, setUTCMinutes, setUTCSeconds, setUTCMilliseconds 更新Date的屬性尘惧。

    @Entry
    @Component
    struct DatePickerExample {
      @State selectedDate: Date = new Date('2021-08-08')
    
      build() {
        Column() {
          Button('set selectedDate to 2023-07-08')
            .margin(10)
            .onClick(() => {
              this.selectedDate = new Date('2023-07-08')
            })
          Button('increase the year by 1')
            .margin(10)
            .onClick(() => {
              this.selectedDate.setFullYear(this.selectedDate.getFullYear() + 1)
            })
          Button('increase the month by 1')
            .margin(10)
            .onClick(() => {
              this.selectedDate.setMonth(this.selectedDate.getMonth() + 1)
            })
          Button('increase the day by 1')
            .margin(10)
            .onClick(() => {
              this.selectedDate.setDate(this.selectedDate.getDate() + 1)
            })
          DatePicker({
            start: new Date('1970-1-1'),
            end: new Date('2100-1-1'),
            selected: this.selectedDate
          })
        }.width('100%')
      }
    }
    
  • 當(dāng)裝飾的變量是Map時(shí),可以觀察到Map整體的賦值递递,同時(shí)可通過調(diào)用Map的接口set, clear, delete 更新Map的值喷橙。

  • 當(dāng)裝飾的變量是Set時(shí),可以觀察到Set整體的賦值登舞,同時(shí)可通過調(diào)用Set的接口add, clear, delete 更新Set的值贰逾。

框架行為

  • 當(dāng)狀態(tài)變量被改變時(shí),查詢依賴該狀態(tài)變量的組件菠秒;

  • 執(zhí)行依賴該狀態(tài)變量的組件的更新方法疙剑,組件更新渲染;

  • 和該狀態(tài)變量不相關(guān)的組件或者UI描述不會(huì)發(fā)生重新渲染践叠,從而實(shí)現(xiàn)頁(yè)面渲染的按需更新言缤。

使用場(chǎng)景

裝飾簡(jiǎn)單類型的變量

以下示例為@State裝飾的簡(jiǎn)單類型,count被@State裝飾成為狀態(tài)變量禁灼,count的改變引起B(yǎng)utton組件的刷新:

  • 當(dāng)狀態(tài)變量count改變時(shí)管挟,查詢到只有Button組件關(guān)聯(lián)了它;

  • 執(zhí)行Button組件的更新方法弄捕,實(shí)現(xiàn)按需刷新僻孝。

@Entry
@Component
struct MyComponent {
  @State count: number = 0;

  build() {
    Button(`click times: ${this.count}`)
      .onClick(() => {
        this.count += 1;
      })
  }
}

裝飾class對(duì)象類型的變量

  • 自定義組件MyComponent定義了被@State裝飾的狀態(tài)變量count和title,其中title的類型為自定義類Model守谓。如果count或title的值發(fā)生變化穿铆,則查詢MyComponent中使用該狀態(tài)變量的UI組件,并進(jìn)行重新渲染斋荞。

  • EntryComponent中有多個(gè)MyComponent組件實(shí)例荞雏,第一個(gè)MyComponent內(nèi)部狀態(tài)的更改不會(huì)影響第二個(gè)MyComponent。

class Model {
  public value: string;

  constructor(value: string) {
    this.value = value;
  }
}

@Entry
@Component
struct EntryComponent {
  build() {
    Column() {
      // 此處指定的參數(shù)都將在初始渲染時(shí)覆蓋本地定義的默認(rèn)值譬猫,并不是所有的參數(shù)都需要從父組件初始化
      MyComponent({ count: 1, increaseBy: 2 })
        .width(300)
      MyComponent({ title: new Model('Hello World 2'), count: 7 })
    }
  }
}

@Component
struct MyComponent {
  @State title: Model = new Model('Hello World');
  @State count: number = 0;
  private increaseBy: number = 1;

  build() {
    Column() {
      Text(`${this.title.value}`)
        .margin(10)
      Button(`Click to change title`)
        .onClick(() => {
          // @State變量的更新將觸發(fā)上面的Text組件內(nèi)容更新
          this.title.value = this.title.value === 'Hello ArkUI' ? 'Hello World' : 'Hello ArkUI';
        })
        .width(300)
        .margin(10)

      Button(`Click to increase count = ${this.count}`)
        .onClick(() => {
          // @State變量的更新將觸發(fā)該Button組件的內(nèi)容更新
          this.count += this.increaseBy;
        })
        .width(300)
        .margin(10)
    }
  }
}

從該示例中讯檐,我們可以了解到@State變量首次渲染的初始化流程:

  1. 使用默認(rèn)的本地初始化:

    @State title: Model = new Model('Hello World');
    @State count: number = 0;
    
  2. 對(duì)于@State來說,命名參數(shù)機(jī)制傳遞的值并不是必選的染服,如果沒有命名參數(shù)傳值别洪,則使用本地初始化的默認(rèn)值:

   class C1 {
      public count:number;
      public increaseBy:number;
      constructor(count: number, increaseBy:number) {
        this.count = count;
        this.increaseBy = increaseBy;
     }
   }
   let obj = new C1(1, 2)
   MyComponent(obj)

裝飾Map類型變量

說明:
從API version 11開始,@State支持Map類型柳刮。

在下面的示例中挖垛,message類型為Map<number, string>痒钝,點(diǎn)擊Button改變message的值,視圖會(huì)隨之刷新痢毒。

@Entry
@Component
struct MapSample {
  @State message: Map<number, string> = new Map([[0, "a"], [1, "b"], [3, "c"]])

  build() {
    Row() {
      Column() {
        ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
          Text(`${item[0]}`).fontSize(30)
          Text(`${item[1]}`).fontSize(30)
          Divider()
        })
        Button('init map').onClick(() => {
          this.message = new Map([[0, "a"], [1, "b"], [3, "c"]])
        })
        Button('set new one').onClick(() => {
          this.message.set(4, "d")
        })
        Button('clear').onClick(() => {
          this.message.clear()
        })
        Button('replace the first one').onClick(() => {
          this.message.set(0, "aa")
        })
        Button('delete the first one').onClick(() => {
          this.message.delete(0)
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}

裝飾Set類型變量

說明:
從API version 11開始送矩,@State支持Set類型。

在下面的示例中哪替,message類型為Set<number>栋荸,點(diǎn)擊Button改變message的值,視圖會(huì)隨之刷新凭舶。

@Entry
@Component
struct SetSample {
  @State message: Set<number> = new Set([0, 1, 2, 3, 4])

  build() {
    Row() {
      Column() {
        ForEach(Array.from(this.message.entries()), (item: [number, string]) => {
          Text(`${item[0]}`).fontSize(30)
          Divider()
        })
        Button('init set').onClick(() => {
          this.message = new Set([0, 1, 2, 3, 4])
        })
        Button('set new one').onClick(() => {
          this.message.add(5)
        })
        Button('clear').onClick(() => {
          this.message.clear()
        })
        Button('delete the first one').onClick(() => {
          this.message.delete(0)
        })
      }
      .width('100%')
    }
    .height('100%')
  }
}

State支持聯(lián)合類型實(shí)例

@State支持聯(lián)合類型和undefined和null晌块,在下面的示例中,count類型為number | undefined帅霜,點(diǎn)擊Button改變count的屬性或者類型匆背,視圖會(huì)隨之刷新。

@Entry
@Component
struct EntryComponent {
  build() {
    Column() {
      MyComponent()
    }
  }
}

@Component
struct MyComponent {
  @State count: number | undefined = 0;

  build() {
    Column() {
      Text(`count(${this.count})`)
      Button('change')
        .onClick(() => {
          this.count = undefined;
        })
    }
  }
}

常見問題

使用箭頭函數(shù)改變狀態(tài)變量未生效

箭頭函數(shù)體內(nèi)的this對(duì)象身冀,就是定義該函數(shù)時(shí)所在的作用域指向的對(duì)象钝尸,而不是使用時(shí)所在的作用域指向的對(duì)象。所以在該場(chǎng)景下搂根, changeCoverUrl的this指向PlayDetailViewModel珍促,而不是被裝飾器@State代理的狀態(tài)變量。

反例:

export default class PlayDetailViewModel {
  coverUrl: string = '#00ff00'

  changeCoverUrl= ()=> {
    this.coverUrl = '#00F5FF'
  }

}

import PlayDetailViewModel from './PlayDetailViewModel'

@Entry
@Component
struct PlayDetailPage {
  @State vm: PlayDetailViewModel = new PlayDetailViewModel()

  build() {
    Stack() {
      Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
      Row() {
        Button('點(diǎn)擊改變顏色')
          .onClick(() => {
            this.vm.changeCoverUrl()
          })
      }
    }
    .width('100%')
    .height('100%')
    .alignContent(Alignment.Top)
  }
}

所以要將當(dāng)前this.vm傳入剩愧,調(diào)用代理狀態(tài)變量的屬性賦值踢星。

正例:

export default class PlayDetailViewModel {
  coverUrl: string = '#00ff00'

  changeCoverUrl= (model:PlayDetailViewModel)=> {
    model.coverUrl = '#00F5FF'
  }

}

import PlayDetailViewModel from './PlayDetailViewModel'

@Entry
@Component
struct PlayDetailPage {
  @State vm: PlayDetailViewModel = new PlayDetailViewModel()

  build() {
    Stack() {
      Text(this.vm.coverUrl).width(100).height(100).backgroundColor(this.vm.coverUrl)
      Row() {
        Button('點(diǎn)擊改變顏色')
          .onClick(() => {
            let self = this.vm
            this.vm.changeCoverUrl(self)
          })
      }
    }
    .width('100%')
    .height('100%')
    .alignContent(Alignment.Top)
  }
}

狀態(tài)變量的修改放在構(gòu)造函數(shù)內(nèi)未生效

在狀態(tài)管理中,類會(huì)被一層“代理”進(jìn)行包裝隙咸。當(dāng)在組件中改變?cè)擃惖某蓡T變量時(shí),會(huì)被該代理進(jìn)行攔截成洗,在更改數(shù)據(jù)源中值的同時(shí)五督,也會(huì)將變化通知給綁定的組件,從而實(shí)現(xiàn)觀測(cè)變化與觸發(fā)刷新瓶殃。當(dāng)開發(fā)者把狀態(tài)變量的修改放在構(gòu)造函數(shù)里時(shí)充包,此修改不會(huì)經(jīng)過代理(因?yàn)槭侵苯訉?duì)數(shù)據(jù)源中的值進(jìn)行修改),即使修改成功執(zhí)行遥椿,也無法觀測(cè)UI的刷新基矮。

【反例】

@Entry
@Component
struct Index {
  @State viewModel: TestModel = new TestModel();

  build() {
    Row() {
      Column() {
        Text(this.viewModel.isSuccess ? 'success' : 'failed')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            this.viewModel.query()
          })
      }.width('100%')
    }.height('100%')
  }
}

export class TestModel {
  isSuccess: boolean = false
  model: Model

  constructor() {
    this.model = new Model(() => {
      this.isSuccess = true
      console.log(`this.isSuccess: ${this.isSuccess}`)
    })
  }

  query() {
    this.model.query()
  }
}

export class Model {
  callback: () => void

  constructor(cb: () => void) {
    this.callback = cb
  }

  query() {
    this.callback()
  }
}

上文示例代碼將狀態(tài)變量的修改放在構(gòu)造函數(shù)內(nèi),界面開始時(shí)顯示“failed”冠场,點(diǎn)擊后日志打印“this.isSuccess: true”說明修改成功家浇,但界面依舊顯示“failed”,未實(shí)現(xiàn)刷新碴裙。

【正例】

@Entry
@Component
struct Index {
  @State viewModel: TestModel = new TestModel();

  build() {
    Row() {
      Column() {
        Text(this.viewModel.isSuccess ? 'success' : 'failed')
          .fontSize(50)
          .fontWeight(FontWeight.Bold)
          .onClick(() => {
            this.viewModel.query()
          })
      }.width('100%')
    }.height('100%')
  }
}

export class TestModel {
  isSuccess: boolean = false
  model: Model = new Model(() => {
  })

  query() {
    this.model = new Model(() => {
      this.isSuccess = true
    })
    this.model.query()
  }
}

export class Model {
  callback: () => void

  constructor(cb: () => void) {
    this.callback = cb
  }

  query() {
    this.callback()
  }
}

上文示例代碼將狀態(tài)變量的修改放在類的普通方法中钢悲,界面開始時(shí)顯示“failed”点额,點(diǎn)擊后顯示“success”。

寫在最后

  • 如果你覺得這篇內(nèi)容對(duì)你還蠻有幫助莺琳,我想邀請(qǐng)你幫我三個(gè)小忙:
  • 點(diǎn)贊还棱,轉(zhuǎn)發(fā),有你們的 『點(diǎn)贊和評(píng)論』惭等,才是我創(chuàng)造的動(dòng)力珍手。
  • 關(guān)注小編,同時(shí)可以期待后續(xù)文章ing??辞做,不定期分享原創(chuàng)知識(shí)琳要。
  • 想要獲取更多完整鴻蒙最新學(xué)習(xí)知識(shí)點(diǎn),請(qǐng)移步前往小編:https://gitee.com/MNxiaona/733GH/blob/master/jianshu
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凭豪,一起剝皮案震驚了整個(gè)濱河市焙蹭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嫂伞,老刑警劉巖孔厉,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異帖努,居然都是意外死亡撰豺,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門拼余,熙熙樓的掌柜王于貴愁眉苦臉地迎上來污桦,“玉大人,你說我怎么就攤上這事匙监》渤鳎” “怎么了?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵亭姥,是天一觀的道長(zhǎng)稼钩。 經(jīng)常有香客問我,道長(zhǎng)达罗,這世上最難降的妖魔是什么坝撑? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮粮揉,結(jié)果婚禮上巡李,老公的妹妹穿的比我還像新娘。我一直安慰自己扶认,他們只是感情好侨拦,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著辐宾,像睡著了一般阳谍。 火紅的嫁衣襯著肌膚如雪蛀柴。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天矫夯,我揣著相機(jī)與錄音鸽疾,去河邊找鬼。 笑死训貌,一個(gè)胖子當(dāng)著我的面吹牛制肮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播递沪,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼豺鼻,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了款慨?” 一聲冷哼從身側(cè)響起儒飒,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎檩奠,沒想到半個(gè)月后桩了,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埠戳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年井誉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片整胃。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡颗圣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屁使,到底是詐尸還是另有隱情在岂,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布蛮寂,位于F島的核電站洁段,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏共郭。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一疾呻、第九天 我趴在偏房一處隱蔽的房頂上張望除嘹。 院中可真熱鬧,春花似錦岸蜗、人聲如沸尉咕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)年缎。三九已至悔捶,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間单芜,已是汗流浹背蜕该。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留洲鸠,地道東北人堂淡。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像扒腕,于是被迫代替她去往敵國(guó)和親绢淀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

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