Доступ к $ refs родителя от ребенка - Vue.js - PullRequest
0 голосов
/ 12 июня 2018

Надеюсь, на этот вопрос уже был дан ответ - по сути, я пытаюсь добавить блок ("CodeBlock.vue") к элементу внутри App.vue из события onClick, инициированного внутри одного из элементов CodeBlock, и потомка App.vue, ("ButtonSidebar.vue").Меня немного смущает генерация событий и / или использование экземпляра eventBus Vue, поэтому любые указатели будут с благодарностью приняты:

Пока у меня есть следующее.CodeBlock.vue, который будет использоваться как экземпляр и добавляться в div внутри App.vue.

CodeBlock.vue:

<template>
  <div :class="type">
    THIS IS A CODE BLOCK!!
  </div>
</template>

<script>
export default {
  name: 'CodeBlock',
  props: [ 'type' ]
}
</script>

App.vue:

<template>
  <div id="app" class="container">
    <ButtonSidebar/>
    <div id="pageBlocks" ref="container"></div>
  </div>
</template>

<script>
import Vue from 'vue'
import BootstrapVue from 'bootstrap-vue'

// import { eventBus } from './main'

import AddTitle from './components/modules/AddTitle'
import AddSubTitle from './components/modules/AddSubTitle'
import ButtonSidebar from './components/modules/ButtonSidebar'
import CodeBlock from './components/modules/CodeBlock'

import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'

Vue.use(BootstrapVue)

export default {
  name: 'App',
  components: {
    AddTitle,
    AddSubTitle,
    ButtonSidebar,
    CodeBlock
  }
}
</script>

<style>
#app {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #1f1f1f;
  margin-top: 60px;
}

.no-border {
  border: unset !important;
  border: 0px !important;
}
</style>

ButtonSidebar.vue:

<template>
  <div>
    <b-button class="btn-circle absolute-float-tight text-dark" v-on:click="reveal=!reveal">
      <font-awesome-icon v-if="!reveal" :icon="faPlusIcon" />
      <font-awesome-icon v-if="reveal" :icon="faMinusIcon" />
    </b-button>
    <transition name="custom-classes-transition" enter-active-class="animated bounceInDown" leave-active-class="animated bounceOutRight">
      <div v-if="reveal" class="absolute-float-reveal">
        <b-button class="btn-circle text-dark" v-on:click="addCodeBlock"><font-awesome-icon :icon="faCodeIcon" /></b-button>
      </div>
    </transition>
  </div>
</template>

<script>
import Vue from 'vue'

import FontAwesomeIcon from '@fortawesome/vue-fontawesome'
import faPlus from '@fortawesome/fontawesome-pro-regular/faPlus'
import faMinus from '@fortawesome/fontawesome-pro-regular/faMinus'
import faCode from '@fortawesome/fontawesome-pro-regular/faCode'

import CodeBlock from './CodeBlock'

export default {
  name: 'ButtonSidebar',
  computed: {
    faPlusIcon () {
      return faPlus
    },
    faMinusIcon () {
      return faMinus
    },
    faCodeIcon () {
      return faCode
    }
  },
  components: {
    FontAwesomeIcon,
    CodeBlock
  },
  data () {
    return {
      reveal: false
    }
  },
  props: ['codeBlocks'],
  methods: {
    addCodeBlock () {
      var ComponentClass = Vue.extend(CodeBlock)
      var instance = new ComponentClass({
        propsData: { type: 'primary' }
      })
      instance.$mount()

      this.$el.querySelector('#pageBlocks').appendChild(instance.$el)
    }
  }
}
</script>

<style scoped>

  .absolute-float-tight {
    left: 20px;
    position: absolute;
  }

  .absolute-float-reveal {
    left: 60px;
    position: absolute;
  }

  .btn-circle {
    background-color: transparent;
    border-radius: 50%;
    height: 34px;
    padding: 0;
    width: 34px;
  }

</style>

Вокруг части this.$el.querySelector('#pageBlocks').appendChild(instance.$el) я начинаю немного терять сюжет ... Я боюсь, что мне придется все урезать и, возможно, начать заново?

Ответы [ 2 ]

0 голосов
/ 12 июня 2018

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

Так что в вашем случае, если codeBlocks доступно в ваших App.vue компонентах, SidebarButton должно генерировать событие, когда онощелкнул, чтобы родитель App.vue смог добавить новый Codeblock:

(я удалил некоторый код, который не нужен для примера. CodeBlock.vue остался прежним)

App.vue

<template>
  <div id="app" class="container">
    <ButtonSidebar @add-block="addCodeBlock" />
    <CodeBlock v-for="block in codeBlocks" :type="block.type" />
  </div>
</template>

<script>
import ButtonSidebar from '../ButtonSidebar'
import CodeBlock from '../CodeBlock'

export default {
  name: 'App',

  components: {ButtonSidebar, CodeBlock},

  data() {
      return {
          codeBlocks: []
      }
  },
  methods: {
      addCodeBlock() {
          const newBlock = {type: 'whatever'}
          this.codeBlocks.push(newBlock)
      }
  }
}
</script>

ButtonSideBar.vue

<template>
  <div>
    <b-button class="btn-circle text-dark" v-on:click="addCodeBlock</b-button>
  </div>
</template>

<script>  
export default {
  name: 'ButtonSidebar',

  data () {
    return {
      reveal: false
    }
  },

  methods: {
    addCodeBlock () {
      this.$emit('add-block')
    }
  }
}
</script>

Хорошая схема, которой следует следовать в Vue, это поднять состояние до родителей и передатьэто как опора, когда вы чувствуете, что хотите разделить состояние между родителями и детьми.

0 голосов
/ 12 июня 2018

Я думаю, вы могли бы достичь этого простым способом:

App.vue (раздел шаблона)

<ButtonSidebar @add="addCodeItem"/>
<div id="pageBlocks">
    <codeBlock v-for="code in arrCodes" :type="code.type"/>
</div>

App.vue (скрипт)

export default {
  data() {
     return {
        arrCodes: []
     }
  },
  methods: {
     addCodeItem(codeType) {
        this.arrCodes.push( { type: codeType } )
     }
  }
}

ButtonSidebar.vue (секция скрипта)

addCodeBlock () {
  this.$emit('add', 'yourtype');
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...