翻译小程序的实现

2018-11-13  本文已影响115人  sweetBoy_9126

一、页面的实现

@import "./assets/iconfont/iconfont.wxss";
.container {
  padding: 0;
  background-color: #f5fafe;
  height: 100vh;
  display: flex;
  flex-direction: column;
  /* align-items: center; */
  box-sizing: border-box;
  font-size: 30rpx;
  color: #333;
} 
.copyright {
  align-self: center;
  flex: 1;
  display: flex;
  align-items: flex-end;
  padding-bottom: 20rpx;
  font-size: 28rpx;
  color: #999;
}
.view-hover,
.navigator-hover {
  background-color: #f3f3f3!important;
}

{
  "pages":[
    /*pages里的页面顺序决定了先展现的是哪一个页*/
    "pages/index/index",
    "pages/change/change",
    "pages/history/history"
  ],
  "window":{
    "backgroundColor":"#333",
    "backgroundTextStyle":"light",
    "navigationBarBackgroundColor": "#1c1b21",
    "navigationBarTitleText": "立发翻译",
    "navigationBarTextStyle":"#fff"
  },
  "tabBar":{
    "borderStyle":"white",
    "position":"top",
    "color":"#595959",
    "selectedColor":"#1c1b21",
    "list": [
      {
        "pagePath": "pages/index/index",
        "text":"翻译"
      },
      {
        "pagePath":"pages/history/history",
        "text":"历史"
      }
    ]
  }
}

index页面的实现

1、 在小程序中一个index页面主要是由index.wxml、index.wxss、index.js、等组成的。
2、小程序中的WXML 中的动态数据均来自index.js中对应 Page 的 data。
3、看下我的index.wxml页面代码:

<!--index.wxml-->
<view class="container page-index">
  <view class='change'>
    <navigator url='/pages/change/change' hover-class='navigator-hover'>
      <text>到{{curLang.chs}}</text>
      <text class='iconfont icon-down'></text>
    </navigator>
  </view>
  <view class='input-area'>
    <text class='iconfont icon-close' hidden='{{hideClearIcon}}' bindtap='onTapClose'></text>
    <view class='textarea-wrap'>
      <textarea placeholder='请输入要翻译的文本' placeholder-style='color:#8995a1' bindinput='onInput' bindconfirm='onConfirm' bindblur='onConfirm' value='{{query}}'></textarea>
    </view>
    <view class='text-area'>
      <view class='text-title'>译文</view>
      <view class='text-result' wx:for="{{result}}" wx:key="index">
        <text selectable='true'>{{item.dst}}</text>
      </view>
    </view>
  </view>
  <view class='copyright'>
    <text>© 2018 立发翻译</text>
  </view>
</view>

在小程序中

那么index.wxml页面,差不多就可以完成了,然后就是index.wxss和index.js,与css大同小异,遇到不能用的属性是可以看下微信小程序api,总有你需要的效果,如下是index.wxss代码:

/**index.wxss**/
.change {
  color: #8995a1;
  font-size: 24rpx;
  padding: 20rpx 40rpx;
  display: flex;
  align-items: center;
}
.change .icon-down {
  color: #8995a1; 
  font-size: 20rpx;
}
input-area {
  position: relative;
}
.textarea-wrap {
  background: #fff;
  border-bottom: 1px solid #c7cee0;
}
.input-area textarea {
  background-color: #fff;
  padding: 30rpx 0 30rpx 30rpx;
  width: calc(100% - 48rpx);
  margin: 0;
  box-sizing: border-box;
}
.input-area .icon-close {
  position: absolute;
  right: 12rpx;
  top: 90rpx;
  z-index: 100;
  font-size: 40rpx;
  color: #888;
}
.input-area .text-area {
  min-height: 80rpx;
  padding: 40rpx;
  background-color: #fff;
}
.input-area .text-title {
  font-size: 28rpx;
  color: #8995a1;
}
.input-area .text-result {
  padding: 20rpx 0;
}

这里需要说的就是因为在文本中输入内容后会有一个icon显示,以便于我们删除文本中的内容,但如果输入框的宽度撑满,这个icon会被输入框遮住,所以我在写输入框的样式时,让输入框的宽度没有撑满,让出一些,以便于icon的点击

index.js
//index.js
//index.js
import translate from '../../utils/api.js'
const app = getApp()

Page({
  data: {
    hideClearIcon: true,
    query: '',
    result: null,
    curLang: {}
  },
  //页面加载时触发。一个页面只会调用一次,可以在 onLoad 的参数中获取打开当前页面路径中的参数
  onLoad: function(options) {
    //如果当前页面有查询参数,那么直接把查询参数的内容赋给你的query,也就是从历史页面过来,把历史数据的查询参数传过来
    if(options.query){
      this.setData({query: options.query})
    }
  },
  onShow(){
    //如果从历史页面过来,当前设置的语言不是之前的语言
    if(this.data.curLang !== app.globalData.curLang){
      this.setData({'curLang': app.globalData.curLang})
      //当你从历史页面点某个历史过来的时候,它会自动翻译,所以就是触发了onConfirm
      this.onConfirm()
    }
  },
  onInput(e){
    this.setData({query: e.detail.value})
    if(this.data.query){
      this.setData({hideClearIcon: ''})
    }else{
      this.setData({hideClearIcon: true})
    }
  },
  onTapClose(){
    this.setData({query: '',hideClearIcon: true})
    this.setData({result: ''})
  },
  onConfirm(){
    if(!this.data.query) return
    translate(this.data.query,{from: 'auto', to: this.data.curLang.lang})
    .then(res=>{
      this.setData({'result': res.trans_result})
      let history = wx.getStorageSync('history') || []
      history.unshift({query: this.data.query, result: res.trans_result[0].dst})
      history.length = history.length > 10 ? 10 : history.length
      wx.setStorageSync('history', history)
    })
  }

})

Page()

看了微信小程序的文档后都知道,在js文件中,Page(Object) 函数用来注册一个页面。接受一个 Object 类型参数,其指定页面的初始数据、生命周期回调、事件处理函数等。

其中 key 可以以数据路径的形式给出,支持改变数组中的某一项或对象的某个属性,如 array[2].message,a.b.c.d,并且不需要在 this.data 中预先定义。

注意:
1、 直接修改 this.data 而不调用 this.setData 是无法改变页面的状态的,还会造成数据不一致。
2、 仅支持设置可 JSON 化的数据。
3、 单次设置的数据不能超过1024kB,请尽量避免一次设置过多的数据。
4、 请不要把 data 中任何一项的 value 设为 undefined ,否则这一项将不被设置并可能遗留一些潜在问题

页面逻辑

1、实现在输入框中输入内容时,对onInput进行绑定,显示icon,通过设置hideClearIcon的值为false还是true来控制icon
2、在icon显示后,点击icon删除输入内容,对onTapClose进行事件绑定
3、在输入确定内容后对内容进行翻译,对onConfirm进行绑定,准备翻译,然后我想到翻译是一件事情,所以我对它进行了一个封装,在utils里加了一个api.js,这里我用到百度翻译的接口,所以需要查阅一下百度翻译api,以下是api.js:

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

const appid = '20180912000205732'
const key = 'oowRg0jxzoSgwCfAfyVn'
//如果你不传递第二个参数那么这个参数默认就是 { from: 'auto', to: 'auto'},
//如果你第二个参数里没有传from那么默认就是from的值为'auto',如果没传to默认to的值也为'auto',
//如果传了from或者to就是你传递的值,其实就是{from: 形参, to: 形参}
function translate(q, { from = 'auto', to = 'auto' } = { from: 'auto', to: 'auto'}) {
  return new Promise((resolve, reject) => {
    let salt = Date.now()
    let sign = md5(`${appid}${q}${salt}${key}`)
    wx.request({
      url: 'https://fanyi-api.baidu.com/api/trans/vip/translate',
      data: {
        q,
        from,
        to,
        appid,
        salt,
        sign
      },
      success(res) {
        if(res.data && res.data.trans_result) {
          // console.log(res,'1')
          // console.log(res.data,'2')
          // console.log(res.data.trans_result,'3')
          resolve(res.data)
        } else{
          reject({status: 'error', msg: '翻译失败'})
          wx.showToast({
            title: '翻译失败',
            icon: 'none',
            duration: 3000
          })
        }
      },
      fail() {
        reject({status: 'error', msg: '翻译失败'})
        wx.showToast({
          title: '网络异常',
          icon: 'none',
          duration: 3000
        })
      }
    })
  })
}
module.exports.translate = translate

在微信小程序中用wx.request请求数据,需要注意的是百度翻译api要用md5进行加密,所以也需要在utils文件夹中再加入一个md5.min.js文件,这里md5文件最好是用压缩过的,再由import来引入api.js文件中,但我没有直接去使用它,而是用Promise对它进行一个封装

代码解析:
1、 wx.request发起 HTTPS 网络请求。使用前请注意阅读相关说明
2、 wx.showToast(Object object)显示消息提示框
3、 一个模块要想对外暴露其内部的私有变量与函数,只能通过 module.exports 实现。exports: 通过该属性,可以对外共享本模块的私有变量与函数

最后在index.js页面中用import引入api.js,这样就完成了index页面的接口问题,再就是index页面的参数问题,如要翻译成什么语言,这就需要change页面来实现了

change页面的实现

先看下我的change.wxml代码:

<view class="container lang-list">
  <view class='title'>翻译成</view>
  <view class='item' data-chs="{{language.chs}}" data-lang="{{language.lang}}" data-index="{{index}}" wx:for="{{langList}}" wx:key="index" wx:for-item="language" bindtap='onTapItem' hover-class='view-hover'>
    <view class='item-inner'>
      <text>{{language.chs}}</text>
      <text class='iconfont icon-duihao' wx:if="{{index===curLang.index}}"></text>
    </view>
  </view>
</view>

再看下change.js代码:

//change.js
const util = require('../../utils/util.js')
const app = getApp()
Page({
  data: {
    curLang: {},
    langList: app.globalData.langList
  },
  //当change这个页面显示/切入前台时触发
  onShow(){
    this.setData({ 'curLang': app.globalData.curLang})
  },
  onTapItem(e){
    //存储所有以data-开头的属性的值,
    //你在页面上定义的data-chs="{{language.chs}}" data-lang="{{language.lang}}"
  //data-index="{{index}}比如你点击中文,
  //langObj就是{chs: "中文", index: 1, lang: "zh"},这里键名与data-后面的对应
    let langObj = e.currentTarget.dataset
    wx.setStorageSync("curLang", langObj)
    this.setData({"curLang": langObj})
    app.globalData.curLang = langObj
    wx.switchTab({
      url: '/pages/index/index',
    })
  }
})

写到这里的时候,我们发现需要一个函数来保存变量,以便于在index页面翻译,也便于在change页面选择翻译语言的时候引用,所以我把这个函数写在app.js中,方便其他页面调用,调用方法便是const app = getApp(),以下是app.js:

//app.js
App({
  onLaunch: function () {
    //默认一进入页面拿到你的本地 缓存里的curLang,如果没有就读取alobalData.langList里的第一个
    this.globalData.curLang = wx.getStorageSync('curLang') || this.globalData.langList[0]
  },
  globalData: {
    curLang: {},
    langList: [
      {
        'chs': '英文',
        "lang": 'en',
        "index": 0
      },
      {
        'chs': '中文',
        'lang': 'zh',
        "index": 1
      },
      {
        'chs': '日语',
        'lang': 'jp',
        "index": 2
      },
      {
        'chs': '韩语',
        'lang': 'kor',
        "index": 3
      },
      {
        'chs': '法语',
        'lang': 'fra',
        "index": 4
      },
      {
        'chs': '西班牙语',
        'lang': 'spa',
        "index": 5
      },
      {
        'chs': '阿拉伯语',
        'lang': 'ara',
        "index": 6
      }
    ]
  }
})


以上两个文件中的js需要注意的代码:

wx.setStorageSync(string key, Object|string data)
(1) string key
本地缓存中指定的 key
(2) Object|string data
需要存储的内容

Object|string wx.getStorageSync(string key)
(1) string key
本地缓存中指定的 key
(2)Object|string data
key对应的内容

然后在联系上最初的index页面,我们就可以选择需要翻译的语言了,同时在本地缓存中存储了当前翻译的语言,下次打开小程序时,还是上次保存的翻译语言

history页面实现

看一看history.wxml:

<!--pages/history/history.wxml-->
<scroll-view scroll-y class="container">
  <view class="history-list">
    <view class="title">翻译历史</view>
    <view class="item" wx:for="{{history}}" wx:key="index" bindtap='onTapItem' data-query="{{item.query}}" data-langId="{{item.langIndex}}">
      <view class="query">{{item.query}}</view>
      <view class="result">{{item.result}}</view>
    </view>
  </view>
</scroll-view>

history.wxml中主要的就是把它当做一个数组去渲染,然后点击对应数组,跳转到index页面,进行当前语言翻译,而这些功能需要在history.js和change.js中去实现

看一看history.js:

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

Page({
  data: {
    history: []
  },
  onShow: function() {
    this.setData({history: wx.getStorageSync('history')})
  },
  onTapItem: function(e) {
    wx.reLaunch({
      url: `/pages/index/index?query=${e.currentTarget.dataset.query}`
    })
  }
})

当执行以上代码时,便会用到index.js中onConfirm事件的这一段代码:

let history = wx.getStorageSync('history') || []
      history.unshift({query: this.data.query, result: res.trans_result[0].dst})
      history.length = history.length > 10 ? 10 : history.length
      wx.setStorageSync('history', history)

其中存储好history的值,便于history页面去使用

当切换到index页面时,会用到index.js中的这些代码:

 onLoad: function (options){
    // console.log('lonload')
    // console.log(options,55)
    if(options.query) {
      this.setData({query: options.query})
    }
  },
  onShow: function(){
    // console.log(this.data.curLang.lang)
    // console.log(app.globalData.curLang.lang)
    if(this.data.curLang.lang !== app.globalData.curLang.lang) {
      this.setData({curLang: app.globalData.curLang})
      this.onConfirm()
    }
  }

其中onLoad在加载页面中设置query的值,onShow在显示页面后翻译query的值

这样就构成了整个小程序目前需要的需求,如果还想有其他更多的需求,可以在此代码上继续添加

上一篇 下一篇

猜你喜欢

热点阅读