zoukankan      html  css  js  c++  java
  • vue实现微信对话

    因为项目中需要实现仿微信对话功能,于是抽空实现了下,主要是h5的canvas的把图片和文字绘制到画布上

    原文来自我的个人博客:http://lvhww.com/index.php/archives/6/

    1.首先准备图片资源:微信头部导航,对话框,二维码等

     2.API接口

    3,效果图

    4,代码DetailWechat.vue

    <template>
      <div class="s-all">
        <v-header :name="name"></v-header>
        <!-- 人物列表 -->
        <div class="s-content active">
          <div class="s-recommend">
            <span class="span-1">荐</span>
            <span>推荐人物</span></div>
          <div class="s-recommend-people">
            <ul>
              <li v-for="item in recommendList">
                <div class="s-img">
                  <img @click="drawResult(item.name,item.nickname,item._id,$event)"
                       src="../assets/images/e217d58ec3d03b1ab5df0d92589a04bb.jpg"/>
                  <!--:src="item.image.replace('/game/static/images/','')"/>-->
                </div>
                <div class="s-title" v-text="item.name">
                </div>
              </li>
            </ul>
          </div>
          <div class="s-category">
            <span class="span-2">类</span>
            <span>分类</span>
          </div>
          <div class="s-category-a">
            <a class="s-bt" @click="getData(Aname.name)" v-for="Aname in Alist">{{Aname.name}}</a>
          </div>
          <div class="s-category-list">
            <ul>
              <li v-for="item in itemList">
                <a class="s-a-1" @click="drawResult(item.name,item.name,item._id)" :data-alt="item.name"
                   :data-nickname="item.name" :data-num="item._id" name="s-a-1">
                  <div class="s-a-img">
                    <img v-lazy="item.image" class="star-icon" id="star-icon"/>
                  </div>
                  <div class="s-a-title">
                    <div class="s-a-title-name" v-text="item.name"></div>
                    <div class="s-a-title-play">
                      <span class="m-icon icon-star"></span>
                      <span class="m-icon icon-star"></span>
                      <span class="m-icon icon-star"></span>
                      <span class="m-icon icon-star"></span>
                      <span class="m-icon icon-star"></span>
                      <span class="s-people">123456人在玩</span>
                    </div>
                  </div>
                </a>
                <a class="s-a-2" @click="drawResult(item.name,item.name,item._id,$event)" :data-alt="item.name"
                   :data-nickname="item.name" :data-num="item._id">
                  开始<span class="icon-more"></span>
                </a>
              </li>
            </ul>
          </div>
        </div>
        <!-- 正在制作 -->
        <div class="box" id="page2">
          <img id="loading" class="loading" src="https://h5.tangdaoya.com/game/static/loading.png"/>
          <p id="loading-text" class="loading-text">正在生成</p>
        </div>
        <!-- 制作结果 -->
        <div class="box" id="page3">
          <div class="common-result-btnbox">
            <div class="commonbtn-playAgain btn-back" @click="changeContent()" v-if="ShowAgain">
              换个文案试试
            </div>
            <div id="btn-share" class="commonbtn-share">立即去整人</div>
          </div>
          <div class="resultimgbox">
            <img id="result" class="result" src=""/>
          </div>
        </div>
        <!-- 返回制作 -->
        <div class="box" id="page4">
          <div class="butbox common-result-btnbox">
            <div id="backtohomgpage" class="commonbtn-share">返回制作</div>
          </div>
        </div>
        <div class="" style="display: block">
          <img src="../assets/images/header.jpg" id="headerImg" alt="">
          <img src="../assets/images/footer.jpg" id="footerImg" alt="">
          <img src="../assets/images/qr.png" id="codeImg" alt="">
          <img src="../assets/images/8fe39669bff9423bb56c5586f5fa70d1.jpg" id="head2Img" alt="">
        </div>
        <img src="" id="targetImg" alt="">
      </div>
    </template>
    <script>
      import Vue from 'vue'
      import api from '../fetch/api.js'
      import com from '../assets/js/common'
      import axios from 'axios';
      import VueLazyload from 'vue-lazyload'
      import {Toast} from 'mint-ui'
      import VHeader from '@/components/Header.vue'
      var headImg = "" || "https://h5.tangdaoya.com/zb/static/image/cover/8fe39669bff9423bb56c5586f5fa70d1.jpg";
      var manifest = [{
        src: "https://h5.tangdaoya.com/game/static/header.jpg",
        id: "header"
      }, {
        src: "https://h5.tangdaoya.com/game/static/footer.jpg",
        id: "footer"
      }, {
        src: headImg,
        id: "head2"
      }];
      var headerEle;
      var footerEle;
      var codeEle;
      var head2Ele;
      var starImgObg;
      var chatContent, template;
      var starName = "张信哲", starNickName = "張信哲JeffChang", starID = 1, starImg;
      var cW = 640, cHeigth = 1138, headL = 18, headW = 63, headR = cW - headL - headW,
        padding = 20, fontSize = 23, lingheight = 30, imgTextSpace = 20,
        starTextL = headL + headW + imgTextSpace - 3,
        starTextR = headR - imgTextSpace,
        maxTextW = 405, gY = 0, verticlaSpace = 34, textRadius = 6;
      CanvasRenderingContext2D.prototype.roundRect = function (x, y, w, h, r) {
        if (w < 2 * r) r = w / 2;
        if (h < 2 * r) r = h / 2;
        this.beginPath();
        this.moveTo(x + r, y);
        this.arcTo(x + w, y, x + w, y + h, r);
        this.arcTo(x + w, y + h, x, y + h, r);
        this.arcTo(x, y + h, x, y, r);
        this.arcTo(x, y, x + w, y, r);
        this.closePath();
        return this;
      }
    
    
      export default {
        components: {
          VHeader
        },
        data() {
          return {
            name: '',
            itemList: [],
            recommendList: [],
            Alist: [{
              name: '影视大咖'
            }, {
              name: '女明星'
            }, {
              name: '男明星'
            }, {
              name: '商业大亨'
            }],
            starName: '',
            starNickName: '',
            starID: '',
            starImgObg: '',
            chatContent: '',
            template: '',
            ShowAgain: false
          }
        },
        created() {
          this.getData();
        },
        mounted() {
          let self = this;
          headerEle = document.getElementById('headerImg');
          footerEle = document.getElementById('footerImg');
          codeEle = document.getElementById('codeImg');
          head2Ele = document.getElementById('head2Img');
          CanvasRenderingContext2D.prototype.drawStarText = function (x, y, r, text, translate) {
            self.drawStarImg(this, y);
            console.log('star')
            this.font = "24px Helvetica";
            var hastrans = false;
            var wordCnt = com.isChineseChar(text) ? 32 : 33;
            console.log(wordCnt)
            var textArr = self.getText2Arr(this, text, wordCnt);
            var h = headW + lingheight * (textArr.length - 1);
            var w = (textArr.length > 1) ? maxTextW : (this.measureText(textArr[0]).width + 2 * padding);
            if (translate) {
              hastrans = true;
              var transArr = self.getText2Arr(this, translate, 32);
              h = h + lingheight * (transArr.length) + 48;
              if (transArr.length > 1) {
                w = maxTextW;
              }
            }
            gY = y + h + verticlaSpace;
            if (w < 2 * r) r = w / 2;
            if (h < 2 * r) r = h / 2;
            this.save();
            this.beginPath();
            this.moveTo(x + r, y);
            this.arcTo(x + w, y, x + w, y + h, r);
            this.arcTo(x + w, y + h, x, y + h, r);
            this.arcTo(x, y + h, x, y, r);
    
            this.lineTo(x, y + 31 + 7);
            this.lineTo(x - 10, y + 31);
            this.lineTo(x, y + 31 - 7);
            this.arcTo(x, y, x + w, y, r);
            this.closePath();
            this.strokeStyle = '#d3d3d3';
            this.lineWidth = 2;
            this.stroke();
            this.fillStyle = "#fff";
            this.fill();
    
            this.textBaseline = 'top';
            this.textAlign = 'left';
            this.fillStyle = '#000';
            self.writeTextArr(this, textArr, lingheight, x + padding, y + padding);
            //writeMulLineText(this, text, 32, 30, x + padding, y+padding);
            //this.fillText(text, x + padding, y+padding);
            if (hastrans) {
              this.beginPath();
              var lineY = y + padding * 2 + textArr.length * lingheight;
              this.moveTo(x + padding, lineY);
              this.lineTo(x + w - padding, lineY);
              this.strokeStyle = "#ddd";
              this.stroke();
              self.writeTextArr(this, transArr, lingheight, x + padding, lineY + 20);
              gY = gY - verticlaSpace;
              this.transFlag(x, gY + 8, textRadius);
            }
            this.restore();
    
            return this;
          }
    
          CanvasRenderingContext2D.prototype.drawSelfText = function (x, y, r, text) {
            self.drawSelfImg(this, y);
            this.font = "24px Helvetica"; // Arial
            var wordCnt = com.isChineseChar(text) ? 32 : 33;
            var textArr = self.getText2Arr(this, text, wordCnt);
            var h = headW + lingheight * (textArr.length - 1);
            var w = (textArr.length > 1) ? maxTextW : (this.measureText(textArr[0]).width + 2 * padding);
            x = x - w;
            gY = y + h + verticlaSpace;
            if (w < 2 * r) r = w / 2;
            if (h < 2 * r) r = h / 2;
            this.save();
            this.beginPath();
            this.moveTo(x + r, y);
    
            this.arcTo(x + w, y, x + w, y + h, r);
            this.lineTo(x + w, y + 31 + 7);
            this.lineTo(x + w + 10, y + 31);
            this.lineTo(x + w, y + 31 - 7);
    
            this.arcTo(x + w, y + h, x, y + h, r);
            this.arcTo(x, y + h, x, y, r);
            this.arcTo(x, y, x + w, y, r);
            this.closePath();
    
            this.strokeStyle = '#8bdf49';
            this.lineWidth = 2;
            this.stroke();
            this.fillStyle = "#a0e75a";
            this.fill();
    
            this.textBaseline = 'top';
            this.textAlign = 'left';
            this.fillStyle = '#000';
            self.writeTextArr(this, textArr, lingheight, x + padding, y + padding);
            //writeMulLineText(this, text, 32, 30, x + padding, y+padding);
            //this.fillText(text, x + padding, y+padding);
            this.restore();
    
            return this;
          }
    
          CanvasRenderingContext2D.prototype.drawHelloText = function (x, y, r, text) {
            this.save();
            this.font = "18px Helvetica";
            var h = 32;
            var w = this.measureText(text).width + 2 * padding;
            x = x - w / 2;
            gY = y + h + 22;
            if (w < 2 * r) r = w / 2;
            if (h < 2 * r) r = h / 2;
    
            this.beginPath();
            this.moveTo(x + r, y);
            this.arcTo(x + w, y, x + w, y + h, r);
            this.arcTo(x + w, y + h, x, y + h, r);
            this.arcTo(x, y + h, x, y, r);
            this.arcTo(x, y, x + w, y, r);
            this.closePath();
            this.fillStyle = "#cecece";
            this.fill();
            this.textBaseline = 'middle';
            this.textAlign = 'center';
            this.fillStyle = '#fff';
            this.fillText(text, cW / 2, y + h / 2);
            this.restore();
    
            return this;
          }
    
          CanvasRenderingContext2D.prototype.transFlag = function (x, y, r, text) {
            this.save();
            this.font = "18px Helvetica";
            var h = 32;
            text = '√ 已翻译';
            var transpading = 10;
            var w = this.measureText(text).width + 2 * transpading;
            gY = y + h + verticlaSpace;
            if (w < 2 * r) r = w / 2;
            if (h < 2 * r) r = h / 2;
            this.beginPath();
            this.moveTo(x + r, y);
            this.arcTo(x + w, y, x + w, y + h, r);
            this.arcTo(x + w, y + h, x, y + h, r);
            this.arcTo(x, y + h, x, y, r);
            this.arcTo(x, y, x + w, y, r);
            this.closePath();
            this.fillStyle = "#cecece";
            this.fill();
            this.textBaseline = 'middle';
            this.textAlign = 'left';
            this.fillStyle = '#fff';
            this.fillText(text, x + transpading, y + h / 2);
            this.restore();
            return this;
          }
          CanvasRenderingContext2D.prototype.drawQrcode = function (img, x, y) {
            self.drawStarImg(this, y);
            var h = 200 + padding;
            var w = 200 + padding;
            var r = textRadius;
            if (w < 2 * r) r = w / 2;
            if (h < 2 * r) r = h / 2;
            this.save();
            this.beginPath();
            this.moveTo(x + r, y);
            this.arcTo(x + w, y, x + w, y + h, r);
            this.arcTo(x + w, y + h, x, y + h, r);
            this.arcTo(x, y + h, x, y, r);
    
            this.lineTo(x, y + 31 + 7);
            this.lineTo(x - 10, y + 31);
            this.lineTo(x, y + 31 - 7);
            this.arcTo(x, y, x + w, y, r);
            this.closePath();
            this.strokeStyle = '#d3d3d3';
            this.lineWidth = 2;
            this.stroke();
            this.fillStyle = "#fff";
            this.fill();
            this.drawImage(img, x + 10, y + 10, 200, 200)
            gY = y + h + verticlaSpace;
          }
        },
        methods: {
          getData(ev) {
            let self = this;
            // 默认页面加载的数据
            if (ev == undefined) {
              self.$http.get('https://h5.tangdaoya.com/game/wechat/getstarbytype/影视大咖')
                .then(res => {
                  let result = res.data.list;
    //              self.itemList = result;
                  self.recommendList = result;
                }).catch(error => {
                Toast('网络出现错误,请稍后再试');
              });
    
            } else {
              // 传递参数请求接口
              self.$http.get('https://h5.tangdaoya.com/game/wechat/getstarbytype/' + ev)
                .then(res => {
                  console.log(res.data.list);
                  let result = res.data.list;
                  self.itemList = result;
                }).catch(error => {
                Toast('网络出现错误,请稍后再试');
              });
            }
          },
          drawResult(a, b, c, e) {
            let self = this;
            self.starName = a;
            self.starNickName = b;
            self.starID = c;
            starImgObg = e.target;
            Toast('正在生成中~');
            self.getChatContent();
          },
          gameStart() {
            let self = this;
            var canvas = document.createElement('canvas');
            canvas.width = cW;
            canvas.height = cHeigth;
            var context = canvas.getContext('2d');
            context.fillStyle = '#ebebeb';
            context.fillRect(0, 0, cW, cHeigth);
            context.drawImage(headerEle, 0, 0);
            self.writeHeader(context, starName);
            gY = 115;
    
            if (template == 1) {
              context.drawHelloText(cW / 2, gY, textRadius, com.getTime(true));
            } else {
              context.drawHelloText(cW / 2, gY, textRadius, com.getDateTime());
            }
    
            for (var i = 0; i < chatContent.length; i++) {
              var contentTemp = chatContent[i]['content'];
              if (com.is_weixn()) {
                contentTemp = contentTemp.replace(/xxx/ig, nickName);
              } else {
                contentTemp = contentTemp.replace(/是xxx吗?/ig, '');
              }
              if (chatContent[i] && chatContent[i]['star']) {
                if (chatContent[i]['isImg']) {
                  // context.drawQrcode(codeEle, starTextL, gY);
                  context.drawQrcode(codeEle, starTextL, gY);
    
                } else {
                  context.drawStarText(starTextL, gY, textRadius, contentTemp, chatContent[i]['translate']);
                  if (i == 0 && template == 2) {
                    self.drawHello(context, starNickName);
                    gY = gY + 12;
                  }
                }
              } else {
                context.drawSelfText(starTextR, gY, textRadius, contentTemp);
              }
            }
            // context.drawImage(footerEle, 0, cHeigth - 78, 640, 78);
            context.drawImage(footerEle, 0, cHeigth - 78, 640, 78);
            console.log('canvas'+canvas);
            console.log(canvas);
              console.log(canvas.toDataURL("image/png", 0.6));
            self.saveImage(canvas.toDataURL("image/png", 0.6))
          },
          saveImage(data) {
            $('#targetImg').attr('src', data);
          },
          getChatContent() {
            let self = this;
            var server = "https://h5.tangdaoya.com/game/wechat/getChatContent/" + 2;//this.starID
            self.$http.get(server).then(res => {
              let result = res.data;
              this.chatContent = result.chatContents;
              chatContent = this.chatContent;
              this.template = result['template'];
              if (result['changeContent'] == 0) {
                //Selector('.commonbtn-playAgain').style.display = "none";
                this.ShowAgain = false;
              } else if (result['changeContent'] == 1) {
                this.ShowAgain = true;
              }
              self.gameStart();
            }).catch(error => {
              //Toast('网络出现错误,请稍后再试');
            });
    
    
          },
          changeContent() {
            $('#result').attr('src', '');
            $('#page2').removeClass('active');
            $('#page3').addClass('active');
          },
          drawStarImg(ctx, y) {
            ctx.drawImage(starImgObg, headL, y, headW, headW);
          },
          writeHeader(ctx, name) {
            var y = 67;
            ctx.save();
            ctx.textBaseline = 'middle';
            ctx.textAlign = 'center';
            ctx.fillStyle = '#fff';
            ctx.font = "19px Arial";
            ctx.fillText(com.getTime(), cW / 2, 18);
            ctx.font = "29px Arial";
            ctx.fillText(name, cW / 2, y);
            ctx.restore();
          },
          drawSelfImg(ctx, y) {
            //ctx.drawImage(selfImgObg, headR, y, headW, headW)    ;
            // ctx.drawImage(head2Ele, headR, y, headW, headW);
            ctx.drawImage(head2Ele, headR, y, headW, headW);
          },
          getText2Arr(ctx, text, rw) {
            var textArr = [];
            for (var i = 0; com.getTrueLength(text) > 0; i++) {
              var tl = com.cutString(text, rw);
              if (ctx.measureText(text.substr(0, tl)).width < 350)
                tl = tl + 1;
              for (var j = 0; j < tl; j++) {
                var temp = text.substr(tl, 1);
                if (temp == " " || temp.charCodeAt(0) > 128 || temp == "") {
                  break;
                }
                else {
                  tl = tl - 1;
                }
              }
              //ctx.fillText(text.substr(0, tl).replace(/^s+|s+$/, ""), offsetX , i * lineheight + offsetY);
              textArr.push(text.substr(0, tl));
              text = text.substr(tl);
            }
    
            return textArr;
          },
          writeTextArr(ctx, textArr, lineheight, offsetX, offsetY) {
            for (var i = 0; i < textArr.length; i++) {
              ctx.fillText(textArr[i].replace(/^s+|s+$/, ""), offsetX, i * lineheight + offsetY);
            }
          }
        }
      }
    </script>
    <style lang="less" rel="stylesheet/less" scoped>
      .s-content {
        margin-top: 50px;
        height: 1000px;
      }
    
      .s-recommend {
        height: 30px;
        line-height: 2em;
        border-bottom: 1px solid #F0F0F7;
        .span-1 {
          background-color: #FF4852;
          color: white;
          margin-left: 10px;
        }
      }
    
      .s-recommend-people {
         100%;
        height: 100px;
        margin-top: 5px;
        border-bottom: 3px solid #F0F0F7;
        ul {
           100%;
          height: 100px;
          margin: 0 auto;
          li {
            position: relative;
            display: inline-block;
            list-style: none;
             25%;
            height: 80px;
            margin-top: 10px;
            margin-left: 6%;
            .s-img {
               50px;
              height: 50px;
              margin: 0 auto;
              img {
                 50px;
                height: 50px;
                border-radius: 10px;
              }
            }
            .s-title {
               50px;
              height: 20px;
              border: 1px solid balck;
              margin: 0 auto;
              text-align: center;
              margin-top: 5px;
              font-size: 0.8em;
            }
          }
        }
      }
    
      .s-category {
        height: 30px;
        line-height: 2em;
        border-bottom: 1px solid #F0F0F7;
        .span-2 {
          background-color: #139F00;
          color: white;
          margin-left: 10px;
        }
      }
    
      .s-category-a {
        height: 50px;
        margin-top: 5px;
        a {
          border: 1px solid #9b9b9b;
          display: inline-block;
          border-radius: 10px;
          padding: .15rem 0.31rem;
          display: inline-block;
          margin-top: 12px;
          height: 25px;
          line-height: 1.6em;
          margin-left: 10px;
        }
      }
    
      .s-category-list {
        margin-top: 10px;
        height: 700px;
        ul {
           100%;
          height: 100%;
          li {
            border-bottom: 1px solid #F0F0F7;
             100%;
            height: 80px;
            margin-top: 10px;
            .s-a-1 {
              float: left;
               78%;
              height: 80px;
              .s-a-img {
                float: left;
                 60px;
                height: 60px;
                background-color: gray;
                margin-top: 10px;
                margin-left: 10px;
                border-radius: 10px;
                img {
                   60px;
                  height: 60px;
                  border-radius: 10px;
                }
              }
              .s-a-title {
                float: left;
                height: 60px;
                margin-top: 10px;
                margin-left: 5px;
                .s-a-title-name {
                  margin-top: 10px;
                  color: black;
                  font-size: 0.8em;
                }
                .s-a-title-play {
                  margin-top: 10px;
                  .s-people {
                    font-size: 0.8em;
                  }
                  .icon-star {
                    font-size: 0.9em;
                  }
                }
              }
            }
            .s-a-2 {
              float: right;
               60px;
              height: 27px;
              border: 1px solid #EFB31D;
              margin-top: 25px;
              margin-right: 20px;
              border-radius: 5px;
              line-height: 1.8em;
              text-align: center;
              color: #EFB31D;
              .icon-more {
                display: inline-block;
    
                color: #EFB31D;
    
              }
            }
          }
        }
      }
    
      /* 制作页样式*/
    
      .box {
        display: none;
        .loading {
          position: relative;
           75px;
          margin-top: 40%;
        }
        .loading-text {
          position: relative;
          text-align: center;
          color: #FF4303;
          margin-top: 20px auto;
          font-family: "微软雅黑";
          letter-spacing: 1px;
        }
      }
    
      .commonbtn-share {
        display: inline-block;
        margin: 0.5%;
        padding: 0.5em 0em;
        font-size: 16px;
        color: white;
        background-color: #FF4303;
        border-radius: 40px;
         35%;
        box-sizing: border-box;
        -webkit-box-sizing: border-box;
      }
    
      .active .loading {
        -webkit-animation: roting 1s linner infinite;
      }
    </style>
  • 相关阅读:
    ubuntu18【合上盖子不休眠】
    linux和windows双系统开机显示 Minimal BASHlike line editingis supported xxxxxx
    Linux下opera不支持h5播放器的解决方法
    linux openjdk路径
    Linux安装redis tar.gz
    dpkg 安装deb文件
    Linux破解Navicat15
    kali设置grub主题
    kali安装git tar.gz
    kali 安装 teamviewer 显示检测到wayland
  • 原文地址:https://www.cnblogs.com/lvhw/p/6822317.html
Copyright © 2011-2022 走看看