Vuejs子组件中的属性值无法绑定到元素属性 [英] Prop value in Vuejs child component not available to bind to element attribute

查看:560
本文介绍了Vuejs子组件中的属性值无法绑定到元素属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Vuetify在Vuejs中开发一个管理应用程序,并且在表单中有三个字段供用户选择十六进制颜色值。为了使用户更容易,我基于此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>
从{vue-color'导入{Chrome}

导出默认值{
道具:{
fieldName:字符串,
initColor:字符串
},
组件:{
'chrome-picker':Chrome
},
data(){
return {
颜色:{
hex:'#000000',
},
colorValue:this.initColor,
displayPicker:false,
}
},已安装
){
this.setColor(this.color ||'#3121e0');
},
方法:{
setColor(color){
this.updateColors(color);
this.colorValue = color;
},
updateColors(color){
if(color.slice(0,1)=='#'){
this.colors = {
十六进制: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)
}
},
手表:{
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;
高度:50像素;
显示:inline-block;
background-color:#EEE;
职位:相对;
}

.color-picker-inner {
width:30px;
高度:30像素;
职位:相对;
top:10像素;
左:13px;
显示:inline-block;
}

.vc-chrome {
position:absolute;
top:0像素;
左:55px;
z-index:9;
}
< / style>

这就是我从父 TenantTemplateEdit.vue调用的方式

 < v-layout row> 
< v-flex xs4>
< v文本字段
v-bind = fields.alertBackgroundColor
v-model = templateModel.alertBackgroundColor
占位符=#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>
<!-警告文本颜色->
< v-flex xs4>
< v文本字段
v-bind = fields.alertTextColor
v-model = templateModel.alertTextColor
占位符=#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>

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



要获得<$ c $,我需要更改什么c> background-color 是在初始加载时设置的吗?

解决方案

如果您纠正了一些错字等(例如 string 而不是 String v-bind 中没有参数,请清除



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



https://codesandbox.io/s/p9620jzoy7



我希望我正确理解了您的问题,此代码段对您有所帮助。



我粘贴了代码在这里(公司de已编辑,因此可以在沙盒环境中使用):

  // ColorPickerButton.vue 

<模板>
< div ref = colorpicker class = color-picker-outer>
< span
class = color-picker-inner
:style = {'background-color':colorValue}
@ click = togglePicker
>< / span>
子级初始化:{{initColor}}
子级颜色:{{colorValue}}
< chrome-picker:value = colors @ input = updateFromPicker v-if = displayPicker />
< / div>
< / template>

< script>
从 vue-color导入{Chrome};

导出默认值{
道具:{
fieldName:字符串,
initColor:字符串
},
分量:{
chrome-picker:Chrome
},
data(){
return {
颜色:{
十六进制:#000000
},
colorValue:this.initColor,
displayPicker:false
};
},
mount(){
//实际上没有这样的东西'this.color'
//在模板中
// this.setColor(this .color ||#3121e0);
},
方法:{
setColor(color){
this.updateColors(color);
this.colorValue = color;
},
updateColors(color){
if(color.slice(0,1)===#){
this.colors = {
十六进制:color
};
}否则if(color.slice(0,4)=== rgba){
var rgba = color.replace(/ ^ rgba?\(| \s + | \) $ / g,).split(,),
十六进制=
# +

(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;
}否则{
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);
}
},
手表:{
initColor:function(newVal,oldVal){
console.log(newVal);
this.colorValue = newVal;
}
}
};
< / script>

< style scoped>
div.color-picker-outer {
width:55px;
高度:50像素;
显示:inline-block;
background-color:#EEE;
职位:相对;
}

.color-picker-inner {
width:30px;
高度:30像素;
职位:相对;
top:10像素;
左:13px;
显示:inline-block;
}

.vc-chrome {
position:absolute;
top:0像素;
左:55px;
z-index:9;
}
< / style>

另一个模板:

  // TenantTemplateEdit.vue 

< template>
< v-layout行>
< v-flex xs4>
< v文本字段
v-bind:field-name = fields.alertBackgroundColor
v-model = templateModel.alertBackgroundColor
placeholder =#4A4A4A
/>
父级:{{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>
<!-警告文本颜色->
< v-flex xs4>
< v文本字段
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>
从 ./ColorPickerButton导入ColorPickerButton;
导出默认值{
组件:{
ColorPickerButton
},
data(){
return {
字段:{
alertBackgroundColor:#00ff00,
alertTextColor:#ff0000
},
templateModel:{
alertBackgroundColor:#00ff00,
alertTextColor:#ff0000
}
};
},
方法:{
getUpdatedColor(colorValue,fieldName){
this.fields [fieldName] = colorValue;
this.templateModel [fieldName] = colorValue;
}
}
};
< / script>

编辑



<我更新了沙箱(以及SO上的代码)以从输入字段开始工作。我认为它可以完成应有的功能。


I am working on an admin app in Vuejs with Vuetify, and I have three fields in a form for a user to select a hex color value. To make it easier for the user, I have implemented a color picker based off of this codepen.

Here is the ColorPickerButton component:

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

and here is how I call it from the parent TenantTemplateEdit.vue component.

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

The issue I'm struggling with is setting the initial color for the span.color-picker-inner element when the data is changed. and the ColorPickerButton component is called from TenantTemplateEdit. I have verified that the initColor prop is being properly passed and is available in ColorPickerButton, but what I have is not getting to my background-color attribute in the template.

What do I need to change to get background-color set on initial load?

解决方案

If you correct some typos and such (like string instead of String, no parameters at v-bind, clearing out the mounted() hook in the picker template) in the code, it should work.

Here's a working example (the inner color changes as you pick a new color, and it's set on initial load):

https://codesandbox.io/s/p9620jzoy7

I hope I correctly understood your problem and this snippet helps.

I paste the code here (the code is edited so it can be used in a sandbox environment):

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

The other template:

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

EDIT

I updated the sandbox (and the code here on SO) to work from the input field. I think it does everything it's supposed to do.

这篇关于Vuejs子组件中的属性值无法绑定到元素属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆