Vue2:道具没有受约束

时间:2018-06-08 07:55:41

标签: vue.js vuejs2

注意:我是Vue的新手,但在发布之前,我已经查阅过文档并寻找其他问题。我找不到答案。我还安装了Vue dev工具来帮助调试,无法解决这个看似简单的问题。

我想制作一个简单的Vue单文件组件进行测试,看看我的汇总捆绑设置是否正常工作(例如,为了确保我对vue组件的理解,模块和导出是正确的。)

所以我的简单组件由两个较小的组件组​​成 - 一个带有V形按钮或一个V形按钮的按钮。我们的想法是让它位于页面中间,然后单击移动到下一个section标记。

到目前为止,我的功能非常好(见demo)。

但是,我想将属性传递给两个子组件 - 一个offsetSelector。无论我如何尝试设置属性,我都无法在父级别设置它(例如v-bind:offsetSelector=".navbar":offsetSelector=".navbar"offsetSelector=".navbar"等。

有人可以帮我弄清楚为什么不受约束?

箭头至section.vue

<template>
  <div>
    <up :offsetSelector="offsetSelector"></up>
    <down :offsetSelector="offsetSelector"></down>
  </div>
</template>

<script>
import down from './section-down.vue';
import up from './section-up.vue';

export default {
  components: { down, up },
  props: [ 'offsetSelector' ],
  data: function () {
    return { }
  }
}
</script>

<style scoped>
div {
  position: fixed;
  top:50%;
  margin-left: 10px;
}

div > button {
  display: block;
  margin-bottom: 10px !important;
}
</style>

部分-down.vue

<template>
  <button type="button" name="button" v-on:click="animateScrollTo">
    <i class="fa fa-chevron-down"></i>
  </button>
</template>

<script>


export default {
  props: [ 'offsetSelector' ],
  data: function () {
    return {
      offset: 0
    }
  },
  computed: {

  },
  methods: {
    setOffset: function() {
      this.offset = this.offsetSelector == undefined
      ? 0
      : $(this.offsetSelector).outerHeight() == undefined
        ? 0
        : $(this.offsetSelector).outerHeight()
    },

    animateScrollTo: function() {

      this.setOffset()


      var sections = document.querySelectorAll("section")
      var current = undefined;
      var curOffset = this.offset

      console.log('vue-down-offset', curOffset, this.offsetSelector)

      sections.forEach(function(s, i){
        var winScroll = $(window).scrollTop() - curOffset
        var curScroll = $(s).offset().top

        if ( winScroll < curScroll && current == undefined)
        { current = s }
      })

      if (current != undefined) {
        $('html, body').animate({
            scrollTop: $(current).offset().top - curOffset
        }, 1000, function() {});
      }
    }

  }
}
</script>

<style scoped>
button {
  background: radial-gradient(rgb(0, 198, 255), rgb(0, 114, 255));
  background-color: transparent;
  border: transparent 0px solid;

  margin: 0;
  padding: 0px;

  width:32px;
  height:32px;

  border-radius: 50%;
}

i { font-size: 16px; }

button:focus {
  outline: transparent 0px solid;
}
</style>

部分-up.vue

<template>
  <button type="button" name="button" v-on:click="animateScrollTo">
    <i class="fa fa-chevron-up"></i>
  </button>
</template>

<script>


export default {
  props: [ 'offsetSelector' ],
  data: function () {
    return { offset: 0 }
  },
  computed: { },
  methods: {
    setOffset: function() {
      this.offset = this.offsetSelector == undefined
      ? 0
      : $(this.offsetSelector).outerHeight() == undefined
        ? 0
        : $(this.offsetSelector).outerHeight()
    },

    animateScrollTo: function() {
      this.setOffset()

      var sections = document.querySelectorAll("section")
      var current = undefined;
      var curOffset = this.offset
      console.log('vue-up-offset', curOffset, this.offsetSelector)

      sections.forEach(function(s, i){
        var winScroll = $(window).scrollTop()
        var curScroll = $(s).offset().top - curOffset

        if ( winScroll > curScroll)
        { current = s }
      })
      if (current == undefined) {
        current = document.querySelector("body")
      }

      if (current != undefined) {
        $('html, body').animate({
            scrollTop: $(current).offset().top - curOffset
        }, 1000, function() {});
      }
    }

  }
}
</script>

<style scoped>
button {
  background: radial-gradient(rgb(0, 198, 255), rgb(0, 114, 255));
  background-color: transparent;
  border: transparent 0px solid;

  margin: 0;
  padding: 0px;

  width:32px;
  height:32px;

  border-radius: 50%;
}


button:focus {
  outline: transparent 0px solid;
}

i { font-size: 16px; }
</style>

demo.html

<style media="screen">
    section {
      height: 100vh;
    }
  </style>


  <body>
    <nav class="navbar navbar-light sticky-top">
      <a class="navbar-brand" href="../../">
          <img src="../../data/vdsm.svg" alt="logo" style="width:150px;">
          <h4 class="lead"> vue components </h4>
      </a>
      <crumbs id="crumbs"></crumbs>
    </nav>
    <arrowToSection id="arrowToSection" offset-selector=".navbar"></arrowToSection>

    <section style="background-color:#5433FF;"></section>
    <section style="background-color:#20BDFF;"></section>
    <section style="background-color:#A5FECB;"></section>
    <section style="background-color:#86fde8;"></section>

  </body>

  <script type="text/javascript" src="component.js"></script>

component.js

let arrowToSection = vdsm.arrowToSection
new Vue({
  el: '#arrowToSection',
  template: '<arrowToSection/>',
  components: { arrowToSection }
})

代码库

可以找到回购here

两个子组件:

  • /src/scripts/modules/section-up.vue
  • /src/scripts/modules/section-down.vue

我正在处理的组件:

  • /src/scripts/modules/arrow-to-section.vue

组件演示:

  • /demos/arrow-to-section/index.html

2 个答案:

答案 0 :(得分:2)

我还没有完全阅读您的存储库,但从我可以看到的答案可以在这里找到:https://vuejs.org/v2/guide/components-props.html

  

HTML属性名称不区分大小写,因此浏览器会解释   任何大写字符为小写。这意味着当你使用时   in-DOM模板,camelCased道具名称需要使用他们的kebab-cased   (连字符分隔)等价物:

道具列表中的道具基本上是camelCase,但在html属性中它是kebap-case。我希望有帮助:)

答案 1 :(得分:1)

为什么它不起作用

实际上,答案非常简单:你不在你的arrowToSection组件上添加任何道具。虽然在你的身体中有一个令人困惑的名为<arrowToSection>的元素,但它上面没有安装arrowToSection组件 - 至少不能直接安装。您可以在component.js中创建的匿名Vue实例中创建arrowToSection组件,此处为:template: '<arrowToSection/>'。你没有传递任何道具。

如何解决

要修复它,你需要在这里传递道具:

let arrowToSection = vdsm.arrowToSection
new Vue({
  el: '#arrowToSection',
  template: '<arrowToSection :offsetSelector="'.navbar'" />',
  components: { arrowToSection }
})

接下来,您可能会问“为什么不向此匿名元素添加道具,并使用在HTML中设置的值”。答案是,道具是在Vue组件之间传递值的方式。外部HTML不是Vue组件,您不能从那里传递道具。您放在#arrowToSection元素上的属性只是普通属性(整个元素被替换,参数丢失,顺便说一句)。

稍后注意:This example in documentation显示从HTML元素中明显读取的属性。这似乎与我的实验有点矛盾。如果您使用完整的v-bind:prop="..."表示法而不是:prop="..."速记,则传递道具可能会有效。

propsData

的替代解决方案

如果您真的想使用道具,可以使用propsData

let arrowToSection = vdsm.arrowToSection
new Vue({
  el: '#arrowToSection',
  props: ['offsetSelector'],
  propsData: {
    offsetSelector: '.navbar',
  },
  template: '<arrowToSection :offsetSelector="offsetSelector" />',
  components: { arrowToSection }
})

如你所见,这是非常人为的,没有意义。但是,您并不真正需要中间组件,因此,至少在实践中,您可以这样使用propsData

let arrowToSection = vdsm.arrowToSection
new Vue(Object.assign({}, arrowToSection, {
  el: '#arrowToSection',
  propsData: {
    offsetSelector: '.navbar',
  },
}))

免责声明:我不确定正式支持使用这种方式的组件。可能不是。但它确实有效。