После завершения проекта небольшой программы начальник дал мне зарплату в 6 тысяч~

Vue.js
После завершения проекта небольшой программы начальник дал мне зарплату в 6 тысяч~

Привет всем, я@IT·平头哥联盟изГлавный специалист по заполнению карьеров——Сунан(Юг · Вс), сегодня я хочу поделиться с вами небольшим программным проектом, недавно сделанным компанией, некоторыми хорошими выводами и подводными камнями, с которыми столкнулись в процессе, я надеюсь, что это может принести некоторое удобство другим осадным львам, и я надеюсь Чтобы иметь возможность Как говорится в названии, ваш босс повысит вам зарплату после того, как вы закончите ~

相关图片

Сегодня первый день Фестиваля Середины Осени.Я проснулась очень рано утром праздника.Не знаю почему,может потому что на обратном пути из последнего онлайн проекта компании обнаружила небольшой баг ночь.

相关图片

Вышесказанное полная ерунда, а теперь начнем притворяться серьезными, пожалуйста, пристегните ремни безопасности, вы можете ехать посередине, пожалуйста, обратите внимание на безопасность! ! ! ! !

Недавно этот проект общался с командой партнеров и, наконец, выбрал среди множества фреймворков.wepy, родным напрямую не пользуюсь, апплет родной..., все знают, пользуйтесьwepyФреймворк принес мне удобство, но и принес много подводных камней, но даже так у меня все равно есть: "Даже если ты оскорбляешь меня тысячу раз, я все равно отношусь к тебе как к своей первой любви.«Ментальность, чтобы сделать проект хорошо.

компонент тостов

  • toastКомпоненты, как мы все знаем, официальные APIwx.showToastнедостаточно для наших нужд, потому что поддерживает только "успех", "loading«Два государства одновременно» текст заголовка может отображать до 7 китайских иероглифов в длину», это официальные оригинальные слова, есть картинки и правда, стиль уродлив ~

wx.showToast({
  title: '成功',
  icon: 'success',
  duration: 2000
})
wx.showModal({
  title: '提示',
  content: '这是一个模态弹窗',
  success: function(res) {
    if (res.confirm) {
      console.log('用户点击确定')
    } else if (res.cancel) {
      console.log('用户点击取消')
    }
  }
})

wx.showModalТекст контента будет не по центру (не уверен, есть ли сейчас расширение, его можно поставить), смутно помню, что однажды чуть не поссорился с продакт-менеджером из-за проблемы, и текст был по центру Я сказал, что это займет не менее двух часов, а изделие в это время взорвалось. ? ? Два часа уходит на центрирование текста? ? два часа? ? два часа? ? Ха-ха~ Я ушел, а потом решил инкапсулировать свой собственный компонент тоста,Ниже приведена часть основного кода

“崩溃暴走 表情包”的图片搜索结果

<template lang="wxml">
	
	<view class="ui-toast  {{ className }}" hidden="{{ !visible }}">
		<view class="ui-toast_bd">
			<icon wx:if="{{ options.icon}}" type="{{ options.icon }}" size="40" color="{{ options.color }}" class="ui-toast_icon" />
			<view class="ui-toast_text">{{ options.text }}</view>
		</view>
	</view>
</template>

<script>
	import wepy from 'wepy';
	const __timer__ =1900;
	//方法以 : __XX__ 命名,因并入其他组件中后,可能引起方法名重复
	class Toast extends wepy.component {
			
		/**
		 * 默认数据
		 */
		data={
			 list:[
				{
					type: `success`,
					icon: `success`,
					className: `ui-toast-success`,
				},
				{
					type: `cancel`,
					icon: `cancel`,
					className: `ui-toast-cancel`,
				},
				{
					type: `forbidden`,
					icon: `warn`,
					className: `ui-toast-forbidden`,
				},
				{
					type: `text`,
					icon: ``,
					className: `ui-toast-text`,
				},
			],
			timer:null,
			scope: `$ui.toast`, 
			animateCss:'animateCss',
			className:'',
			visible:!1,
			options:{
				type: ``, 
				timer: __timer__, 
				color: `#fff`, 
				text: `已完成`, 
			}
		}
		/**
		 * 默认参数
		 */
		__setDefaults__() {
			return {
				type: `success`, 
				timer: __timer__, 
				color: `#fff`, 
				text: `已完成`, 
				success() {}, 
			}
		}
		/**
     * 设置元素显示
     */
    __setVisible__(className = `ui-animate-fade-in`) {
    	this.className = `${this.animateCss} ${className}`;
    	this.visible = !0;
    	this.$apply();
    }

    /**
     * 设置元素隐藏
     */
    __setHidden__(className = `ui-animate-fade-out`, timer = 300) {
    	this.className = `${this.animateCss} ${className}`;
    	this.$apply();
      setTimeout(() => {
  			this.visible = !1;
  			this.$apply();
      }, timer)
    }
		/**
		 * 显示toast组件 @IT·平头哥联盟,首席填坑官∙苏南的专栏,梅斌的专栏
		 * @param {Object} opts 配置项
		 * @param {String} opts.type 提示类型
		 * @param {Number} opts.timer 提示延迟时间
		 * @param {String} opts.color 图标颜色
		 * @param {String} opts.text 提示文本
		 * @param {Function} opts.success 关闭后的回调函数
		 */
		__show__(opts = {}) {
			let options = Object.assign({}, this.__setDefaults__(), opts)
			const TOAST_TYPES = this.list;
			TOAST_TYPES.forEach((value, key) => {
				if (value.type === opts.type) {
					options.icon = value.icon;
					options.className = value.className
				}
			})
			this.options = options;
			if(!this.options.text){
				return ;
			};
			clearTimeout(this.timer);
			this.__setVisible__();
			this.$apply();
			this.timer = setTimeout(() => {
				this.__setHidden__()
				options.success&&options.success();
			}, options.timer);

		}
		__info__(args=[]){
			let [ message, callback, duration ]  = args;
	   	this.__show__({
		    type: 'text',
		    timer: (duration||__timer__),
		    color: '#fff',
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __success__(args=[]){
	  	let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: 'success',
		    timer: (duration||__timer__),
		    color: '#fff',
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __warning__(args){
			let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: 'forbidden',
		    timer: (duration||__timer__),
		    color: '#fff',
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __error__(args){
	  	let [ message, callback, duration ]  = args;
	  	this.__show__({
		    type: 'cancel',
		    timer: (duration||__timer__),
		    color: '#fff',
		    text: message,
		    success: () => {callback&&callback()}
		  });
	  }
	  __showLoading__(options){
	  	wx.showLoading({
			  title: (options&&options.title||"加载中"),
			});
	  }
	  __hideLoading__(){
	  	wx.hideLoading();
	  }
	  onLoad(){
      this.$apply()
    }
	}

	export default Toast;
</script>

Пример вызова:

<template>
	<view class="demo-page">
		<Toast />
		<Modals />
	</view>
</template>

<script>
	import wepy from 'wepy' //@IT·平头哥联盟
	import Toast from '../components/ui/Toast'
	import Modals from '../components/ui/Modals'
	import {fetchJson} from '../utils/fetch';

	export default class Index extends wepy.page {
		config = {
			navigationBarBackgroundColor: "#0ECE8D",
      navigationBarTextStyle:"white",
			navigationBarTitleText: ''
		}
		components = {
			Toast: Toast,
			Modals: Modals
		}
		methods = {
			tapToast(){
				this.$invoke("Toast","__success__",[`您已提交成功,感谢您的支持与配合`]);
			}	
		}
	}
</script>

Место хранения

  • Storage(Хранение) так, как мы храним на переднем конце,cookie,localStorage,sessionStorageВ ожидании этих характеристик по порядку объяснять не буду, все в апплете знают, что хранилище данных может вызывать только wx.setStorage, wx.setStorageSync, что эквивалентно h5localStoragelocalStorageОн не истечет, это все знают, и во многих интервью интервьюер задаст этот вопрос, как сделать так, чтобыlocalStorageрисунокcookieА как насчет двух часов, двух дней или даже двух минут? Сегодня я возьму вас, чтобы разрешить ваши сомнения, чтобы вы могли уменьшить еще одну сложную проблему на собеседовании на рабочем месте.Этот метод мы также использовали в нашем проекте, и он также практичен в небольших программах:

class storage {

  constructor(props) {
    this.props = props || {}
    this.source =  wx||this.props.source;

  }

  get(key) {
    const data = this.source,
          timeout = (data.getStorageSync(`${key}__expires__`)||0)

    // 过期失效
    if (Date.now() >= timeout) {
      this.remove(key)
      return;
    }
    const value = data.getStorageSync(key)
    return value
  }

  // 设置缓存
  // timeout:过期时间(分钟)
  set(key, value, timeout) {
    let data = this.source
    let _timeout = timeout||120;
    data.setStorageSync(key,(value));
    data.setStorageSync(`${key}__expires__`,(Date.now() + 1000*60*_timeout));
 
    return value;
  }

  remove(key) {
    let data = this.source
        data.removeStorageSync(key)
        data.removeStorageSync(`${key}__expires__`)
    return undefined;
  }
}
module.exports = new storage();

Это на самом деле очень просто.После прочтения все говорили "Ой, оказывается, это можно сделать вот так. Перед данными сравните их с текущим временем, если оно меньше текущего времени, оно истечет и напрямую возвращать пустые данные.

Сопровождение API интерфейса

  • **Сопровождение интерфейса API, ** при отсутствииnodejsРаньше передняя часть, казалось, беспокоилась, вызывая соответствующий API в разных средах. Что она делала, так это использовала доменное имя для вынесения суждений. Конечно, были некоторые передовые методы. Внутренняя часть сохраняла переменную, когда страница была обработана.cookieГлобальная переменная api (исходя из отсутствия разделения front-end и back-end) выводится на странице или на странице.То же самое и в случае с апплетом.Приходится каждый раз вручную менять окружение. Тогда проект может иметь разные бизнесы и называться разными доменными именами.api, и есть разные экологические различия, как лучше их поддерживать? ?

    env/dev.js //локальная среда модуль.экспорт = { вабАпи: { хозяин:"dev-ali.southsu.com/XX/api/**", }, questionApi:{ host:"Dev-ali.bin.com/question/AP…", }, mockApi:{ host:"easy.com/mock/594635…" }, inWelApi: { host: "https://dev.**.com/Wab/api/escene/v2"
    } };

    импортировать dev из './env/dev';//локальный или для разработки импортировать uat из './env/pre';//Испытать среду импортировать prd из './env/prd';//Онлайн

    var ENV = "prd"; //'dev | uat | prd'; let base = { dev, uat, prd }[ENV]; var config = { ENV, baseAPI:{...base, env : ENV }, appID:"wx***b625e", // счет компании (индекс) appid авторизация: правда, 'logId': 'gVDSMHHAas4qSSOTb-gzGzoHsz', 'logKey': 'pxFOgJn3JyjOVr', questionnaireNo:'zInsu' // номер анкеты }; экспортировать константуDEBUG = (ENV!="prd"); export default config;

    Пример запроса, вызывающего обработку API

    import wepy from 'wepy' import login from './login'; import config,{DEBUG} из './config'; импортировать «wepy-асинхронную функцию»; экспортировать константу fetchJson = (опции)=>{ /* * Обработка общедоступных данных до запроса, колонка директора по заполнению ∙ Сунан, колонка Мэй Бин * @param {String} url Адрес запроса * @param {String} Введите тип запроса * @param {String} sessionId пользователя userToken * @ param {Boolean} openLoad Открыть приглашение на загрузку, по умолчанию вкл., true-вкл., false-выкл. * @ param {function} Статический метод подсказки StaticToast, подробности см. в component/ui/Toast * @param {Object} заголовок запроса сброса заголовка * @param {Boolean} isMandatory Необходимо ли принудительно авторизовать пользователя для получения информации о пользователе */

    StaticToast = getCurrentPages()[getCurrentPages().length - 1];
    let { url,openLoad=true, type, data={},header={}, ...others } = options||{};
    let sessionId = (Storage.get(__login__.server+'_userToken')||"");
    /*Start */
       
        var regExp = /\/(.*?)\//,
        hostkey = url.match(regExp)[1];
    let baseUrl = config.baseAPI[hostkey].host;
    url = url.replace(regExp, '/');
    
    /*End */
    
    __DEBUG__&&console.log('#--baseUrl:', baseUrl);
    __DEBUG__&&console.log('#--请求地址:', `${baseUrl}${url}`);
    __DEBUG__&&console.log('----------分割线---------------');
    openLoad&&StaticToast.__showLoading__();
    return new Promise((resolve, reject) => {
    	return wepy.request({
    		url:`${baseUrl}${url}`,
    		method:(type || 'POST'),
    		data,
    		header:{
    			"t9oken":sessionId,
    			'content-type': 'application/json',
    			// 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    			...header
    		},
    		success:(res)=>{
    			StaticToast.__hideLoading__();
    			return resolve(resHandler(res,options));
    		},
    		error:(err,status)=>{
    			StaticToast.__hideLoading__();
    			return reject(errorHandler(err,options,err.statusCode));
    		}
    	});
    })
    

Пример делового звонка

fetchJson({
	type:"post",
	// url:"/mockApi/service/XXX", 最后请求得到的地址是 https://easy.com/mock/594635**c/miniPrograms/service/XXX (域名不同环境不一样,在config里的 ENV baseAPI控制)
	data:{
		name:"苏南"
	},
	success:res=>{
		console.log(`大家好,我是@IT·平头哥联盟-苏南`,res)
		
	}
})

Пришло время заполнить дыру

  • Пришло время заполнить дыру,wepyОбратный вызов жизненного цикла onload в каждом компоненте в структуре, пока компонент введен, он будет выполняться независимо от того, визуализируется ли ваше представление или нет, что приводит к исключению, когда какая-то бизнес-логика не использует его (конечно, это горшок) Я точно не читаю~^~), подробности смотрите по ссылке:GitHub.com/Tencent/WEP…,GitHub.com/Tencent/WEP…, я не знаю, решил ли кто-нибудь это позже.

компонент форматированного текста

  • **rich-text,** Компонент апплета, хотя и есть немного пользы, но я должен сказать, для чего он используется? Остальное я вытерплю,aЭтикетка,aЯрлыков, атрибутов не существует, так что толку от этого, ты не хочешь, чтобы я прыгал, ты мне еще нужен? b, i, span, em... Какой из них я не могу использовать? Я не знаю, был ли человек, разработавший этот компонент, лягнутым ослом (да благословит его Бог, я ругаю его здесь, но не показывайся, ха-ха~), и там есть ссылка на содержание фоновая конфигурация бизнес-требований, нет Кстати, давай, делай, делай насмерть, все ширк это оправдание твоим низким навыкам (Смотри, смотри, как другие могут прыгать, как другие могут это делать? Дай мне нож, я продукт можно измельчить в шлак), поэтому начинка ямы следующая:

<template>
	<view class="test-page">
			<button @tap="cutting">点击解析html</button>
			<view wx:if="{{result.length>0}}" class="parse-list">
					<view  class="parse-view" wx:for="{{result}}" wx:key="unique" wx:for-index="index" wx:for-item="items">
							<block wx:if="{{items.children&&items.children.length}}">
									<block wx:for="{{items.children}}" wx:for-item="child" >
											<text wx:if="{{child.type == 'link'}}" class="parse-link" @tap="goToTap({{child.link}})">{{child.value}}</text>
											<text class="parse-text" wx:else>{{child.value}}</text>
									</block>
							</block>
							<text class="parse-text" wx:else>{{items.value}}</text>
					</view>
			</view>
			<Toast />
			<Modals />
	</view>
</template>

<script>
        //首席填坑官∙苏南的专栏,梅斌的专栏
	import wepy from 'wepy'
	import { connect } from 'wepy-redux'
	import Toast from '../components/ui/Toast'
	import Modals from '../components/ui/Modals'
	import {fetchJson} from '../utils/fetch';
	import Storage from "../utils/storage";

	function wxHtmlParse(htmlStr=''){
			if(!htmlStr){
					return []
			};
			const httpExp  =/(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|\&|-)+)/g;//提取网址正则
			const aExp=/<a.[^>]*?>([(^<a|\s\S)]*?)<\/a>/ig; //a标签分割正则
			let cuttingArr = htmlStr.split(/[\n]/);
			let result = [];
			//有a标签的html处理
			let itemParse = (itemHtml='')=>{
					let itemCutting = itemHtml.split(aExp)||[];
					let itemResult = [];
					for(var i = 0;i<itemCutting.length;i++){
							let _html = itemCutting[i];
							if(_html!==''){
									let itemData = {
											value:_html,
											type:'text',
											class:"parse-text"
									};
									let matchTag = itemHtml.match(aExp)||[]; //再次匹配有 a 标签的
									if(matchTag.length){
											let itemIndex = matchTag.findIndex((k,v)=>(k.indexOf(_html)!==-1));
											if(itemIndex>=0){
													let link = matchTag[itemIndex].match(httpExp)[0];
													itemData.type = 'link';
													itemData.link = link;
													itemData.class = "parse-link";
											};
									};
									itemResult.push(itemData)
							}
					};
					return itemResult;
			};
			cuttingArr.map((k,v)=>{
					let itemData = {type : "view",class:"parse-view"};
					let isATag = k.match(aExp);
					if(isATag){
							itemData.children = itemParse(k);
					}else{
							itemData.value = k;

					};
					result.push(itemData);
					return k;
			}) ;
			return result;
	};
	export default class Index extends wepy.page {
			config = {
					navigationBarBackgroundColor: "#0ECE8D",
					navigationBarTextStyle:"white",
					navigationBarTitleText: '小程序解析数据中的a标签'
			}
			components = {
					Toast: Toast,
					Modals: Modals
			}
			data = {
					html:'大家好,我是苏南(South·Su),\n职业:@IT·平头哥联盟-首席填坑官,\n身高:176cm,\n性别:男,\n性取向:女,\n公司:目前就职于由腾讯、阿里、平安三巨头合资的一家互联网金融公司深圳分公司某事业部、,\n简介:宝剑锋从磨砺出 梅花香自苦寒来,认真做自己,乐于分享,希望能尽绵薄之力 助其他同学少走一些弯路!,gitHub:https://github.com/meibin08/,\n兴趣:跑步、羽毛球、爬山、音乐、看书、分享自己的微薄知识帮助他人……,\n其他:想了解更多吗?可以加入<a href="https://honeybadger8.github.io/blog/#/">386485473交流群</a>,也可以给我电话<a href="https://github.com/meibin08/">134XX852xx5</a> ,开玩笑啦',
					result:[]
			}
			methods = {
				cutting(e){
					this.result = wxHtmlParse(this.html);
					console.log(`result`,this.result);
					this.$apply();
				},
					
			}
			
	}
</script>

PS:Полный пример исходного кодаДа ладно~, я думаю, хорошо помнить Стар,Star,WatchОй ну спасибо!

На сегодняшнем обмене все.Пишу давно.В блог только недавно начала пробовать.Я новичок в дороге.Если что-то не так в статье,поправьте пожалуйста. Если вы считаете, что эта статья полезна для вас, пожалуйста, не забудьте поставить лайк~, хотите узнать обо мне больше? Добро пожаловать, чтобы следовать нижепубликаой

Автор: Сунан-首席填坑官
Группа связи: 912594095, публичный аккаунт: honeyBadger8
Данная статья является оригинальной и авторские права принадлежат автору. Для коммерческой перепечатки обращайтесь@IT · Союз братьев ПинтоуАвторизованная, некоммерческая перепечатка, просьба указывать оригинальную ссылку и источник.

Ссылки на этот призыв к статьям:nuggets.capable/post/684490…