weex實現(xiàn)RichText自動換行效果

weex實現(xiàn)富文本RichText效果

話不錯說,先上效果圖:


1559011516332.png

由于最近公司需求,仿微信朋友圈,評論回復@的人需要實現(xiàn)變藍色效果,研究了一番,發(fā)現(xiàn)weex-ui里面的富文本控件滿足不了要求,weex官網(wǎng)提供的RichText經(jīng)檢測,只能在0.20.0.0的版本才能正常使用,所以參考他們的源碼,寫了一個自己的富文本。

weex-ui源碼:https://github.com/alibaba/weex-ui

首先分析一波:

1,要實現(xiàn)不同顏色的字體,這里肯定是for循環(huán)創(chuàng)建了多個text,所以這里你看到,其實是多個text標簽,而非一個text標簽實現(xiàn)的。

2,既然是多個text標簽,如何截取給定的字符串,找到換行的具體位置是整個RichText實現(xiàn)的關鍵所在。(當然這里主要是算法上的一些操作,因人而異,最終的目的就是找出換行的位置)。

其實看到這里,相信每個人心里都有一些思考,那么這里先上效果分析圖:

1559012964700.png

上面每一個紅色矩形都表示一個text標簽,可以看到,這里一共有8個text標簽。

話不多說,上代碼:

<template>
  <div style="width:750px;align-items: center; background-color: #0094ff">
      <div style="flex-wrap: wrap; flex-direction: row;background-color: #ffffff" :style="{width:RichTextwidth+'px'}">
          <div v-for="(item,index) in data" :key="index">
              <text :style="{color:item.color,fontSize:item.size + 'px'}">{{item.content}}</text>
          </div>
      </div>
  </div>

</template>

<script>
  export default {
      name: "RichText",
      data () {
          return {
              data:[],
          }
      },
      props:{
          //數(shù)據(jù)源,我們這里傳進來就是一個數(shù)組包,數(shù)組中的每一個對象包含以下三個字段
          //color 這里的color跟我們在Style里面寫的color是一樣的,例如白色,這里就寫color:'#ffffff'
          //size  這里的size跟style里面的font-size有區(qū)別,這里的類型為數(shù)字,例如style里面的font-size:28px;那么這里就寫 color:28
          //content 這就是我們需要展示的內(nèi)容,類型為String
          datas:Array,
          //設置RichText的寬度,默認為690,注意這里的類型是數(shù)字,而不是我們在style中寫的那樣
          RichTextwidth:{
              type:Number,
              default:690,
          },
      },

      mounted() {
          //這個地方對數(shù)據(jù)做重新封裝之后再添加到data里面去
          let data = this.datas;
          //對data做判空處理,不為空時這里為true
          if (data){
              if (data.length){
                  //這個數(shù)組是我們對傳入數(shù)組處理之后得到的新的數(shù)據(jù)源
                  let tempContent = [];
                  //定義當前行可用的展示空間,第一行的時候,默認就是設置的行寬
                  let endLenght = this.RichTextwidth;
                  //對傳入的數(shù)據(jù)源做for循環(huán)操作得到每一個具體的元素
                  for (let i = 0; i < data.length; i++) {
                      //獲取到當前索引下的content
                      let tempStr = data[i].content;
                      //這里跟Java有細微區(qū)別,通過split轉換成字符數(shù)組
                      let char = tempStr.split("");
                      //strLength表示當前字符串的內(nèi)容長度,默認是0
                      let strLength = 0;
                      //ratio 表示當前字符的寬度占比
                      let ratio = 0;
                      /**
                       * 需要說明兩點點,一:這里的ratio并不是一個準確的值,這個是根據(jù)50px下 750px寬度內(nèi) 中文 英文大小寫 數(shù)字最大個數(shù) 計算出來的一個比率
                       * 經(jīng)測試,發(fā)現(xiàn)這樣計算出來的比率 在font-size為40px的情況下展示效果是最好的,所以我的效果圖,也是按照size為40給出的。
                       * 二:這里由于無法判斷符號是中文還是英文的,所以在此未對符號做兼容,如果你有什么好的方法,不妨在下方評論留言,謝謝
                       * */
                      for (let j = 0; j < char.length; j++) {
                          //常規(guī)操作
                          if (0 <= char[j] && char[j] <= 9){
                              //數(shù)字0~9
                              ratio = 0.56;
                          } else if ('a' <= char[j] && char[j] <= 'z'){
                              //小寫字母a~z
                              ratio = 0.51;
                          } else if ('A' <= char[j] && char[j] <= 'Z'){
                              //大些字母A~Z
                              ratio = 0.64;
                          } else {
                              //中文和符號暫不做區(qū)分,寬度系數(shù)就為1,
                              ratio = 1;
                          }
                          //總長度做求和操作
                          strLength += data[i].size * ratio
                      }

                      // 對比當前字符串長度是否小于當前可展示空間
                      if (strLength >= 0 && strLength <= endLenght){
                          //改變結束位置的長度,用來動態(tài)對比下一個元素是否需要直接存儲
                          endLenght = endLenght - strLength;
                          //長度小于當前可用空間長度,直接存儲到數(shù)組中
                          tempContent.push(data[i]);
                      } else {
                          //截取當前字符串長度,按照當前可用空間做截取
                          let arr = this.subStr2Length(data[i], endLenght);
                          //當前行可用空間能展示的當前字符串的最大索引值
                          let index = arr[0];
                          //當前可用空間展示的字符串的真實長度
                          let lenght = arr[1];
                          /**
                           * 計算剩余長度的字符串還可以占幾行
                           *  需要注意一點,Vue里面的“/”除操作跟Java有區(qū)別,這里得到的值是浮點數(shù),也就是小數(shù),舉例,12/10=1.2,跟Java有區(qū)別
                           * */
                          let rows = (strLength - lenght) / this.RichTextwidth;
                          //將剛剛計算出的需要添加的元素添加到數(shù)組中
                          let item1 = {
                              //截取真實長度填充到當前行末尾的可用空間中
                              content:data[i].content.substring(0,index),
                              size:data[i].size,
                              color:data[i].color,
                          };
                          tempContent.push(item1);
                          //判斷剩下的內(nèi)容是否新起一行可以展示完
                          if (rows <= 1){
                              //如果可以展示完,直接添加
                              let item2 = {
                                  /**
                                   * 需要說明一點,這里的subString跟Java中有細微區(qū)別,Vue中subString不會出現(xiàn)索引越界的問題,超出的話,截取至末尾
                                   */
                                  content:data[i].content.substring(index,data[i].content.length),
                                  size:data[i].size,
                                  color:data[i].color,
                              };

                              tempContent.push(item2);
                              //添加完成,需要修改我們的可用空間的值,以便于下一次進行對比
                              endLenght = this.RichTextwidth - (strLength - lenght);
                          } else {
                              //如果剩余長度,大于等于2行時
                              //定義一個值,記錄最后一行所占的長度
                              let lenght = 0;
                              //循環(huán)操作剩余的長度
                              for (let j = 0; j < rows; j++) {
                                  //獲取數(shù)據(jù)源中剩余的可用于展示的內(nèi)容
                                  data[i].content = data[i].content.substring(index ,data[i].content.length);
                                  //計算當前長度下能展示到的索引,和真實展示的長度
                                  let arr = this.subStr2Length(data[i], this.RichTextwidth);
                                  //獲取當前行最后一個元素的index,這里取值是長度剛剛超過一行時的索引,因為subString這個方法包含左不包含右,
                                  index = arr[0];
                                  //獲取真實展示的長度
                                  lenght = arr[1];
                                  let item2 = {
                                      content:data[i].content.substring(0,index),
                                      size:data[i].size,
                                      color:data[i].color,
                                  };
                                  tempContent.push(item2);
                              }
                              //記錄最后一行的可用空間
                              endLenght = this.RichTextwidth - lenght;
                          }
                      }

                  }
                  this.data = this.data.concat(tempContent);
              }
          }
      },

      methods : {
          //按照長度(px)裁剪當前字符串,返回一個數(shù)組,0索引位置返回的是當前換行時的index,1索引位置記錄的是截取的元素的真實長度。
          subStr2Length (data , lenght) {
              if (data.content){
                  let char = data.content.split("");
                  if (lenght && lenght != 0){
                      let tempLenght = 0;
                      for (let j = 0; j < char.length; j++) {
                          let ratio = 0;
                          if (0 <= char[j] && char[j] <= 9){
                              ratio = 0.56;
                          } else if ('a' <= char[j] && char[j] <= 'z'){
                              ratio =  0.51;
                          } else if ('A' <= char[j] && char[j] <= 'Z'){
                              ratio =  0.64;
                          } else {
                              //中文和符號暫不做區(qū)分,寬度系數(shù)就為1,
                              ratio =  1;
                          }
                          tempLenght += data.size * ratio;
                          if (tempLenght > lenght){
                              let arr = [j, tempLenght - data.size * ratio];
                              return arr;
                          }
                      }
                      //當截取傳入的長度超出了剩余長度的時候,返回最后的真實長度和索引
                      return [char.length, tempLenght];
                  } else {
                      return [0,0];
                  }
              }
          }
      }


  }
</script>

<style scoped>

</style>

以上是RichText控件的代碼,算法上可以根據(jù)自己的需求做相應的修改,接下來提供一個使用的demo代碼:

<template>
    <div style="flex: 1">
        <RichText :datas="data"></RichText>
    </div>
</template>

<script>
    import RichText from "./RichText";
    export default {
        name: "TestDemo",
        components: {RichText},
        data () {
            return {
                data:[
                    {
                        content:'張三張三張三張三張三張張三張三張三張三張三張',
                        size:'40',
                        color:'#00ffff',
                    },
                    {
                        content:'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                        size:'40',
                        color:'#0094ff',
                    },
                    {
                        content:'abcdefghijklmnopqrstuvwxyzabcdefj',
                        size:'40',
                        color:'#ff94ff',
                    },
                    {
                        content:'012345678901234567890123456',
                        size:'40',
                        color:'#9494ff',
                    },
                ]
            }
        },
    }
</script>

<style scoped>

</style>

以上代碼如果有任何問題,都可以直接在下方留言,同時感謝大家指出的問題。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 0x1 讀完后希望你會 了解Weex中,we腳本的各個標簽<template> 解析實現(xiàn)方式,如何生成可以運行的...
    Orechi閱讀 5,137評論 1 52
  • 什么是 Weex? Weex 是使用流行的 Web 開發(fā)體驗來開發(fā)高性能原生應用的框架。 Weex 致力于使開發(fā)者...
    小花生_peanut閱讀 4,553評論 0 1
  • 一、與 Weex 的緣分 公司接了一個新項目,項目本身也不是很復雜于是我們老大說希望用 Weex 進行跨平臺開發(fā),...
    瀾秋閱讀 943評論 0 1
  • 2016年底了解到weex,看到它的諸多優(yōu)點,但因為工作中和它沒什么交集也就沒著手去學習。后續(xù)換工作有用到weex...
    喝酸奶舔下蓋閱讀 1,210評論 0 1
  • 最近與老友方總聊天,聊起了與人相處之道。 ——方總:曾經(jīng)的同事小方,2014年辭職創(chuàng)業(yè)至今 ...
    閑云若夕閱讀 392評論 2 0

友情鏈接更多精彩內(nèi)容