Использование синтаксиса jsx в vue

Vue.js
Использование синтаксиса jsx в vue

Что такое JSX?

JSX — это формат, сочетающий Javascript и XML. React изобрел JSX, используя синтаксис HTML для создания виртуального DOM. Когда он встречает

Почему я должен использовать JSX в vue?

Хочу подкинуть, шучу.Во-первых, потому что я недавно учился реагировать, я испытал в нем jsx-грамматику, и я обнаружил, что не было дискомфортного ощущения, что говорят другие, поэтому я хотел попробовать это в vue, ерунда. Без лишних слов давайте воспользуемся кодом, чтобы увидеть разницу между ними.

ps:Для большинства сцен в Vue не нужно использовать функцию рендеринга, либо шаблон более лаконичен и интуитивно понятен..

использовать шаблон

// item.vue
<template>
 <div>
   <h1 v-if="id===1">
     <slot></slot>
   </h1>
   <h2 v-if="id===2">
     <slot></slot>
   </h2>
   <h3 v-if="id===3">
     <slot></slot>
   </h3>
   <h4 v-if="id===4">
     <slot></slot>
   </h4>
 </div>
</template>

<script>
   export default {
       name: "item",
       props:{
         id:{
           type:Number,
           default:1
         }
       }
   }
</script>

Компонент элемента должен получать значение идентификатора, переданное родительским компонентом, для отображения различных тегов h, можно сказать, что v-if использует «экстремальный» и записывает множество избыточных слотов.

Использование функции рендеринга и jsx

// item.vue
<script>
   export default {
       name: "item",
       props:{
         id:{
           type:Number,
           default:1
         }
       },
     render(){
         const hText=`
                       <h${this.id}>${this.$slots.default[0].text}</h${this.id}>
                     `
       return <div domPropsInnerHTML={hText}></div>
     }
   }
</script>

Плюс родительский компонент для управления значением реквизита. Родительский компонент не сравнивает и использует традиционный формат шаблона.

// list.vue
<template>
 <div>
   <h-title :id="id">Hello World</h-title>
   <button @click="next">下一个</button>
 </div>
</template>

<script>
 import Title from './item'

 export default {
   name: "list",
   data() {
     return {
       id:1
     }
   },
   components: {
     "h-title":Title
   },
   methods:{
     next(){
       ++this.id
     }
   }
 }
</script>

После запуска страница будет отображать тег h1, h2 или h3, и есть только один слот.Нажмите, чтобы переключить значение реквизита, и также будут отображаться разные теги h. Хотя второй способ написания не очень прямолинеен, он экономит много избыточного кода, а страница становится намного чище.

А если нет v-if, v-for, v-model?

Не волнуйтесь, эти инструкции — просто черная магия, которую легко реализовать с помощью js.

  • v-if
  render(){
       return (
         <div>
           {this.show?'你帅':'你丑'}
         </div>
       )
     }

Вы можете писать только простые троичные выражения, а if/else используются для сложных выражений.

   render(){
        let ifText
        if(this.show){
            ifText=<p>你帅</p>
        }else{
            ifText=<p>你丑</p>
        }
        return (
          <div>
            {ifText}
          </div>
        )
      }

  • v-for
     data(){
        return{
          show:false,
          list:[1,2,3,4]
        }
      },
      render(){
        return (
          <div>
            {this.list.map((v)=>{
              return <p>{v}</p>
            })}
          </div>
        )
      }

В jsx {} нет возможности писать операторы if/for, можно писать только выражения, поэтому карта используется как цикл, а троичное выражение используется как суждение.

  • v-model

    Недавно я помогал компании проводить собеседования и набирать людей и обнаружил, что многие люди в v-model не знают, что такое синтаксический сахар? Потом некоторые люди говорят, что я могу реализовать это с помощью нативного js, но они даже не знают, как это реализовать в vue, ну и два момента: передача значений и прослушивание событий для изменения значений.

    <script>
    export default {
        name: "item",
      data(){
        return{
          show:false,
          list:[1,2,3,4],
          text:'',
        }
      },
      methods:{
        input(e){
          this.text=e.target.value
        }
      },
      render(){
        return (
          <div>
            <input type="text" value={this.text} onInput={this.input}/>
            <p>{this.text}</p>
          </div>
        )
      }
    }
</script>

Как использовать пользовательские компоненты?

Это очень просто, просто импортируйте, не нужно объявлять в атрибуте components, пишите прямо в jsx, например

<script>
  import HelloWolrd from './HelloWorld'
    export default {
      name: "item",
      render(){
        return (
            <HelloWolrd/>
        )
      }
    }
</script>

Как связать события, класс, стиль, ссылку и т.д.?

Посмотрите на надпись ниже

render (h) {
  return (
    <div
      // normal attributes or component props.
      id="foo"
      // DOM properties are prefixed with `domProps`
      domPropsInnerHTML="bar"
      // event listeners are prefixed with `on` or `nativeOn`
      onClick={this.clickHandler}
      nativeOnClick={this.nativeClickHandler}
      // other special top-level properties
      class={{ foo: true, bar: false }}
      style={{ color: 'red', fontSize: '14px' }}
      key="key"
      ref="ref"
      // assign the `ref` is used on elements/components with v-for
      refInFor
      slot="slot">
    </div>
  )
}

Выше следует отметить одну вещь: при привязке событий к пользовательским компонентам используйте nativeOnClick, и используется формат шаблона.@click.native, Кроме того, когда он используется для привязки событий к функциональным компонентам, это немного ям. О нем поговорим ниже.

Функциональные компоненты в JSX

Функциональные компоненты не имеют состояния и не имеют экземпляра this.В документации vue упоминается следующий отрывок:

Поскольку функциональный компонент — это просто функция, накладные расходы на рендеринг также намного ниже. Однако отсутствие постоянных экземпляров также означает, что функциональные компоненты не отображаются в дереве компонентов Vue devtools.

Я лично понимаю, что из-за отсутствия состояния (данных) обработка намного менее отзывчива, а такие процессы, как жизненный цикл, улучшат скорость и снизят использование памяти, верно?

Функциональные компоненты также могут использоваться в формате шаблона, как это

<template functional>

</template

Как насчет функциональных компонентов в jsx? Это также очень просто, просто добавьте конфигурациюfunctional: trueпросто хорошо Этот функциональный компонент ушелthisКак экземпляры связывают события и как они получают реквизиты?

Все, что нужно компоненту, передается через контекст, в том числе:

  • props: объект, предоставляющий все реквизиты
  • children: массив дочерних узлов VNode
  • slots: функция, которая возвращает объект всех слотов
  • data: объект данных передается компоненту, а компонент передается в качестве второго параметра для createElement.

Выше я перечислил лишь некоторые свойства, это вещи для нефункциональных компонентов, для функциональных компонентов Vue добавляет объект контекста, который необходимо использовать какrender(h,context)Второй параметр передается,this.$slots.defaultобновить доcontext.childrenреквизит изначально вешался прямо на это, а теперь становитсяcontext.propsЗавис на context.props.this.dataсталcontext.data

Следует отметить, что для функциональных компонентов нет свойства, определяемого как свойство.Не будуАвтоматически добавляется в корневой элемент компонента, а это значит, что нам нужно вручную добавить его в корневой элемент компонента.Рассмотрим пример.

//父组件
 ...省略无关代码
 render(){
      return (
        <Item data={this.data} class="large"/>
      )
    }
//Item.vue组件
export default {
    functional:true,
      name: "item",
      render(h,context){
        return (
          <div class="red" >
            {context.props.data}
          </div>
        )
      }
    }

Приведенный выше код предполагает, что имя класса .large будет передано корневому элементу Item, но это не так. нам нужно что-то добавить

// Item.vue
export default {
    functional:true,
      name: "item",
      render(h,context){
        return (
          <div class="red" {...context.data}>
            {context.props.data}
          </div>
        )
      }
    }

Обратите внимание, что все атрибуты добавляются к корневому элементу через оператор расширения.Этот context.data является атрибутом, который вы добавили к дочернему компоненту в родительском компоненте.Он будет интеллектуально объединен с атрибутами корневого элемента дочернего элемента. Теперь .large Имя класса передается. Это полезно, когда вам нужно привязать события от родительских компонентов к дочерним компонентам. Поговорим о небольшой яме о привязке событий

Передавая context.data в качестве второго параметра createElement, мы передаем все функции и прослушиватели событий выше my-functional-button. На самом деле это очень прозрачно, эти события даже не требуют модификатора .native.

Вышеприведенный абзац с официального сайта Vue, но, прочитав его один раз, я упустил из виду очень важное предложение, которое является последним предложением Он сказал, что модификатор .native не нужен? хорошо посмотри на код

// 父组件
 methods:{
      show(){
        alert('你好')
      }
    },
    render(){
      return (
        <Item data={this.data} onNativeClick={this.show} class="large"/>
      )
    }

Приведенный выше код на первый взгляд выглядит нормально. Пользовательский компонент использует onNativeClick, и в результате окно не появляется. Увы, я в итоге несколько раз прочитал объяснение в документе vue, и обнаружил, что исходный функциональный компонент не нуждается в модификаторе .native, и формат шаблона точно отражен, а вот для jsx ну и поставьте вышеуказанноеonNativeClickизменить наonClickДостаточно.

Какие функции существующих проектов можно заменить jsx?

На самом деле это очень похоже на пример, который я привел в начале. Я использовал его в своем проекте, чтобы избавиться от полноэкранного режима v-if/v-else. Так как мой бизнес на блокноте, требование состоит в том, чтобы в наборе контрольных работ были десятки вопросов, и только один вопрос должен отображаться на одном экране, а следующий вопрос отображается при нажатии на следующий вопрос. Идея относительно проста:

  1. Используйте переменную num для представления индекса темы, отображаемой в данный момент.
  2. num++ каждый раз, когда нажимается кнопка следующего вопроса
  3. Используйте v-if, чтобы определить num===1 и num===2, чтобы решить, что отображать.

В этом письме очень много шаблонов, так как шаблоны наших вопросов могут быть разными для каждого вопроса, нет возможности зациклиться, поэтому мы можем написать их все только вручную. Раньше я рассматривал возможность использования динамических компонентов для переключения, но отказался от этого, потому что это не интуитивно понятно.

Давайте посмотрим, как оптимизировать его с помощью jsx.

//父组件
  export default {
    name: "list",
    data() {
      return {
       data:'我是函数式组件',
        id:1,
         tests:{
          1:<div><span>第一道题</span></div>,
          2:<div><section>第二道题</section></div>,
          3:<div><p>第三道题</p></div>
        }
      }
    },
    methods:{
      next(){
        ++this.id
      }
    },
    render(){
      return (
       <div>
         <Item data={this.tests[this.id]} class="large"/>
         <button onClick={this.next}>下一题</button>
       </div>
      )
    }
  }

Структура каждого из вышеперечисленных вопросов противоречива

 //子组件,只接受数据展示,用函数式组件
<script>
  export default {
  functional:true,
    name: "item",
    render(h,context){
      return (
        <div class="red" {...context.data}>
          {context.props.data}
        </div>
      )
    }
  }
</script>

Вышеупомянутая функция выполняется без каких-либо оценок if/else.Я думаю, что здесь более уместно использовать jsx.Интересно, есть ли у вас какие-либо другие идеи?

Наконец

Подводя итог, мы обычно используем шаблон для разработки, потому что он интуитивно понятен и лаконичен, а различные инструкции очень удобны в использовании.Когда вы чувствуете, что код, написанный в шаблоне, выглядит избыточным, или вы хотите сами контролировать логику рендеринга, например зацикливание, суждение и т. д. Рассмотрите возможность использования JSX. Кроме того, рекомендуется использовать функциональные компоненты для повышения производительности.

Я впервые пишу статью.Я надеюсь, что большие ребята, которые нашли время, чтобы прочитать это, чувствуют, что это не строго и нужно простить.Я приму любые комментарии.

использованная литература

функция рендеринга vue и jsx

babel-plugin-transform-vue-jsx