1

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

我想制作一个简单的 Vue 单文件组件来测试并查看我的与汇总捆绑的设置是否有效(例如,以确保我对作为模块和导出的 vue 组件的理解是正确的)。

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

到目前为止,我得到这个功能非常好(见演示)。

但是,我想将一个属性传递给两个子组件——一个 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>

section-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>

分段向上.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>

演示.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>

组件.js

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

代码库

可以在这里找到 repo 。

两个子组件:

  • /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
4

2 回答 2

2

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

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

基本上 props 列表中的 prop 是 with camelCase,但在 html 属性里面是kebap-case. 我希望这会有所帮助:)

于 2018-06-08T08:07:42.900 回答
1

为什么它不起作用

实际上,答案很简单:您没有在arrowToSection组件上放置任何道具。虽然在您的身体中有一个令人困惑的元素<arrowToSection>,但 arrowToSection 组件并未安装在其上 - 至少不是直接安装。您在创建的匿名 Vue 实例中创建 arrowToSection 组件component.js,这里:template: '<arrowToSection/>'。而且你没有向它传递任何道具。

如何修复它

要修复它,您需要在此处传递道具:

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

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

稍后注意:文档中的此示例显示属性显然是从 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',
  },
}))

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

于 2018-06-08T14:10:07.013 回答