Maison > interface Web > Voir.js > le corps du texte

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

青灯夜游
Libérer: 2022-12-05 18:53:43
avant
2924 Les gens l'ont consulté

Comment Vue restitue-t-il dynamiquement les composants via JSX ? L'article suivant vous présentera comment Vue peut restituer efficacement des composants de manière dynamique via JSX. J'espère qu'il vous sera utile !

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

1. Exigences claires

Comment rendre des composants dynamiques ? [Recommandations associées : Tutoriel vidéo vuejs]

Il existe un ensemble de structures de tableau comme suit :

const arr = [ 
  { tag: 'van-field' },  // 输入框
  { tag: 'van-cell' },   // 弹出层
  { tag: 'van-stepper' } // 步进器
]
Copier après la connexion

Je souhaite obtenir le composant correspondant pour le rendu tag en bouclant arr. tag渲染对应的组件。

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

下面我们分析如何写才是最优。

二、进行分析

2.1 v-if走天下

我们可以写一个v-for去循环arr数组,然后通过v-if去判断tag,渲染对应的组件类型。

这样子写不是不可以,只不过扩展性不好,每次加一个标签,模板就要再加一个v-if。

我相信很多人起初都是这样写。

但这不是我们优雅人该写的代码。

2.2 动态渲染组件标签

我们能不能根据tag的标签来渲染出真正的标签。

关键是循环内,怎么根据遍历的tag去渲染出真正的组件。

<van-cell  v-for="(cell, cellKey) in arr" :key="cellKey" >
      <!-- 动态渲染  -->
</van-cell>
Copier après la connexion

有请今天的主角JSX上场。

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

2.3 JSX动态渲染组件

父组件


  
  


const arr = [ 
  { tag: &#39;van-field&#39; },  // 输入框
  { tag: &#39;van-cell&#39; },   // 弹出层
  { tag: &#39;van-stepper&#39; } // 步进器
]
Copier après la connexion

子组件RendTag.vue

<script>
const AssemblyRend = {
  name: "assembly-rend",
  props: ["cell"],
  data() {
    return {
      input: "",
    };
  },
  methods: {
    onClick() {
      this.$emit("changeTag", this.input);
    },
  },
  computed:{
    itemVal:{
      get(){
        return this.cell.value
      },
      set(v){
        this.cell.value = v
      }
    }
  },
  render() {
    const { cell } = this; // 解构
    const assembly = cell.tag;  // 这里就是我们动态渲染组件的核心 

    return (
        <assembly
          v-model={this.itemVal}
          placeholder={cell.placeholder}
          min={cell.min}
          onClick={this.onClick}
        >
        </assembly>
      );
  },
};

export default {
  name: "RendTag",
  props: {
    cell: {
        type: Object,
        default:()=>{
            return {
                {
                    "title": "能否输入",
                    placeholder: &#39;请输入姓名&#39;,
                    "value": "name",
                    "tag": "van-switch",
                }
            }
        }
    },
  },
  methods: {
    changeTag(val) {},
  },
  render() {
    const { cell } = this; // 解构
    return (
      <div class="rendTag-content">
        <AssemblyRend
          cell={cell}
          onChangeTag={this.changeTag}
        ></AssemblyRend>
      </div>
    );
  },
};
</script>
Copier après la connexion

我们利用JSX的render可以写JavaScript返回组件,来实现我们动态渲染标签。

render相当于我们vue中的模板。

于是渲染出的效果如下:根据tag渲染成真正的组件

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

我们用普通的组件,无法像JSX一样渲染成我们想要的组件。

这里的v-model用计算属性的坑,我推荐看一遍:实战v-model如何绑定多循环表达式(内含原理)

其实这两篇是有一定的挂钩的,只不过我在这里拆开了需求。

主要也是方便朋友们阅读理解。

三、vue中如何使用JSX

借着该需求,我们恶补一下JSX。

3.1 是什么?

JSX 是一种 Javascript 的语法扩展,JSX = Javascript + XML,即在 Javascript 里面写 XML,因为 JSX 的这个特性,所以他即具备了 Javascript 的灵活性,同时又兼具 html 的语义化和直观性。

活度强的部分组件可以用JSX来代替(比如以上需求);
整个工程没有必要都使用JSX。

3.2 基本用法

3.2.1 函数式组件

我们在组件中,也可以嵌入ButtonCounter组件。

const ButtonCounter = {
  name: "button-counter",
  props: ["count"],
  methods: {
    onClick() {
      this.$emit("changeNum", this.count + 1);
    }
  },
  render() {
    return <button onClick={this.onClick}>数量:{this.count}</button>;
  }
};

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      count: 0
    };
  },
  methods: {
    // 改变button按钮数量
    changeNum(val) {
      this.count = val;
    }
  },
  render() {
    const { count } = this; // 解构
    return (
      <div class="hello-world-content">
        <ButtonCounter style={{ marginTop: "20px" }} count={count} onChangeNum={this.changeNum}></ButtonCounter>
      </div>
    );
  }
};
Copier après la connexion

3.2.2 普通属性、行内样式、动态class与style

可以看到,其实和vue的模板写法基本一致,只不过要注意的是花括号;

在vue的模板是要写两对花括号,而在JSX只需要写一对

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      count: 0,
      text: "Hello World!",
      msgClass: "msg-class",
      isGreen: true
    };
  },
  render() {
    const { count, text } = this; // 解构
    return (
      <div class="hello-world-content">
        <p class={this.msg ? this.msgClass : ""}>动态绑定class</p>
        <p style={this.isGreen ? "color: green" : ""}>动态绑定style</p>
      </div>
    );
  }
};
Copier après la connexion

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

3.2.3 常用指令

v-html、v-if、v-for、v-model常用指令在JSX中无法使用,需要使用其他方式来实现。

v-html

在JSX中,如果要设置DOM的innerHTML,需要用到domProps

组件使用:

<HelloWorld 
   msg="<div class=&#39;custom-div&#39;>这是自定义的DOM</div>"> 
</HelloWorld>
Copier après la connexion

组件代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {};
  },
  methods: {},
  render() {
    return <div domPropsInnerHTML={this.msg}></div>;
  }
};
Copier après la connexion

渲染DOM结果:

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

v-for

使用map来实现:

render() {
  const list = [1,2,3]
  return( 
    <div>
      { list.map(item => <button>按钮{item}</button>) }
    </div>
  )
}
Copier après la connexion

v-if

简单示例:用三元

render() {
    const bool = false;
    return <div>{bool ? <button>按钮1</button> : <button>按钮2</button>}</div>;
}
Copier après la connexion

复杂示例:直接用JS

render() {
  let num = 3
  if(num === 1){ return( <button>按钮1</button> ) }
  if(num === 2){ return( <button>按钮2</button> ) }
  if(num === 3){ return( <button>按钮3</button> ) }
}
Copier après la connexion

v-model

直接使用:<input v-model={this.value}>

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

ci-dessous Nous analysons comment écrire de manière optimale.

Deuxièmement, analyser

2.1 v-si voyager autour du monde

Nous pouvons écrire un v-for parcourt le tableau arr, puis utilise v-if pour déterminer la balise et restituer le type de composant correspondant.

🎜Il n'est pas impossible d'écrire ainsi, mais l'évolutivité n'est pas bonne. Chaque fois qu'une balise est ajoutée, un v-if doit être ajouté au modèle. 🎜🎜Je crois que beaucoup de gens ont écrit comme ça au début. 🎜🎜Mais ce n’est pas le code que nous, les gens élégants, devrions écrire. 🎜

🎜2.2 Rendu dynamique des balises de composants🎜

🎜Pouvons-nous restituer la vraie balise en fonction de la balise de tag. 🎜🎜La clé est de savoir comment restituer le composant réel en fonction des balises parcourues dans la boucle. 🎜
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      value: "abc"
    };
  },
  watch: {
    value(val) {
      console.log("this.model内容:" + val);
    }
  },
  methods: {},
  render() {
    return (
      <div>
        <input v-model={this.value} placeholder="普通文本" />
      </div>
    );
  }
};
Copier après la connexion
🎜 Le protagoniste d'aujourd'hui, JSX, est invité à comparaître. 🎜🎜Parlons de la façon dont Vue restitue dynamiquement les composants via JSX🎜

🎜2.3 Composant de rendu dynamique JSX🎜

🎜Composant parent🎜
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {};
  },
  methods: {
    handleClick(val) {
      alert(val);
    }
  },
  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick.bind(this, 11)}>
          方式一
        </button>
        <button type="button" onClick={() => this.handleClick(22)}>
          方式二
        </button>
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion
🎜Composant enfant RendTag.vue🎜
methods: {
    input(e) {
      this.value = e.target.value;
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} onInput={this.input} />
      </div>
    );
  }
Copier après la connexion
Copier après la connexion
🎜Nous pouvons écrire du JavaScript en utilisant le render de JSX. le composant pour implémenter notre rendu dynamique des balises. 🎜🎜render est équivalent au modèle dans notre vue. 🎜🎜Donc l'effet de rendu est le suivant : rendu dans un composant réel selon la balise🎜🎜Parlons de la façon dont Vue restitue dynamiquement les composants via JSX🎜🎜Nous utilisons des composants ordinaires, qui ne peuvent pas être restitués dans les composants que nous voulons comme JSX. 🎜🎜Le v-model utilise ici des attributs calculés. Je recommande de le lire : V-model pratique comment lier des expressions multi-boucles (y compris les principes)🎜🎜🎜En fait, ces deux articles sont quelque peu liés, mais je Les exigences sont décomposées ici. 🎜🎜Principalement pour faciliter la lecture et la compréhension des amis. 🎜

3. Comment utiliser JSX dans vue🎜🎜Avec cette demande, nous compenserons JSX. 🎜

🎜3.1 Qu'est-ce que c'est ? 🎜

🎜JSX est une extension de syntaxe de Javascript, JSX = Javascript + XML, c'est-à-dire l'écriture de XML en Javascript. En raison de cette fonctionnalité de JSX, il a la flexibilité de Javascript, tout en. ayant la sémantique et l’intuitivité du HTML. 🎜
🎜Certains composants à forte activité peuvent être remplacés par JSX (comme les exigences ci-dessus) ;
Il n'est pas nécessaire d'utiliser JSX pour l'ensemble du projet. 🎜

🎜3.2 Utilisation de base🎜

🎜3.2.1 Composants fonctionnels🎜🎜🎜Nous sommes ici Dans le composant, le composant ButtonCounter peut également être intégré. 🎜
<input 
  type="text" 
  value={this.value} 
  onInput={(e) => (this.vaue = e.target.value)} 
/>
Copier après la connexion
Copier après la connexion

🎜3.2.2 Attributs communs, styles en ligne, classes et styles dynamiques🎜🎜🎜Comme vous pouvez le voir, c'est fondamentalement la même chose que la méthode d'écriture de modèle de vue, mais il convient de noter que les accolades ; 🎜🎜Dans le modèle vue, vous devez écrire deux paires d'accolades, mais dans JSX vous n'avez besoin d'écrire que 🎜une paire🎜. 🎜
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      value: ""
    };
  },
  watch: {
    value(val) {
      console.log("this.model的内容:" + val);
    }
  },
  methods: {
    handleInput(e) {
      this.value = e.target.value;
    },
    handleFocus(e) {
      console.log(e.target);
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} {...{ on: { input: this.handleInput, focus: this.handleFocus } }} />
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion
🎜Parlons de la façon dont Vue restitue dynamiquement les composants via JSX🎜< h4 data-id="heading-11">🎜3.2.3 Instructions communes 🎜🎜🎜 Les instructions communes v-html, v-if, v-for, v-model ne peuvent pas être utilisées dans JSX et doivent être implémentées d'une autre manière . 🎜🎜🎜v-html🎜🎜🎜Dans JSX, si vous souhaitez définir le innerHTML du DOM, vous devez utiliser domProps. 🎜🎜Utilisation du composant : 🎜
{...{nativeOn:{click: this.handleClick}}}
Copier après la connexion
Copier après la connexion
🎜Code du composant : 🎜
if (event.target !== event.currentTarget){
  return
}
Copier après la connexion
Copier après la connexion
🎜Résultat DOM rendu : 🎜🎜Parlons de la façon dont Vue restitue dynamiquement les composants via JSX🎜🎜🎜v-for🎜🎜🎜Utilisez map pour implémenter : 🎜
if(event.keyCode === 13) {
  // 执行逻辑
}
Copier après la connexion
Copier après la connexion
🎜🎜v-if🎜🎜🎜Exemple simple : utiliser Ternaire 🎜
export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  methods: {
    handleClick(e) {
      console.log("click事件:" + e.target);
    },
    handleInput(e) {
      console.log("input事件:" + e.target);
    },
    handleMouseDown(e) {
      console.log("mousedown事件:" + e.target);
    },
    handleMouseUp(e) {
      console.log("mouseup事件" + e.target);
    }
  },
  render() {
    return (
      <div
        {...{
          on: {
            // 相当于 :click.capture
            "!click": this.handleClick,
            // 相当于 :input.once
            "~input": this.handleInput,
            // 相当于 :mousedown.passive
            "&mousedown": this.handleMouseDown,
            // 相当于 :mouseup.capture.once
            "~!mouseup": this.handleMouseUp
          }
        }}
      >
        点击模块
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion
🎜Exemple complexe : utiliser directement JS🎜
<HelloWorld>
    <template slot="default">默认内容</template>
    <template slot="footer">
      <el-button type="primary">确定</el-button>
      <el-button>取消</el-button>
    </template>
</HelloWorld>
Copier après la connexion
Copier après la connexion
🎜🎜v-model🎜🎜🎜Utiliser directement : <input v-model={this.value}>🎜
export default {
  name: "HelloWorld",
  render() {
    return (
      <div>
        <div class="default">{this.$slots.default}</div>
        <div class="footer">{this.$slots.footer}</div>
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion
🎜🎜3.2 . 4 Événements d'écoute et modificateurs d'événements🎜🎜🎜🎜Événements d'écoute🎜🎜🎜Je pense utiliser onChange, onClick, etc. pour écouter les événements. 🎜

需要注意的是,传参数不能使用 onClick={this.handleClick(params)},这样子会每次 render的时候都会自动执行一次方法。

应该使用bind,或者箭头函数来传参。

组件示例代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {};
  },
  methods: {
    handleClick(val) {
      alert(val);
    }
  },
  render() {
    return (
      <div>
        <button type="button" onClick={this.handleClick.bind(this, 11)}>
          方式一
        </button>
        <button type="button" onClick={() => this.handleClick(22)}>
          方式二
        </button>
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion

用监听事件来实现v-model:

methods: {
    input(e) {
      this.value = e.target.value;
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} onInput={this.input} />
      </div>
    );
  }
Copier après la connexion
Copier après la connexion

也可以调整为:

<input 
  type="text" 
  value={this.value} 
  onInput={(e) => (this.vaue = e.target.value)} 
/>
Copier après la connexion
Copier après la connexion

还可以使用对象的方式去监听事件:解构事件

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  data() {
    return {
      value: ""
    };
  },
  watch: {
    value(val) {
      console.log("this.model的内容:" + val);
    }
  },
  methods: {
    handleInput(e) {
      this.value = e.target.value;
    },
    handleFocus(e) {
      console.log(e.target);
    }
  },
  render() {
    return (
      <div>
        <input type="text" value={this.value} {...{ on: { input: this.handleInput, focus: this.handleFocus } }} />
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion

nativeOn仅对于组件,用于监听原生事件,也可以使用对象的方式去监听事件:

{...{nativeOn:{click: this.handleClick}}}
Copier après la connexion
Copier après la connexion

事件修饰符

和指令一样,除了个别的之外,大部分的事件修饰符都无法在JSX中使用。

  • .stop : 阻止事件冒泡,在JSX中使用event.stopPropagation()来代替
  • .prevent:阻止默认行为,在JSX中使用event.preventDefault() 来代替
  • .self:只当事件是从侦听器绑定的元素本身触发时才触发回调,使用下面的条件判断进行代替
if (event.target !== event.currentTarget){
  return
}
Copier après la connexion
Copier après la connexion

.enter与keyCode: 在特定键触发时才触发回调

if(event.keyCode === 13) {
  // 执行逻辑
}
Copier après la connexion
Copier après la connexion

除了上面这些修饰符之外,尤大大对于.once,.capture,.passive,.capture.once做了优化,简化代码:

export default {
  name: "HelloWorld",
  props: {
    msg: String
  },
  methods: {
    handleClick(e) {
      console.log("click事件:" + e.target);
    },
    handleInput(e) {
      console.log("input事件:" + e.target);
    },
    handleMouseDown(e) {
      console.log("mousedown事件:" + e.target);
    },
    handleMouseUp(e) {
      console.log("mouseup事件" + e.target);
    }
  },
  render() {
    return (
      <div
        {...{
          on: {
            // 相当于 :click.capture
            "!click": this.handleClick,
            // 相当于 :input.once
            "~input": this.handleInput,
            // 相当于 :mousedown.passive
            "&mousedown": this.handleMouseDown,
            // 相当于 :mouseup.capture.once
            "~!mouseup": this.handleMouseUp
          }
        }}
      >
        点击模块
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion

3.3 插槽

3.3.1 普通插槽与具名插槽

父传子。

示例:

<HelloWorld>
    <template slot="default">默认内容</template>
    <template slot="footer">
      <el-button type="primary">确定</el-button>
      <el-button>取消</el-button>
    </template>
</HelloWorld>
Copier après la connexion
Copier après la connexion

HelloWorld组件代码:this.$slots

export default {
  name: "HelloWorld",
  render() {
    return (
      <div>
        <div class="default">{this.$slots.default}</div>
        <div class="footer">{this.$slots.footer}</div>
      </div>
    );
  }
};
Copier après la connexion
Copier après la connexion

3.3.2 作用域插槽

子传父。

示例:

<HelloWorld>
    <template v-slot:content="{ name, age }">
      <div>姓名:{{ name }}</div>
      <div>年龄:{{ age }}</div>
    </template>
</HelloWorld>
Copier après la connexion

HelloWorld组件代码:this.$scopedSlots

export default {
  name: "HelloWorld",
  render() {
    return (
      <div>
        <div class="content">{this.$scopedSlots.content({ name: "张三", age: 20 })}</div>
      </div>
    );
  }
};
Copier après la connexion

子组件通过{this.$scopedSlots.content({ name: "张三", age: 20 })}指定插槽的名称为content,并将含有name,age属性的对象数据传递给父组件,父组件就可以在插槽内容中使用子组件传递来的数据。

看到v-html用innerHTML;v-for用map;.stop用event.stopPropagation()
你有什么感想?
这不就是我们JavaScript方法的操作吗。
所以JSX就是Javascript + XML。

Parlons de la façon dont Vue restitue dynamiquement les composants via JSX

后记

我以前一直觉得Vue中没必要用JSX吧,用模板Template足以了。

但经过这个需求,我想JSX在处理动态渲染组件还是蛮占有优势的?。

日后面试官问我JSX在Vue的有什么应用场景,我想我可以把这个需求说一说。

(学习视频分享:web前端开发编程基础视频

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!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal