澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

最中央的入门知识,vue本领要点

pwa重构上海地铁线路图

2018/03/28 · JavaScript · PWA

原文出处: Neal   

之前一直有在维护一个上海地铁线路图的 pwa,最主要的特性就是 “offline first”。但是由于代码都是通过原生的 js 去实现,之前我都不是很喜欢去用框架,不想具有任何框架的偏好。但是到后期随着代码量的增加,代码的确变得混乱不堪,拓展新功能也变得尤为困难。因此,花了将近两个礼拜的时候对于应用进行了一次完整的重构。网站访问地址:

前言

浅谈vue项目重构技术要点和总结,vue技术要点

前言

最近太忙了,博客好久没有更新了。今天忙里偷闲,简单总结一下最近vue项目重构的一些技术要点。

vue数据更新, 视图未更新

这个问题我们经常会遇到,一般是vue数据赋值的时候,vue数据变化了,但是视图没有更新。这个不算是项目重构的技术要点,也和大家分享一下vue2.0通常的解决方案吧!

解决方案如下:

1、通过vue.set方式赋值

Vue.set(数据源, key, newValue)

2、 通过Array.prototype.splice方法

数据源.splice(indexOfItem, 1, newValue)

3、修改数据的长度

数据源.splice(newLength)

4、变异方法

Vue.js 包装了被观察数组的变异方法,故它们能触发视图更新。被包装的方法有:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

prop 对象数组应用

在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组, 在子组件内部改变它会影响父组件的状态 。利用这一点,我们在子组件中改变prop数组或者对象,父组件以及所有应用到prop中数据的地方都会变化。我之前写过一篇js深拷贝和浅拷贝的文章,感兴趣的去看下,其实,原理是一致的。

案例如下:

<input class="pinput max" type="text" v-model="itemData.data.did">

<script>
export default {
 components: {
 },
 data() {
 },
 props: {
 itemData: Object
 },
 methods: {
 }
};
</script>

所有应用到itemData的地方都会变化!

上面这种改变prop,Vue 不会在控制台给出警告,假如我们完全改变或者赋值prop,控制台会发出警告!引用官方给出的解决方案如下:

1、定义一个局部变量,并用 prop 的值初始化它:

props: ['initialCounter'],
data: function () {
 return { counter: this.initialCounter }
}

2、定义一个计算属性,处理 prop 的值并返回:

props: ['size'],
computed: {
 normalizedSize: function () {
 return this.size.trim().toLowerCase()
 }
}

v-model 的一些坑

其实v-model和sync都是一些语法糖,我之前有文章介绍过,官网也能找到类似的案例!

v-model 数据有时候是undefined的时候,不会报错,所以,一定要注意,v-model不能是undefined,否则有些莫名的问题!

重构-动态组件的创建

有时候我们有很多类似的组件,只有一点点地方不一样,我们可以把这样的类似组件写到配置文件中,动态创建和引用组件

方法一:component 和is配合使用

通过使用保留的 元素,并对其 is 特性进行动态绑定,你可以在同一个挂载点动态切换多个组件:

var vm = new Vue({
 el: '#example',
 data: {
 currentView: 'home'
 },
 components: {
 home: { /* ... */ },
 posts: { /* ... */ },
 archive: { /* ... */ }
 }
})
<component v-bind:is="currentView">
 <!-- 组件在 vm.currentview 变化时改变! -->
</component>

方法二:通过render方法创建

<script>
export default {
 data() {
 return {
 };
 },
 render: function(createElement) {
 let _type = bi.chart.data.type;
 let _attr = bi.chart.components[_type]["attr"];
 return createElement(_attr, {
  props: {
  }
 });
 }
};
</script>

bi.chart.components[_type]["attr"]这个是在配置文件中动态配置的,type点击的时候会改变,会取不同type下面的attr属性!

公共属性抽离

我们在项目中,经常会用很多状态或者数据,我们可以把很多公共数据抽离出来,放到一个对象中,后面我们可以监听这个数据对象变化。进行数据保存或者获取。

c: {
 handler: function (val, oldVal) { /* ... */ },
 deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
 handler: function (val, oldVal) { /* ... */ },
 immediate: true
},

可以利用上面深度监听。假如初始化的时候要立即执行,我们可以用立即执行监听!

require动态加载依赖

我们可以利用require同步特性,在代码中动态加载依赖,例如下面echart主题,我们可以点击切换的时候,动态加载!

require("echarts/theme/"  data.theme);

import加载要放到头部,初始化的时候,可以把默认主题用import加载进来!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持帮客之家。

前言 最近太忙了,博客好久没有更新了。今天忙里偷闲,简单总结一下最近vue项目重构的一...

业务扩展,IOS和安卓都有成型的版本,所以要做一个对应的移动端H5版的机票订,买票应用,入口是微信公众号,当然少不了jssdk的使用,以及balabala的授权处理等。最初是考虑用React Redux Webpack,前后端完全分离,但考虑到人手不足,前后端暂时做不了完全分离,然后还有对React也不熟悉,项目时间等问题,然后就被Boss否了。
最终用了更熟悉的Vue Vuex Webpack。主要还是因为更轻,API更加友好,上手速度更快,加上团队里有人熟悉,可以马上开工。比较遗憾的是因为各种原因前后端分离还不是很彻底,前端用的是jsp模板加js渲染页面。好处是首屏数据可以放到script标签里面直出,在进度条读完的时候页面就能够渲染出来了,提高首屏渲染时间。但是调试的时候十分麻烦,因为没有Node做中间层,每次都要在本地完整地跑个服务器,不然拿不到数据。
Vue,Vuex,Vue-router,Webpack这些不了解的同学就去看看文档。MV*框架用好了真的是极大地解放生产力,特别是页面的交互十分复杂的时候。

Learn once, write anywhere: Build mobile apps with React.

准备

准备工作先做好,在 vue 和 react 之间,我还是选择了后者。基于 create-react-app 来搭建环境,crp 为你准备了一个开箱即用的开发环境,因此你无需自己亲手配置 webpack,因此你也不需要成为一名 webpack 配置工程师了。

另外一方面,我们还需要一些数据,包括站点信息,线路路径,文字说明等等。基于之前的应用,可以通过一小段的代码获取信息。就此如要我们获取我们以前的站点在 svg 图中的相关属性,普通的站点使用 circle 元素,为了获取其属性:

const circles = document.querySelectorAll('circle'); let result = []; circles.forEach(circle => { let ele = { cx: circle.cx, cy: circle.cy, sroke: circle.stroke, id: circle.id }; result.push(ele); }) const str = JSON.stringify(result);

1
2
3
4
5
6
7
8
9
10
11
12
13
const circles = document.querySelectorAll('circle');
let result = [];
circles.forEach(circle => {
  let ele = {
    cx: circle.cx,
    cy: circle.cy,
    sroke: circle.stroke,
    id: circle.id
  };
  result.push(ele);
})
const str = JSON.stringify(result);
 

通过这样的代码我们就可以获取 svg 普通站点信息,同理还可获取中转站信息,线路路径信息以及站点以及线路 label 信息。还有,我们还需要获取每个站点的时刻表信息,卫生间位置信息,无障碍电梯信息以及出入口信息。这里是写了一些爬虫去官网爬取并做了一些数据处理,再次就不一一赘述。

最近太忙了,博客好久没有更新了。今天忙里偷闲,简单总结一下最近vue项目重构的一些技术要点。

项目过程中遇到的坑

1. 遇到的第一个的坑就是transition。首页有一个滑动的banner,我是直接用css3的transition配合js定时改变transform实现的。
滑动在chrome中模拟没问题,ios中没问题,但是安卓中就没有滑动,百思不得其解。起初还以为是兼容性问题,搞了好久才发现需要在css中先增加一个transform: translateX(0)
,像下面一样,不然之后再通过js更改transform是没法在安卓中触发transition的。
123456

.slide-wp{ transform: translateX(0); -webkit-transform: translateX(0); transition: transform 1.5s ease; -webkit-transition: transform 1.5s ease;}

大家知道,transition的作用是令CSS的属性值在一定的时间区间内平滑地过渡。
所以个人猜测,在安卓中,当没有初始值时,translateX
的改动没有被平滑地过渡,就是说transition并不知道translateX
是从什么地方开始过渡的,所以也就没有平滑之说,也就没有动画了。

2. 第二个就是ES6。既然用了Webpack,当然就要配合Bebel用上ES6啦。写的时候还是很爽的。let
,const
,模块,箭头函数,字符串模版,对象属性简写,解构等等…但帅不过3秒,在chrome上模拟地跑一点问题都没有,一到移动端就直接白屏,页面都没有渲染出来。
排查了好久,才发现是某些扩展运算符...
,某些解构和for...of...
循环的问题。因为这些ES6的特性(其实不指这些)在Bebel中转换是要用到[Symbol.iterator]接口的。如下面这样。转码前:
12

const [a, b, c, d, e] = 'hello';console.log(a, b, c, d, e);//'h','e','l','l','o'

转码后:
123456789101112131415

'use strict';var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arrSymbol.iterator, _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i'return'; } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();var _hello = 'hello';var _hello2 = _slicedToArray(_hello, 5);var a = _hello2[0];var b = _hello2[1];var c = _hello2[2];var d = _hello2[3];var e = _hello2[4];console.log(a, b, c, d, e);//'h','e','l','l','o'

第一行先声明的_slicedToArray函数用到了[Symbol.iterator]接口,然而浏览器对这个接口的支持还很有限,特别是移动端,只有Firefox Mobile36版本以上才支持,其它清一色挂掉。
如下图所示:

澳门新浦京娱乐场网站 1

博客图片

所以说ES6虽好,但真要用到实际项目中的话,还不能太激进,有些特性经过Bebel转码后性能上可能还会有所下降,所以还是应该合理地使用ES6。如果是自己折腾倒无所谓,Symbol,Class,Generator,Promise这些就随便炫技吧。

3. 第三个坑就是Vue使用的问题。如其说是坑,还是不如说是我自身还不够熟悉Vue。先看一下官方说明:
受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。

当时需要在props传来的某些对象数据中增加一个是否可视属性,用来控制一个与其关联的弹出框。增加后点击视图上一点反应都没有,但是用console.log
打印出来发现值的确的有变化的。
也就是说,数据的变化不能触发视图更新。原因就是如上面所说,因为这个属性是我后来添加的,不能被Vuejs检测到。这时候需要使用$set(key, value)这个API。
话说里面的语法需要注意下,第一个参数key
是一个字符串,是一个keypath
,如果假如你的数据是这样:
123456789101112

data(){ visitors : [{ "id": 1, ... }, { "id": 2, ... }, { "id": 3, ... }],}

你需要在某次操作后为visitiors
里面的每个对象增加一个show
属性,则需要这样写:
12345

let str;for (let i = 0 , len = this.visitors.length ; i < len; i ) { str = "visitors[" i "].show"; this.$set(str,true);}

之前真的被这东西搞了很久,明明数据变化了,视图却不更新。个人感觉新手刚使用Vue时很难发现这个问题。也怪自己对Vue,对ES5的getter/setter
的理解还不够吧。

4. 第四个是IOS上的滚动问题。在某些浏览器下,例如微信内嵌浏览器,手指在屏幕上滑动时,页面会进入momentum scrolling(弹性滚动)。这时候会停止所有的事件响应DOM操作引起的页面渲染,onscroll事件不会触发,CSS3动画,gif这些也不会动,一直到滑动停止。
因为需要onscroll事件来执行懒加载等操作,但是在IOS中是要等到滑动停止后才能执行的,用户体验不好。当时google了很久,最终得出的结论是,并没有什么很好的解决方案。所以暂时只能在IOS上首次加载更多资源了。
贴一个在segmentfault上的答案吧,很好地总结了这个问题。(戳这里)

5. 第五个还是IOS上CSS3动画的问题,今天才遇到的。在对img或者设置了background-image的DOM元素设置CSS动画时,动画在刚进入页面的时候有可能不被触发,需要滑动一下屏幕动画才动,安卓下则没有问题。
刚开始还以为是没有设置初始值的问题,但感觉不应该会是这样的。后来在stackoverflow上找到了解决办法(戳这里)。给动画加个0.1s秒的延时
12

animation: slide 1.5s 0.1s linear infinite;webkit-animation: slide 1.5s 0.1s linear infinite;

原因大概是如果Safari和IOS的微信内置浏览器在加载资源,或者进行什么内部渲染操作时出现了短暂的停顿(英文是hiccups),则不会触发动画,需要滑动一下页面来重新触发。所以给动画加个0.1s延时确保资源加载完成后,问题得以解决。

关于Vue的组件化
先上个@xufei大大的博客,里面有多关于组件化的文章,都是满满的干货。
其实组件化是一个很庞大的话题,我这等小白的认识还十分显浅,不过既然在项目中用到了组件化,也就谈谈自己的看法吧。
Vue的组件化需要配合Webpack vue-loader 或者 Browserify vueify 来构建。一个.vue文件一个组件,上手了写起来是十分快捷的,不过对于新手可能就要花点时间去熟悉工具了。
之前在看了@xufei的博客加上自己的工程实践后,表示十分赞同他的说法:
很多人会把复用作为组件化的第一需求,但实际上,在UI层,复用的价值远远比不上分治。

特别是对于.vue这种形式的组件化来说,想做到复用往往需要做到内部实现高度抽象,并对外暴露很多接口,而复用的地方也并不是很多。很多时候,花那么多时间去实现一个组件复用,还不如新建一个组件,复制部分代码,重新进行内部实现来得更快。
要知道一个.vue文件里面除了<template>
、<style>
,还有<script>
。前两者用于实现组件的样式呈现,对于很多地方来说,可能只是有着些许差别,但<script>
里面的东西则是代表着组件的内部逻辑实现,这些逻辑往往有着很大的不同。

澳门新浦京娱乐场网站 2

图1

澳门新浦京娱乐场网站 3

图2

如上面的图1,图2。从样式上看,不同的地方仅仅是图2的每个常用乘机人多了一个复选框勾选,似乎可以通过某个标记来约定是否出现勾选框来达成组件复用。
但实际上,因为这两个组件所身处的业务页面的不同而存在着较大的内部逻辑实现差异。
像图1,是在我的板块里面的。里面仅仅是一个乘客展示和乘客信息编辑的作用,相对较为独立。而图2则是在订单确认页面里面的,除了乘客展示和乘客信息编辑外,还有选择乘客的作用。点了保存后会与订单状态产生交互,而且订单状态的改变还会反过来影响着这些乘客信息的状态,远比图1里面的复杂。
如果强行抽象中公共部分,对外暴露各种API来令该组件可复用,除了实现成本和维护成本高外,其复用得到的价值也不高。还不如写多一个组件,复制其样式部分,重新实现内部逻辑来得实在。而且将两个组件放在不同的板块内,相互独立,也方便管理和维护。
那怎样的组件才适合复用?我个人认为,只有很少内部逻辑的展示型组件才适合复用。像导航栏,弹出层,加载动画这些。而其它的一些组件往往只在两三页面存在复用价值,是否抽象分离出来,就要看个人取舍了。

关于Vuex
Vuex 之于 vue,就相当于 Redux 之于 React。它是一套数据管理架构实现,用于解决在大型前端应用时数据流动,数据管理等问题。
因为组件一旦多起来,不同组件之间的通信和数据流动会变得十分繁琐及难以追踪,特别是在子组件向同级子组件通信时,你可能需要先$dispatch到父组件,再$broadcast给子组件,整个事件流十分繁杂,也很难调试。
Vuex就是用来解决这些问题的。更具体的说明可以看文档,我就不过多叙述了。我就说一下我对Vuex的一些理解。
Vuex里面的数据流是单向的,就像官方说的那样:
用户在组件中的输入操作触发 action 调用;
Actions 通过分发 mutations 来修改 store 实例的状态;
Store 实例的状态变化反过来又通过 getters 被组件获知。

澳门新浦京娱乐场网站 4

vuex

而且为了保证数据是单向流动,并且是可监控和可预测的,除了在mutation handlers 外,其它地方不允许直接修改 store 里面的 state。
个人认为store就是一个类数据库的东西,处于整个应用的最顶端,每个组件之间共享数据,并通过actions来对数据进行操作。在这样的理解下,我更倾向于把mutations类比为查询语句,即只在mutations里面进行增删查改,筛选,排序等一些简单的逻辑操作,也符合是同步函数的约束。就像这样
12345678910111213141516171819202122232425

const mutations = { //设置常用乘机人列表 SET_PSGLIST(state, psgList){ state.psgList = psgList; }, //增加在订单中的乘客 ADD_ORDERPSG(state, orderPsg){ for (let i = 0,len = state.orderPsgList.length; i < len; i ) { if (state.orderPsgList[i].id == orderPsg.id) { state.orderPsgList[i] = orderPsg; return; } } state.orderPsgList.push(orderPsg); }, //删除在订单中的乘客 REMOVE_ORDERPSG(state, orderPsg){ for (let i = 0,len = state.orderPsgList.length; i < len; i ) { if (state.orderPsgList[i].id == orderPsg.id) { state.orderPsgList.splice(i,1) return; } } }}

更复杂的逻辑则写进actions中。例如我要在action中先异步获取常用乘机人数据,并初始化:
12345678910111213141516171819202122232425262728293031

//actionexport const iniPsgList = ({ dispatch }, uid) =>{ let data = { uid: uid, } $.ajax({ url: "../passenger/list", data: data, success(data){ let jsonData = JSON.parse(data); let psgs = jsonData.data.passengers; dispatch('SET_PSGLIST', psgs); }, error(){ console.log('获取常用乘机人列表信息错误'); } }) }//组件中调用import { iniPsgList } from './actions'const vm = new Vue({ created(){ this.iniPsgList(uid); }, vuex: { getters: { ... }, actions: iniPsgList, }})

或者,为了令actions实现得更为通用,你完全可以给每个mutation对应写一个action,每个action就只是分发该mutation,不做其它额外的事情。然后再在组件中引入这些actions。这样其实就相当于在组件中触发mutations,从而减少action这个流程。
123456789

function makeAction(type , data){ return ({ dispath }, data) => { dispatch( type , data) }}export const setPsgList = makeAction('SET_PSGLIST', psgList)export const addOrderPsg = makeAction('ADD_ORDERPSG', orderPsg)export const removeOrderPsg = makeAction('REMOVE_ORDERPSG', orderPsg)

这时候初始化常用乘机人列表,则是这样写。
1234567891011121314151617181920212223242526

//组件中调用import { setPsgList } from './actions'const vm = new Vue({ created(){ let data = { uid: uid, } $.ajax({ url: "../passenger/list", data: data, success: (data) = > { let jsonData = JSON.parse(data); let psgs = jsonData.data.passengers; this.setPsgList(psgs); }, error(){ console.log('获取常用乘机人列表信息错误'); } }) }, vuex: { getters: { ... }, actions: setPsgList, }})

两者的区别就仅是把异步等一些更复杂的逻辑放在action中还是放在组件内部逻辑中。前者的action更有针对性,更具有唯一性;后者的action仅仅就是一个触发mutation的作用,而组件则与更多的逻辑耦合。
谁优谁劣很难说清,和个人喜好、业务逻辑等有较大关系。我在项目中使用的是后一种用法,因为我个人更喜欢在组件实现更多的内部逻辑,方便以后针对改组件的调试和维护,免得还要在action中寻找一次。
莫名其妙地扯了这么多,其实都是一些总结与归纳。

1.新建RN项目:

设计

数据准备好之后,就是应用的设计了。首先,对组件进行一次拆分:

vue数据更新, 视图未更新

$ react-native init MyProject(项目名称)

组件结构

将整个地图理解成一个 Map 组件,再将其分为 4 个小组件:

澳门新浦京娱乐场网站 5

  • Label: 地图上的文本信息,包括地铁站名,线路名称
  • Station: 地铁站点,包括普通站点和中转站点
  • Line: 地铁线路
  • InfoCard: 状态最复杂的一个组件,主要包含时刻表信息、卫生间位置信息、出入口信息、无障碍电梯信息

这是一个大致的组件划分,里面可能包含更多的其它元素,比如 InfoCard 就有 InfoCard => TimeSheet => TimesheetTable 这样的嵌套。

这个问题我们经常会遇到,一般是vue数据赋值的时候,vue数据变化了,但是视图没有更新。这个不算是项目重构的技术要点,也和大家分享一下vue2.0通常的解决方案吧!

确保项目下有node_modules后,运行$react-native run-android来运行项目。

组件通信和状态管理

本地开发的最大的难点应该就是这一块的内容了。本来由于组件的层级并不算特别复杂,所以我并不打算上 Redux 这种类型的全局状态管理库。主要组件之间的通信就是父子通信和兄弟组件通信。父子组件通信比较简单,父组件的 state 即为子组件的 props,可以通过这个实现父子组件通信。兄弟组件略为复杂,兄弟组件通过共享父组件的状态来进行通信。假如这样的情景,我点击站点,希望能够弹出信息提示窗,这就是 Station 组件和 InfoCard 组件之间的通信,通过 Map 组件来进行共享。点击 Station 组件触发事件,通过回调更新 Map 组件状态的更新,同时也实现了 InfoCard 组件的更新。同时为了实现,点击其它区域就可以关闭信息提示窗,我们对 Map 组件进行监听,监听事件的冒泡来实现高效的关闭,当然为了避免一些不必要的冒泡,还需要在一些事件处理中阻止事件冒泡。

澳门新浦京娱乐场网站 6

InfoCard 是最为复杂的一个组件,因为里面包含了好几个 icon,以及状态信息的切换,同时需要实现切换不同的站点的时候能够更新信息提示窗。需要注意信息提示窗信息初次点击信息的初始化,以及切换不同 icon 时分别显示不同的信息,比如卫生间信息或者出入口信息,以及对于时刻表,切换不同的线路的时候更新对应的时刻表。这些状态的转化,需要值得注意。另外值得一题的点就是,在切换不同站点的时候的状态,假如我正在看某个站点的卫生间信息的时候,我点击另外一个站点,这时候弹出的信息提示窗应该是时刻表信息还是卫生间信息呢?我的选择还是卫生间信息,我对于这一状态进行了保持,这样的用户体验从逻辑上来讲似乎更佳。具体实现的代码细节就不一一说明了,里面肯能包含更多的细节,欢迎使用体验。

解决方案如下:

2.RN基本入门及知识点

性能优化

以上这些的开发得益于之前的维护,所以重构过程还是比较快的,稍微熟悉了下 react 的用法就完成了重构。但是,在上线之后使用 lighthouse 做分析,performan 的得分是 0 分。首屏渲染以及可交互得分都是 0 分,首先来分析一下。因为整个应用都是通过 js 来渲染,而最为核心的就是那个 svg。整个看下来,有几点值得注意:

  • 代码直接将 json 导入,导致 js 体积过大
  • 所有组件都在渲染的时候进行加载

澳门新浦京娱乐场网站,找到问题点,就可以想到一些解决方案了。第一个比较简单,压缩 json 数据,去除一些不需要的信息。第二个,好的解决办法就是通过异步加载来实现组件加载,效果明显,尤其是对于 InfoCard 组件:

1、通过vue.set方式赋值

2.1入口

同步

class InfoCard extends React.Component { constructor(props) {    super(props) { ...    }  }  ... }

1
2
3
4
5
6
7
8
9
class InfoCard extends React.Component {
  constructor(props) {
   super(props) {
    ...
   }
 }
 ...
}
 
Vue.set(数据源, key, newValue)

Android的入口文件是根目录下的index.android.js,Ios的入口文件是根目录下的index.ios.js.

异步

export default function asyncInfoCard (importComp) { class InfoCard extends React.Component {    constructor(props) { super(props); this.state = { component: null }; } asyncComponentDidMount() { const { default: component } = await importComp(); this.setState({ component: component })    }  } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default function asyncInfoCard (importComp) {
  class InfoCard extends React.Component {
   constructor(props) {
      super(props);
      this.state = {
        component: null
      };
    }
    
    asyncComponentDidMount() {
      const { default: component } = await importComp();
      this.setState({
        component: component
      })
   }
 }
}
 

这样我们就实现了将同步组件改造成一个异步加载的组件,这样就无需一下子加载所有的组件。这样我们就可以在 Map 中使用异步的方式来进行组件的加载:

import asyncInfoCard from './InfoCard' const InfoCard = asyncInfoCard(() => import('./InfoCard')

1
2
3
import asyncInfoCard from './InfoCard'
const InfoCard = asyncInfoCard(() => import('./InfoCard')
 

通过上线之后的性能分析,lighthouse 性能评分一下子就上升到了 80 多分,证明这样的改进还是比较有效的。另外一个值得提的点就是首屏,因为历史原因,整张图 svg 中元素的位置都是定死的,及横坐标和纵坐标都已经是定义好的,而 svg 被定为在中间。在移动端加载时,呈现的就是左边的空白区域,所以给用户一种程序未加载完毕的错觉。之前的版本的做法就是通过 scroll 来实现滚动条的滚动,将视图的焦点移动到中间位置。这次的想法是通过 transform 来实现:

.svg { transform: translate(-100px, -300px) }

1
2
3
.svg {
transform: translate(-100px, -300px)
}

这样实现了整个 svg 图位置的偏移,使用 lighthouse 进行分析,性能分降到了 70 多分。继续想想有没有其他的方法,后来我想在最左上上角定义一个箭头动画。

img src="right_arrow.png" alt="right arrow" title="right arrow" class="right-arrow"/>

1
img src="right_arrow.png" alt="right arrow" title="right arrow" class="right-arrow"/>

.right-arrow { animation: moveright 3s linear infinite; } @keyframs moveright { 0% { transform: translateX(2rem); } 50% { transform: translateX(3rem); } 100% { transform: translateX(5rem); } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
.right-arrow {
  animation: moveright 3s linear infinite;
}
@keyframs moveright {
  0% {
    transform: translateX(2rem);
  }
  50% {
    transform: translateX(3rem);
  }
  100% {
    transform: translateX(5rem);
  }
}

澳门新浦京娱乐场网站 7

这样我们就可以创建一个循环向右移动的动画,提示用户向右滑动。部署之后发现性能分立马降到 0,索性也就放弃了这个做法。最后来时决定采用 transform: translateX(-200px) translateY(-300px); ,因为这样通过 css3 的属性可以在一些移动设备上还可以利用 GPU 加速,并且 translateX 不会引起页面的重绘或者重排,只会导致图层重组,最小避免对性能的影响。

2、 通过Array.prototype.splice方法

2.2 AppRegistry是JS运行所有React Native应用的入口。应用的根组件应当通过AppRegistry.registerComponent方法注册自己,然后原生系统才可以加载应用的代码包并且在启动完成之后通过调用AppRegistry.runApplication来真正运行应用。

部署

目前的部署方案是采取 create-react-app 的官方建议,通过 gh-pages 实现将 build 的打包文件上传到 gh-pages 分支上从而实现部署。

数据源.splice(indexOfItem, 1, newValue)

eg:  AppRegistry.registerComponent('Helloworld', () => TestComponent);

兼容性

目前该应用在 Chrome 浏览器的支持性是最好的,安卓浏览器建议安装 Chrome 浏览器使用,我一般也都比较喜欢在手机上使用谷歌浏览器。对于 Safari 浏览器,其它的浏览功能似乎没有什么大问题,目前应该还没支持添加到主屏幕。不过在之后的 ios 版本好像对于 pwa 有着更进一步的支持。

3、修改数据的长度

其中Helloworld是你的项目名称,TestComponent是你的入口组件的名称。

结语

澳门新浦京娱乐场网站 8

花了两个礼拜的时间完成了项目的完整的重构,从这一年来的 commit 记录可以看到三月份疯狂 commit 了一波,主要是第一个周末花费了两天的时间修改了好多代码,被那个 InfoCard 的状态切换搞了很久,后面就是针对性能做了一些优化。过程很痛苦,一度怀疑自己的 coding 能力。不过最后还是有以下感悟:

  • 世界上没有最好的语言,最好的框架,只有最合适的
  • 最优雅的实现都不是一蹴而就的,都是一个个试出来的

最后一个冷笑话:

青年问禅师:“请问大师,我写的程序为什么没有得到预期的输出?” 禅师答到:“年轻人,那是因为你的程序只会按你怎么写的执行,不会按你怎么想的执行啊……”

源代码地址,欢迎 star 或者 pr。

 

1 赞 收藏 评论

澳门新浦京娱乐场网站 9

数据源.splice(newLength)

2.3基本组件

4、变异方法

常用的基本组件有Button, View, Image, ListVie,Textw等等,这些组件的引入方法是:import {Button,View, Image, ListView} from‘’react-native.

Vue.js 包装了被观察数组的变异方法,故它们能触发视图更新。被包装的方法有:

使用方法:

push()
pop()
shift()
unshift()
splice()
sort()
reverse()

hello world

prop 对象数组应用

2.4组件显示的布局(flexBox布局详解)

在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,如果 prop 是一个对象或数组, 在子组件内部改变它会影响父组件的状态 。利用这一点,我们在子组件中改变prop数组或者对象,父组件以及所有应用到prop中数据的地方都会变化。我之前写过一篇js深拷贝和浅拷贝最中央的入门知识,vue本领要点。的文章,感兴趣的去看下,其实,原理是一致的。

我们在React Native中使用flexbox规则来指定某个组件的子元素的布局。Flexbox可以在不同屏幕尺寸上提供一致的布局结构。

案例如下:

在组件中的style中指定flexDirection可以决定布局的主轴,子元素是按着水平轴(row)排列,还是数值轴(colum,默认值)排列。flex:定义了元素的可伸缩能力。默认值是0

<input class="pinput max" type="text" v-model="itemData.data.did">

<script>
export default {
 components: {
 },
 data() {
 },
 props: {
 itemData: Object
 },
 methods: {
 }
};
</script>

在组件中的style中指定justifyContent可以决定子元素沿着主轴的排列方式。靠近起始端:flex-start(默认)。 靠近末端:flex-end。 中心:center。space-around和space-between。

所有应用到itemData的地方都会变化!

在组件的style中指定alignItems可以决定其子元素沿着次轴(与主轴垂直的轴,比如若主轴方向为row,则次轴方向为column)的排列方式。

上面这种改变prop,Vue 不会在控制台给出警告,假如我们完全改变或者赋值prop,控制台会发出警告!引用官方给出的解决方案如下:

对应的这些可选项有:flex-start(靠近次轴起始端)、center(次轴中心)、flex-end(次轴末尾段)以及stretch(元素被拉伸以适应容器)。

1、定义一个局部变量,并用 prop 的值初始化它:

注意:要使stretch选项生效的话,子元素在次轴方向上不能有固定的尺寸。

props: ['initialCounter'],
data: function () {
 return { counter: this.initialCounter }
}

使用方法(完整RN Demo):

2、定义一个计算属性,处理 prop 的值并返回:

2.5自定义组件

props: ['size'],
computed: {
 normalizedSize: function () {
 return this.size.trim().toLowerCase()
 }
}

自定义组件需要继承React.Component。组件渲染的方法是render()。最基本的用法是:

v-model 的一些坑

class MyComponent extends React.Component{

其实v-model和sync都是一些语法糖,我之前有文章介绍过,官网也能找到类似的案例!

render() {   //这个方法是必须的

v-model 数据有时候是undefined的时候,不会报错,所以,一定要注意,v-model不能是undefined,否则有些莫名的问题!

Return();  //返回要显示的view最外层只能有一个view

重构-动态组件的创建

}

有时候我们有很多类似的组件,只有一点点地方不一样,我们可以把这样的类似组件写到配置文件中,动态创建和引用组件

}

方法一:component 和is配合使用

导出组件:export default(default只能使用一次)MyComponent

通过使用保留的 元素,并对其 is 特性进行动态绑定,你可以在同一个挂载点动态切换多个组件:

导入组件:import MyComponent from‘./XX.js’

var vm = new Vue({
 el: '#example',
 data: {
 currentView: 'home'
 },
 components: {
 home: { /* ... */ },
 posts: { /* ... */ },
 archive: { /* ... */ }
 }
})
<component v-bind:is="currentView">
 <!-- 组件在 vm.currentview 变化时改变! -->
</component>

export命令规定的是对外的接口,必须与模块内部的变量建立一一对应关系。export,import可以处在任何位置,但必须是在模块顶层。 使用export default时import后不加{}。 若使用export时,import后需要加{}。

方法二:通过render方法创建

2.6自定义样式:

<script>
export default {
 data() {
 return {
 };
 },
 render: function(createElement) {
 let _type = bi.chart.data.type;
 let _attr = bi.chart.components[_type]["attr"];
 return createElement(_attr, {
  props: {
  }
 });
 }
};
</script>

const styles = StyleSheet.create({

bi.chart.components[_type]["attr"]这个是在配置文件中动态配置的,type点击的时候会改变,会取不同type下面的attr属性!

XXX,

公共属性抽离

XXX

我们在项目中,经常会用很多状态或者数据,我们可以把很多公共数据抽离出来,放到一个对象中,后面我们可以监听这个数据对象变化。进行数据保存或者获取。

});

c: {
 handler: function (val, oldVal) { /* ... */ },
 deep: true
},
// 该回调将会在侦听开始之后被立即调用
d: {
 handler: function (val, oldVal) { /* ... */ },
 immediate: true
},

1.props和state的使用及区别

可以利用上面深度监听。假如初始化的时候要立即执行,我们可以用立即执行监听!

Props:大多数组件在创建时就可以使用各种参数来进行定制。用于定制的这些参数就称为props(属性)。

require动态加载依赖

以常见的基础组件Image为例,在创建一个图片时,可以传入一个名为source的prop来指定要显示的图片的地址,以及使用名为style的prop来控制其尺寸。

我们可以利用require同步特性,在代码中动态加载依赖,例如下面echart主题,我们可以点击切换的时候,动态加载!

自定义的组件也可以使用props。通过在不同的场景使用不同的属性定制,可以尽量提高自定义组件的复用范畴。只需在render函数中引用this.props,然后按需处理即可。

require("echarts/theme/"  data.theme);

组件A ->组件B。 组件A中传递的常量(如name),在组件B中可以通过this.props.name来得到。无论是function还是class都不能修改自身的props。

import加载要放到头部,初始化的时候,可以把默认主题用import加载进来!

State:我们使用两种数据来控制一个组件:props和state。props是在父组件中指定,而且一经指定,在被指定的组件的生命周期中则不再改变。 对于需要改变的数据,我们需要使用state。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

一般来说,你需要在constructor中初始化state,然后在需要修改时调用setState方法。

您可能感兴趣的文章:

  • Map.vue基于百度地图组件重构笔记分享

假如我们需要制作一段不停闪烁的文字。文字内容本身在组件创建时就已经指定好了,所以文字内容应该是一个prop。而文字的显示或隐藏的状态(快速的显隐切换就产生了闪烁的效果)则是随着时间变化的,因此这一状态应该写到state中。

2.constructor()方法--构造函数

一般构造函数都会先super(props);

3.方法的定义

function functionName() {

}

在类的内部不使用关键字function

functinName(x, y){}或者是functionName:(x, y)=> {}(箭头函数)

4.使用导航器实现页面的跳转

StackNavigator

TabNavigator

DrawerNavigator

5.let const var的用法

const只可以初始化常量

var定义变量,若不初始化或输出undeifne,不会报错

let它的作用域是块级,用法类似于var。(for循环中可用let)

6.生命周期

7.Redux

Redux的设计思想很简单,就两句话。

(1)Web应用是一个状态机,视图与状态是一一对应的。

(2)所有的状态,保存在一个对象里面。

react-redux:

React-Redux将所有组件分成两大类:UI组件(presentational component)和容器组件(container component)。

React-Redux提供connect方法,用于从UI组件生成容器组件。connect的意思,就是将这两种组件连起来。

connect方法的完整API如下。

import { connect } from 'react-redux'

const VisibleTodoList = connect(

mapStateToProps,

mapDispatchToProps

)(TodoList)

Provier:

import { Provider } from 'react-redux'

render(

)

这样App下的所有子组件都可以拿到state

10.零散知识点梳理:

(1)...items其中三个点(...)表示扩展运算符。是一个将数组用,分割开的参数序列。

(2)箭头函数:functionName:(x)=>{}  === functionName(x) {}

(3)注意this的使用:禁止this指向全局对象。即顶层的this指向undefined。

(4)块级作用域时可以用let代替var

(5)全局常量和线程安全

在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量。

const优于let有几个原因。一个是const可以提醒阅读程序的人,这个变量不应该改变;另一个是const比较符合函数式编程思想,运算不改变值,只是新建值,而且这样也有利于将来的分布式运算;最后一个原因是JavaScript编译器会对const进行优化,所以多使用const,有利于提供程序的运行效率,也就是说let和const的本质区别,其实是编译器内部的处理不同。

const声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误。

所有的函数都应该设置为常量。

长远来看,JavaScript可能会有多线程的实现(比如Intel的River Trail那一类的项目),这时let表示的变量,只应出现在单线程运行的代码中,不能是多线程共享的,这样有利于保证线程安全。

(6)静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。

(7)简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。

11.完整的component组成:

limport xxx from‘’

l此处可以定义顶层的常量,function, 或者cla

lexport {xx,xx}

Init class demo:

class ClassDemo extends React.Component {

constructor(props: xxType) {

super(props)

this.state={

name:’hello’,

index:1

}

}

componentWillMount() {}

render () {

return(

return(

this.function1()}/>

);

);

}

componentDidUpdate () {}

function1(){}

function2() {}

}

本文由澳门新浦京娱乐场网站发布于新浦京娱乐场官网,转载请注明出处:最中央的入门知识,vue本领要点