Maison >interface Web >js tutoriel >Développement de composants de biens dans le framework Vue

Développement de composants de biens dans le framework Vue

亚连
亚连original
2018-06-09 16:08:081384parcourir

Cet article présente principalement l'explication détaillée du développement des composants goodvs du framework Vue. Je vais maintenant le partager avec vous et vous donner une référence.

1. Layout Flex

La mise en page Flex peut réaliser diverses mises en page de manière simple, complète et réactive. Flex est l'abréviation de Flexible Box, qui signifie « élasticité » Mise en page. pour offrir une flexibilité maximale aux modèles de boîte. N’importe quel conteneur peut être désigné comme une mise en page Flex.

// 指定为 Flex 布局
 display: flex;
flex : 等分 内容缩放 展位空间;
flex : 0 0 80px

// Attributs principaux
flex : aucun | 22de5aa233e84b9abb68fc333932b004? 'flex-basis'> ]
L'attribut flex est l'abréviation de flex-grow, flex-shrink et flex-basis. La valeur par défaut est 0 1 auto. Les deux dernières propriétés sont facultatives.
L'attribut flex-grow définit le taux d'agrandissement de l'élément. La valeur par défaut est 0, c'est-à-dire que s'il n'y a pas suffisamment d'espace, l'élément ne sera pas agrandi.
L'attribut flex-shrink définit le taux de rétrécissement de. l'élément. La valeur par défaut est 1, c'est-à-dire que s'il n'y a pas suffisamment d'espace, l'élément ne sera pas agrandi. L'attribut flex-shrink est 0 et les autres éléments sont tous 1. Lorsqu'il n'y a pas suffisamment d'espace, le premier est le premier. ne rétrécira pas
L'attribut flex-basis définit l'espace de l'axe principal (taille principale) occupé par l'élément avant d'allouer l'espace excédentaire. Le navigateur utilise cet attribut pour calculer s'il y a de l'espace supplémentaire sur l'axe principal. Sa valeur par défaut est auto, qui correspond à la taille d'origine du projet. Si elle est définie sur la même valeur que l'attribut width ou height (comme 350px), le projet occupera un espace fixe

2. Composant icône

Composant enfant iconMap

<template lang="html">
 <span class="iconMap" :class="iconClassMap[iconType]"></span>
</template>
export default {
 props: { // 图标类型
 iconType: Number
 },
 created() { // 数组类名
 this.iconClassMap = [&#39;decrease&#39;, &#39;discount&#39;, &#39;special&#39;, &#39;invoice&#39;, &#39;guarantee&#39;]
 }
}
Biens du composant parent

import iconMap from &#39;../iconMap/iconMap&#39; // 注意路径写法
// 注册组件
 components: {
 iconMap
 }
<ul>
 <li v-for=&#39;(item,index) in goods&#39; class="menu-item">
 <span class="text"> // json 数据 根据 type 判断 是否有图标
 <iconMap v-show="item.type>0" :iconType="item.type"></iconMap>
 {{item.name}}
 </span>
 </li>
</ul>

3. application de meilleur défilement

Similaire à iscroll pour obtenir un effet de défilement

Installation

npm install better-scroll
Introduction

import BScroll from &#39;better-scroll&#39;
Explication

(1) Principe : Le wrapper du conteneur parent a une hauteur fixe Lorsque la hauteur du contenu de son premier élément enfant dépasse la hauteur du wrapper, nous pouvons faire défiler la zone de contenu si elle ne dépasse pas la hauteur, nous ne pouvons pas faire défiler.

(2) Initialisation de better-scroll

Le moment d'initialisation de better-scroll est très important, car lorsqu'il est initialisé, il calculera la hauteur et la largeur de l'élément parent et de l'enfant élément pour déterminer si peut défiler verticalement et horizontalement. Par conséquent, lorsque nous l'initialisons, nous devons nous assurer que le contenu de l'élément parent et de l'élément enfant a été rendu correctement. Si la structure DOM de l'élément enfant ou de l'élément parent change, la méthode scroll.refresh() doit être appelée à nouveau et recalculée pour garantir l'effet de défilement normal. Par conséquent, la raison pour laquelle better-scroll ne peut pas défiler est probablement parce que le moment de l'initialisation de better-scroll est incorrect ou que better-scroll n'est pas recalculé lorsque la structure DOM envoie des modifications.

(3) better-scroll combiné avec Vue

Vue.js nous fournit une interface pour obtenir des objets DOM - vm.$refs. Ici, nous accédons à l'objet DOM via this.$refs.wrapper, et nous initialisons better-scroll dans la fonction hook montée et la fonction de rappel de this.$nextTick. Parce qu'à ce stade, le DOM du wrapper a été rendu, nous pouvons calculer correctement sa hauteur et son contenu interne pour assurer un défilement normal.

This.$nextTick est ici une fonction asynchrone Afin de garantir que le DOM a été rendu, MutationObserver ou setTimeout(fn, 0) est utilisé en bas. En fait, nous pouvons remplacer this.$nextTick par setTimeout(fn, 20) ici (20 ms est une valeur d'expérience, chaque Tick dure environ 17 ms), ce qui est imperceptible pour l'expérience utilisateur.

(4) Traitement des données asynchrones

Dans notre travail actuel, les données de la liste sont souvent obtenues de manière asynchrone, donc le moment de l'initialisation de better-scroll doit être après l'obtention des données . Le code est le suivant :


<script>
 import BScroll from &amp;#39;better-scroll&amp;#39;
 export default {
 data() {
 return {
 data: []
 }
 },
 created() {
 requestData().then((res) => {
 this.data = res.data
 this.$nextTick(() => {
 this.scroll = new Bscroll(this.$refs.wrapper, {})
 })
 })
 }
 }
</script>
Le requestData ici est un pseudo code. Sa fonction est d'initier une requête http pour obtenir des données du serveur, et cette fonction renvoie une promesse (dans les projets réels, nous. peut utiliser axios ou vue -resource). Après avoir obtenu les données, nous devons initialiser better-scroll de manière asynchrone, car Vue est basée sur les données. Lorsque les données de Vue changent (this.data = res.data) et que la page est restituée, il s'agit d'un rendu asynchrone. processus.Nous Le temps d'initialisation est après le nouveau rendu du DOM, donc this.$nextTick est utilisé ici. Bien sûr, il peut être remplacé par setTimeout(fn, 20).

Remarque : Pourquoi les données sont-elles demandées dans la fonction hook créée au lieu de dans la fonction hook montée ? Parce que requestData envoie une requête réseau, ce qui est un processus asynchrone, lorsque les données de réponse sont obtenues, le DOM de Vue a déjà été rendu, mais les données changent -> Le re-rendu du DOM est toujours un processus asynchrone, donc même si après nous obtenons. les données, nous devons également initialiser un meilleur défilement de manière asynchrone.

Utilisez

pour initialiser la structure dom qui doit défiler

Utilisez l'attribut ref pour lier un certain élément dom ou pour lier un certain composant, puis utilisez this.$refs.menuwrapper pour obtenir le dom à l'intérieur de la fonction.

Remarque : si elle est utilisée sur un élément DOM normal, la référence pointe vers l'élément DOM ; si elle est utilisée sur un sous-composant, la référence pointe vers l'instance du composant :

<p class="menu-wrapper" ref=&#39;menuWrapper&#39;> </p>
<p class="foods-wrapper" ref="foodsWrapper"></p>
Exécuté dans la fonction ajax _initScroll()

Avant cela, nous devons faire quelques préparatifs et précautions

(1) dom结构完全加载完再调用_initScroll()方法才会生效

(2) 因为要监听内容区域的高度,所以初始化应在created过程中去监听dom结构是否完全加载,这里是在$nextTick对象中进行触发检测

ES6语法格式: this.$nextTick(() => {})

created (){ // 在实例创建完成后被立即调用 $el 属性目前不可见。
 axios.get(&#39;static/data.json&#39;).then((result) => {
 this.goods=result.data.goods
 //dom结构加载结束
 this.$nextTick(() => {
 this._initScroll(); // 初始化scroll
 })
 })
}

(3) 在methods方法里面定义一个_initScroll的函数,主要用来对左右两侧dom结构进行初始化

methods:{
 // 用来对左右两侧dom结构进行初始化
 _initScroll (){
 // 实例化 better-scroll 插件,传入要滚动的DOM 对象 
 this.meunScroll=new BScroll(this.$refs.menuWrapper,{
 click:true 
 });
 this.foodScroll=new BScroll(this.$refs.foodsWrapper,{
 click:true
 });
 
 }
 }

说明:vue中更改数据,DOM会跟着做映射,但vue更新DOM是异步的,用 $nextTick ()来确保Dom变化后能调用到_initScroll()方法。调用_initScroll()方法能计算内层ul的高度,当内层ul的高度大于外层wrapper的高度时,可以实现滚动。

此时俩侧可以分别滚动了!

(4) 实现左右联动

原理:我们计算出右侧实时变化的y值,落到哪一个区间,我们就显示那一个区间。首先我们要计算整体区间的一个高度,然后分别计算第一个区间的高度,第二个区间的高度,以此类推。然后将区间数存入一个定义好的数组。当我们在滚动的时候实时拿到y轴的高度,然后对比在哪一个区间,这样我们就会得到一个区间的索引值去对应左侧的菜品类别,最后我们用一个vue的class去绑定高亮文本。

1.定义一个方法在 _initScroll 下面,作为计算高度的方法叫做_calculateHeight () ,再定义一个listHeight:[]数组,存放获取到的每一块foods类的高度。然后通过给每个li 定义类名来供js 选择 从而计算出高度存放到listHeight数组里。

// 通过 方法 计算foods内部每一个块的高度,组成一个数组listHeight。
 // 每个li 定义一个类food-list-hook 通过获取该类 来计算 每一块的高度 存到数组listHeight里
 _calculateHeight (){
 // 获取 li 通过food-list-hook
 let foodList=this.$refs.foodsWrapper.querySelectorAll(".food-list-hook");
 let height=0;// 初始化高度
 this.listHeight.push(height) // 把第一个高度存入数组
 //通过循环foodList下的dom结构,将每一个li的高度依次送入数组
 for(let i = 0 ,l = foodList.length ; i < l ; i++){
 let item=foodList[i]; //每一个item都是刚才获取的food的每一个dom
 height += item.clientHeight; //获取每一个foods内部块的高度
 this.listHeight.push(height) // 将获取的值存放到数组里
 }
 
 }

2.我们获取到区间高度数组后,我们要实时获取到右侧的y值,和左侧的索引值做一个对比,定义一个scrollY变量用来存放实时获取的y值。bs插件为我们提供了一个实时获取y值的方法,我们在初始化this.foodScroll的时候加一个·属性probeType: 3,其作用就是实时获取y值,相当于探针的作用。

goods: [],// goods json 数组
listHeight: [],// 存放 foods 内部的每一块的高度
scrollY:0
this.foodScroll=new BScroll(this.$refs.foodsWrapper,{
 click:true,
 //探针作用,实时监测滚动位置
 probeType: 3
 });

3.我们再添加一个方法this.foodScroll.on('scroll',(pos) => {}),作用是实时滚动的时候把获取到的位置给暴露出来。代码如下。

//结合BScroll的接口使用,监听scroll事件(实时派发的),并获取鼠标坐标,当滚动时能实时暴露出scroll
 this.foodScroll.on("scroll",(pos) =>{ // 回调函数
 //scrollY接收变量 
 this.scrollY=Math.abs(Math.round(pos.y)) //滚动坐标会出现负的,并且是小数,所以需要处理一下,实时取得scrollY
 // console.log(pos.y)
 })

4.定义一个计算属性computed,获取到food滚动区域对应的menu区域的子块的索引i值,从而定位到左侧边栏的位置。

computed:{
 currentIndex (){ //计算到达哪个区域的区间的时候的对应的索引值
 // 利用 listHeight 存放 每一块 对应的高度
 for (let i=0,l=this.listHeight.length; i<l ; i++){
 let menuHeight_fir = this.listHeight[i] // 当前menu 子块区域的 高度
 let menuHeight_sec = this.listHeight[i + 1] // 下一个menu 子块区域的 高度
 // 当滑到底部时,menuHeight_sec 为 underfined,
 // 需要确定滑到俩个高度区间 
 if( !menuHeight_sec || (this.scrollY > menuHeight_fir && this.scrollY < menuHeight_sec) ){
 return i;
 }
 }
 },
 
 }

获取到i后,,然后通过设置一个class来做样式切换变化 :class="{'current':currentIndex === index}" ,当currentIndex和menu-item对应的index相等时,设置current的样式。这样就可以实现左右联动了。

<li v-for=&#39;(item,index) in goods&#39; class="menu-item" :class="index === currentIndex?&#39;menu-item-selected&#39;:&#39;menu-item&#39;">
...

在样式里提前设好 选中和正常的样式

5.最后实现左侧点击的功能。在左侧的li下绑定一个selectMenu的点击事件,并传入索引值,这样我们就可以知道点击的是哪一个li

<li v-for=&#39;(item,index) in goods&#39; class="menu-item" @click="selectMenu(index,$event)" :class="index === currentIndex?&#39;menu-item-selected&#39;:&#39;menu-item&#39;">
...
selectMenu (index, event){ // 点击左侧 ,右侧响应
 this.foodScroll.scrollTo(0, -this.listHeight[index], 300)
 }
scrollTo(x, y, time, easing)
//滚动到某个位置,x,y 代表坐标,time 表示动画时间,easing 表示缓动函数
scroll.scrollTo(0, 500)

参考: vue使用 better-scroll的参数和方法

6.关于在selectMenu中点击事件

在selectMenu中点击,在pc界面会出现两次事件,在移动端就只出现一次事件的问题

原因 : better-scroll 会监听事件(例如touchmove,click之类),并且阻止默认事件(prevent stop),并且他只会监听移动端的,pc端的没有监听

在pc页面上 better-scroll 也派发了一次click事件,原生也派发了一次click事件

// better-scroll 的事件,有_constructed: true
MouseEvent {isTrusted: false, _constructed: true, screenX: 0, screenY: 0, clientX: 0…}
//pc的事件
MouseEvent {isTrusted: true, screenX: -1867, screenY: 520, clientX: 53, clientY: 400…}

解决 : 针对better-scroll 的事件,有_constructed: true,所以做处理,return掉非better-scroll 的事件

selectMenu(index, event){
 if (!event._constructed) { //去掉自带的click事件点击,即pc端直接返回
 return;
 }
 let foodList=this.$refs.foodsWrapper.querySelectorAll(".food-list-hook"); // 获得监听元素
 let el = foodList[index]; // 获得 当前 监听元素的高度 
 this.foodScroll.scrollToElement(el, 300); //类似jump to的功能,通过这个方法,跳转到指定的dom
 }

goods 组件到此差不多了!

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

使用原生JavaScript实现放大镜效果

在nodejs中通过redis作为缓存实现的封装缓存类

Vue Socket.io源码详细分析

vue中调用methods的方法

Vue组件通信(详细教程)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn