Vuejs 子组件中的道具值无法绑定到元素属性

Posted

技术标签:

【中文标题】Vuejs 子组件中的道具值无法绑定到元素属性【英文标题】:Prop value in Vuejs child component not available to bind to element attribute 【发布时间】:2019-09-24 16:30:32 【问题描述】:

我正在使用 Vuetify 在 Vuejs 中开发一个管理应用程序,并且我在表单中有三个字段供用户选择十六进制颜色值。为了方便用户,我实现了一个基于this codepen 的颜色选择器。

这里是ColorPickerButton 组件:

<template>
    <div ref="colorpicker" class="color-picker-outer">
      <span class="color-picker-inner" v-bind:style=" 'background-color': colorValue" @click="togglePicker"></span>
            <chrome-picker :value="colors" @input="updateFromPicker" v-if="displayPicker" />
    </div>
</template>

<script>
import  Chrome  from 'vue-color'

export default 
    props: 
        fieldName: String,
        initColor: string
    ,
  components: 
      'chrome-picker': Chrome
  ,
  data() 
    return 
      colors: 
                hex: '#000000',
            ,
            colorValue: this.initColor,
            displayPicker: false,
    
  ,
  mounted() 
        this.setColor(this.color || '#3121e0');
  ,
    methods: 
        setColor(color) 
            this.updateColors(color);
            this.colorValue = color;
        ,
        updateColors(color) 
            if(color.slice(0, 1) == '#') 
                this.colors = 
                    hex: color
                ;
            
            else if(color.slice(0, 4) == 'rgba') 
                var rgba = color.replace(/^rgba?\(|\s+|\)$/g,'').split(','),
                    hex = '#' + ((1 << 24) + (parseInt(rgba[0]) << 16) + (parseInt(rgba[1]) << 8) + parseInt(rgba[2])).toString(16).slice(1);
                this.colors = 
                    hex: hex,
                    a: rgba[3],
                
            
        ,
        showPicker() 
            document.addEventListener('click', this.documentClick);
            this.displayPicker = true;
        ,
        hidePicker() 
            document.removeEventListener('click', this.documentClick);
            this.displayPicker = false;
        ,
        togglePicker() 
            this.displayPicker ? this.hidePicker() : this.showPicker();
        ,
        updateFromInput() 
            this.updateColors(this.colorValue);
        ,
        updateFromPicker(color) 
            this.colors = color;
            if(color.rgba.a == 1) 
                this.colorValue = color.hex;
            
            else 
                this.colorValue = 'rgba(' + color.rgba.r + ', ' + color.rgba.g + ', ' + color.rgba.b + ', ' + color.rgba.a + ')';
            
        ,
        documentClick(e) 
          var el = this.$refs.colorpicker,
                target = e.target;
            if(el !== target && !el.contains(target)) 
                this.hidePicker()
            
            this.$emit('update-color', this.colorValue, this.fieldName)
        
  ,
  watch: 
        colorValue(val) 
            if(val) 
                this.updateColors(val);
                this.$emit('input', val);
                //document.body.style.background = val;
            
        
    

</script>

<style scoped>
  div.color-picker-outer 
    width: 55px;
    height: 50px;
    display: inline-block;
    background-color: #EEE;
    position: relative;
  

  .color-picker-inner 
    width: 30px;
    height: 30px;
    position: relative;
    top: 10px;
    left: 13px;
    display: inline-block;
  

    .vc-chrome 
    position: absolute;
    top: 0px;
    left: 55px;
    z-index: 9;
  
</style>

这是我从父组件TenantTemplateEdit.vue 调用它的方式。

              <v-layout row>
                <v-flex xs4>
                  <v-text-field
                    v-bind="fields.alertBackgroundColor"
                    v-model="templateModel.alertBackgroundColor"
                    placeholder="#4A4A4A"
                  />
                </v-flex>
                <v-flex xs2>
                  <ColorPickerButton
                    v-bind:field-name="'alertBackgroundColor'"
                    v-bind:init-color="templateModel.alertBackgroundColor"
                    v-on:update-color="getUpdatedColor">
                  </ColorPickerButton>
                </v-flex>
                <!-- Alert Text Color -->
                <v-flex xs4>
                  <v-text-field
                    v-bind="fields.alertTextColor"
                    v-model="templateModel.alertTextColor"
                    placeholder="#4A4A4A"
                  />
                </v-flex>
                <v-flex xs2>
                  <ColorPickerButton
                    v-bind:field-name="'alertTextColor'"
                    v-bind:init-color="templateModel.alertTextColor"
                    v-on:update-color="getUpdatedColor"
                  ></ColorPickerButton>
                </v-flex>
              </v-layout>

我正在努力解决的问题是在数据更改时为span.color-picker-inner 元素设置初始颜色。并且ColorPickerButton 组件是从TenantTemplateEdit 调用的。我已验证 initColor 属性已正确传递并且在 ColorPickerButton 中可用,但我没有在模板中访问我的 background-color 属性。

我需要更改什么才能在初始加载时设置background-color

【问题讨论】:

如何从 TenantTemplateEdit 传递initColor?例如::init-color="SomeColorCode" 还是什么? @click="togglePicker()" 应该是 @click="togglePicker" (forum.vuejs.org/t/…),因为你没有通过函数的任何参数。 你有错误吗?您是否检查过元素并看到该样式确实没有被应用?您是否首先记录 colorValue 以查看它是否具有正确的字符串值?你能在codepen上重现吗? (如果“background-color 属性”是指样式属性) @ajafari 我更新了上面的代码。 @muka.gergely 谢谢,已修复。 【参考方案1】:

如果你更正了一些拼写错误等(如 string 而不是 Stringv-bind 处没有参数,清除 mounted() 钩子在选择器模板中),它应该可以工作。

这是一个工作示例(内部颜色会随着您选择新颜色而变化,并且在初始加载时设置):

https://codesandbox.io/s/p9620jzoy7

我希望我正确理解了您的问题,并且这个 sn-p 对您有所帮助。

我把代码贴在这里(代码经过编辑,可以在沙盒环境中使用):

// ColorPickerButton.vue

<template>
  <div ref="colorpicker" class="color-picker-outer">
    <span
      class="color-picker-inner"
      :style=" 'background-color': colorValue"
      @click="togglePicker"
    ></span>
    Child init: initColor
    Child color: colorValue
    <chrome-picker :value="colors" @input="updateFromPicker" v-if="displayPicker"/>
  </div>
</template>

<script>
import  Chrome  from "vue-color";

export default 
  props: 
    fieldName: String,
    initColor: String
  ,
  components: 
    "chrome-picker": Chrome
  ,
  data() 
    return 
      colors: 
        hex: "#000000"
      ,
      colorValue: this.initColor,
      displayPicker: false
    ;
  ,
  mounted() 
    // actually there's no such as 'this.color'
    // in this template
    // this.setColor(this.color || "#3121e0");
  ,
  methods: 
    setColor(color) 
      this.updateColors(color);
      this.colorValue = color;
    ,
    updateColors(color) 
      if (color.slice(0, 1) === "#") 
        this.colors = 
          hex: color
        ;
       else if (color.slice(0, 4) === "rgba") 
        var rgba = color.replace(/^rgba?\(|\s+|\)$/g, "").split(","),
          hex =
            "#" +
            (
              (1 << 24) +
              (parseInt(rgba[0], 10) << 16) +
              (parseInt(rgba[1], 10) << 8) +
              parseInt(rgba[2], 10)
            )
              .toString(16)
              .slice(1);
        this.colors = 
          hex: hex,
          a: rgba[3]
        ;
      
    ,
    showPicker() 
      document.addEventListener("click", this.documentClick);
      this.displayPicker = true;
    ,
    hidePicker() 
      document.removeEventListener("click", this.documentClick);
      this.displayPicker = false;
    ,
    togglePicker() 
      this.displayPicker ? this.hidePicker() : this.showPicker();
    ,
    updateFromInput() 
      this.updateColors(this.colorValue);
    ,
    updateFromPicker(color) 
      this.colors = color;
      if (color.rgba.a === 1) 
        this.colorValue = color.hex;
       else 
        this.colorValue =
          "rgba(" +
          color.rgba.r +
          ", " +
          color.rgba.g +
          ", " +
          color.rgba.b +
          ", " +
          color.rgba.a +
          ")";
      
    ,
    documentClick(e) 
      var el = this.$refs.colorpicker,
        target = e.target;
      if (el !== target && !el.contains(target)) 
        this.hidePicker();
      
      this.$emit("update-color", this.colorValue, this.fieldName);
    
  ,
  watch: 
    initColor: function(newVal, oldVal) 
      console.log(newVal);
      this.colorValue = newVal;
    
  
;
</script>

<style scoped>
div.color-picker-outer 
  width: 55px;
  height: 50px;
  display: inline-block;
  background-color: #EEE;
  position: relative;


.color-picker-inner 
  width: 30px;
  height: 30px;
  position: relative;
  top: 10px;
  left: 13px;
  display: inline-block;


.vc-chrome 
  position: absolute;
  top: 0px;
  left: 55px;
  z-index: 9;

</style>

另一个模板:

// TenantTemplateEdit.vue

<template>
  <v-layout row>
    <v-flex xs4>
      <v-text-field
        v-bind:field-name="fields.alertBackgroundColor"
        v-model="templateModel.alertBackgroundColor"
        placeholder="#4A4A4A"
      />
      Parent: templateModel.alertBackgroundColor
    </v-flex>
    <v-flex xs2>
      <ColorPickerButton
        v-bind:field-name="'alertBackgroundColor'"
        v-bind:init-color="templateModel.alertBackgroundColor"
        v-on:update-color="getUpdatedColor"
      ></ColorPickerButton>
    </v-flex>
    <!-- Alert Text Color -->
    <v-flex xs4>
      <v-text-field
        v-bind:field-name="fields.alertTextColor"
        v-model="templateModel.alertTextColor"
        placeholder="#4A4A4A"
      />
    </v-flex>
    <v-flex xs2>
      <ColorPickerButton
        v-bind:field-name="'alertTextColor'"
        v-bind:init-color="templateModel.alertTextColor"
        v-on:update-color="getUpdatedColor"
      ></ColorPickerButton>
    </v-flex>
  </v-layout>
</template>
<script>
import ColorPickerButton from "./ColorPickerButton";
export default 
  components: 
    ColorPickerButton
  ,
  data() 
    return 
      fields: 
        alertBackgroundColor: "#00ff00",
        alertTextColor: "#ff0000"
      ,
      templateModel: 
        alertBackgroundColor: "#00ff00",
        alertTextColor: "#ff0000"
      
    ;
  ,
  methods: 
    getUpdatedColor(colorValue, fieldName) 
      this.fields[fieldName] = colorValue;
      this.templateModel[fieldName] = colorValue;
    
  
;
</script>

编辑

我更新了沙箱(以及 SO 上的代码)以在输入字段中工作。我认为它做了它应该做的一切。

【讨论】:

完美!我用你的代码修复了我的代码,它运行良好。感谢您花时间这样做。 我很高兴能帮上忙

以上是关于Vuejs 子组件中的道具值无法绑定到元素属性的主要内容,如果未能解决你的问题,请参考以下文章

更改 vuejs2 中的道具值

VueJS - 绑定自定义道具不适用于 b-form 组件

Vuejs 2将道具对象传递给子组件并检索

vuejs 计算属性 - 何时触发更新?

如何在Vuejs中将反应性道具传递给孩子

在 vuejs 中用户单击时更新发送到子组件的值