微信小程序(翻译小助手)项目实战

效果展示图:

在这里插入图片描述
在这里插入图片描述

这个项目主要的难点在于api的调用,只有俩个页面,页面布局相对简单一些.

1.通过百度翻译开放平台,申请百度翻译开发者账号,获取百度翻译中通用翻译API服务的相关信息.
2.构建翻译首页:
index.wxml:

<!--index.wxml-->
<view class='container'>
  <view class='to-change-page'>
    <navigator
      url='/pages/change/change'
    >
      <text class='lang'>翻译成{{curLang.chinese}}</text>
      <text class='iconfont icon-down'></text>
    </navigator>    
  </view>

  <view class='input-area'>
    <view class='textarea-container'>
      <textarea
        placeholder='请输入要翻译的文本'
        placeholder-style='color: #8995a1;'
        value='{{query}}'
        bindinput='onInput'
        bindconfirm='onConfirm'
      ></textarea>
      <text class='iconfont icon-close'
        bindtap='onTapClose'
        hidden='{{hideCloseIcon}}'
      ></text>
    </view>
  </view>

  <button
    bindtap='onConfirm'
  >点击翻译</button>

  <view class='output-area'>
    <text class='title'>译文</text>
    <view class='result-container'>
      <view class='result'
        wx:if='{{translateResult}}'
      >{{translateResult}}</view>
    </view>
  </view>
  <view class='copyright'>
    <text>© 2019 strugglebak</text>
  </view>
</view>

index.js:

import {translate} from '../../utils/api.js'

const app = getApp()
Page({
  data: {
    curLang: {},
    hideCloseIcon: true,
    query: '',
    translateResult: '',
  },
  onLoad: function (options) {
    console.log('options query', options.query)
    if (options.query) {
      this.setData({
        query: options.query
      })
    }
  },
  onShow: function () {
      this.setData({
        curLang: app.globalData.curLang
      })
      this.onConfirm();
  },
  onInput: function (e) {
    this.setData({
      query: e.detail.value
    })
    if (this.data.query.length > 0) {
      this.setData({
        hideCloseIcon: false
      })
    } else {
      this.setData({
        hideCloseIcon: true
      })
    }
  },
  onConfirm: function () {
    translate(
      this.data.query,
      {
        from: 'auto',
        to: this.data.curLang.lang
      }
    ).then(data=> {
      let resultArray = []
      for (let i=0; i<data.trans_result.length; i++) {
        resultArray.push(data.trans_result[i])
      }
      console.log('resultArray', resultArray)
      let src = []
      let dst = []
      resultArray.forEach(key=> {
        src.push(key['src'])
        dst.push(key['dst'])
      })
      let queryString = src
      let resultString = dst
      console.log(queryString, resultString)
      this.setData({
        translateResult: resultString
      })
     })
  },
  onTapClose: function () {
    this.setData({
      query: '',
      hideCloseIcon: true,
      translateResult: ''
    })
  }
})

index.wxss:

/**index.wxss**/
view.to-change-page {
  display: flex;
  align-items: center;
  color: #8995a1;
  font-size: 24rpx;
  padding: 20rpx 40rpx;
}
navigator .iconfont {
  font-size: 20rpx;
  color: #8995a1;
}
/* view.input-area {
  border-bottom: 1px solid #c7cee0;
} */
view.textarea-container {
  background: white;
  position: relative;
  box-shadow:1px 2px 3px 4px #ccc
}
view.textarea-container textarea {
  background: white;
  padding: 30rpx;
  padding-right: 0;
  width: calc(100% - 110rpx);
  font-size: 34rpx;
}
view.textarea-container .iconfont {
  position: absolute;
  top: 30rpx; right: 40rpx;
  z-index: 999;
  font-size: 40rpx;
  color: #888;
}

view.output-area {
  min-height: 180rpx;
  background: white;
  padding: 40rpx;
  box-shadow:1px 2px 3px 4px #ccc
}
view.output-area text.title {
  font-size: 28rpx;
  color: #8995a1;
}
view.output-area .result-container {
  padding: 20rpx 0;
  font-size: 34rpx;
}
view.output-area .result {
  word-break: break-all;
}

button {
  margin: 20rpx 20rpx;
  font-size: 32rpx;
  position: relative;
}
button::after {
  position: absolute;
  content: '';
  display: block;
  border: 1px solid black;
  top: 0; left: 0;
  bottom: 0; right: 0;
  transform-origin: 0 0;
  z-index: 2;
}

view.copyright {
  color: #999;
  display: flex;
  justify-content: center;
  flex: 1;
  align-items: flex-end;
  font-size: 28rpx;
  padding-bottom: 20rpx;
}

3.封装api接口:
api.js:

import md5 from './md5.min.js'

const appid = "20190217000267988"
const key = "3Y5ZIcch3mbq5fX6Q7EC"
const url = "https://fanyi-api.baidu.com/api/trans/vip/translate"

function translate(
  q, 
  { from = 'auto', to = 'en' } = { from: 'auto', to: 'en' },
)
{
  return new Promise((resolve, reject)=> {
    let salt = Date.now()
    let sign = md5(`${appid}${q}${salt}${key}`)
    wx.request({
      url, 
      data: {
        q, from, to, appid, salt, sign
      },
      success(response) {
        let data = response.data
        if (data && data.trans_result) {
          resolve(data)
        } 
      }
    })
  })
}

module.exports = {
  translate: translate
}

3.引入md5.min.js文件:

4.构建change页面:

change.wxml:

<!-- change.wxml -->
<view class='container'>
  <text class='title'>翻译成</text>
  <view class='lang-list'>
    <view class='lang-wrapper'>
      <view class='item'
        wx:for='{{langList}}'
        wx:key='index'
        wx:for-item='langItem'
        bindtap='onTapItem'
        data-index='{{index}}'
        data-lang='{{langItem.lang}}'
        data-chinese='{{langItem.chinese}}'
      >
        <view class='lang'>{{langItem.chinese}}</view>
        <text class='iconfont icon-ok'
          wx:if='{{index===curLang.index}}'
        ></text>
      </view>    
    </view>  
  </view>
</view>

change.js:

// pages/change/change.js
const app = getApp();

Page({

  /**
   * 页面的初始数据
   */
  data: {
    curLang: {},
    langList: app.globalData.langList
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    this.setData({
      curLang: app.globalData.curLang
    })
  },

  /**
   * onTapItem--监听 change 页 item 项被 tap
   */
  onTapItem: function (e) {
    let langObject = e.currentTarget.dataset
    console.log(langObject)
    // 本地设置
    this.setData({
      curLang: langObject
    })
    // 全局设置
    app.globalData.curLang = langObject
    wx.switchTab({
      url: '/pages/index/index'
    })
  }
})

change.wxss:

/* change.wxss */
/* change.wxss */
.container {
  background: #f8f8f8;
}

.title {
  background: white;
  border-bottom: 1px solid #ececec;
  padding: 20rpx 40rpx;
  color: #aaa;
  font-size: 28rpx;
}

.lang-wrapper {
  padding-left: 40rpx;
}

.lang-wrapper .item {
  padding: 20rpx 40rpx 20rpx 0;
  background: white;
  display: flex;
  flex-direction: row;
  align-items: center;
  border-bottom: 1px solid #ececec;
  font-size: 32rpx;
}
.item .lang {
  flex: 1;
}
.item .iconfont {
  margin-left: auto;
  color: #aaa;
  font-size: 28rpx;
}


5.构建翻译历史页面(history)

history.wxml:

<!-- history.wxml -->
<view class='container'>
  <text class='history-title {{state}}'>翻译历史</text>

  <scroll-view scroll-y class='history-result-list'>
    <view class='history-result'
      wx:for='{{history}}'
      wx:for-item='historyItem'
      wx:key='index'
      bindtap='onTapReLaunch'
      data-query='{{historyItem.query}}'
    >
      <view class='orign-text'>{{historyItem.query}}</view>
      <view class='tanslate-text'>{{historyItem.result}}</view>
    </view> 
  </scroll-view>

</view>

history.js:

// pages/history/history.js
const app = getApp()

Page({

  /**
   * 页面的初始数据
   */
  data: {
    history: [],
    state: ''
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    this.setData({
      history: wx.getStorageSync('history')
    })
    let history = this.data.history
    if (history && history.length > 0) {
      this.setData({
        state: 'stiky'
      })
    } else {
      this.setData({
        state: ''
      })
    }
  },

  onTapReLaunch: function (e) {
    console.log('data-set', e.currentTarget.dataset)
    let url = `/pages/index/index?query=${e.currentTarget.dataset.query}`
    wx.reLaunch({
      url
    })
  }
})

history.wxss:

/* history.wxss */
view.container {
  padding: 40rpx 0;
  display: flex;
  height: 100vh;
}
.history-title {
  font-size: 26rpx;
  line-height: 38rpx;
  color: #8995a1;
  position: fixed;
  top: 0; left: 0;
  padding: 40rpx;
  overflow: hidden;
  width: 100%;
  z-index: 999;
  transition: all 0.3s;
}
.history-title.stiky {
  background-color: white;
}
scroll-view.history-result-list {
  margin-top: 50rpx;
  background-color: #f5fafe;
}
view.history-result {
  margin-top: 40rpx;
  display: flex;
  flex-direction: column;
}
view.history-result:last-child {
  margin-bottom: 40rpx;
}
.orign-text {
  color: #8995a1;
  padding: 0 40rpx;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.tanslate-text {
  margin-top: 16rpx;
  padding: 0 40rpx;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}

app.js:

//app.js
App({
  onLaunch: function () {
    // 展示本地存储能力
    this.globalData.curLang = wx.getStorageSync('curLang') 
    || this.globalData.langList[0]
  },
  globalData: {
    curLang: {},
    langList: [
      {
        'lang': 'en',
        'index': 0,
        'chinese': '英文'
      },
      {
        'lang': 'zh',
        'index': 1,
        'chinese': '中文'
      },
      {
        'lang': 'jp',
        'index': 2,
        'chinese': '日语'
      },
      {
        'lang': 'kor',
        'index': 3,
        'chinese': '韩语'
      },
      {
        'lang': 'fra',
        'index': 4,
        'chinese': '法语'
      },
      {
        'lang': 'spa',
        'index': 5,
        'chinese': '西班牙语'
      },
      {
        'lang': 'ara',
        'index': 6,
        'chinese': '阿拉伯语'
      }
    ]
  }
})

app.json:

{
  "pages": [
    "pages/index/index",
    "pages/history/history",
    "pages/change/change"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#1c1b21",
    "navigationBarTitleText": "翻译小助手",
    "navigationBarTextStyle": "white"
  },
  "tabBar": {
    "position": "top",
    "color": "#595959",
    "selectedColor": "#1c1b21",
    "borderStyle": "white",
    "list": [
      {
        "text": "翻译",
        "pagePath": "pages/index/index"
      },
      {
        "text": "历史",
        "pagePath": "pages/history/history"
      }
    ]
  },
  "sitemapLocation": "sitemap.json"
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值