Vue 组合 API 中的只读目标
Posted
技术标签:
【中文标题】Vue 组合 API 中的只读目标【英文标题】:Readonly target in Vue composition API 【发布时间】:2021-04-06 21:16:34 【问题描述】:我的“Generateur”组件正在向我的“Visionneuse”组件发送道具。在浏览器中一切正常,但我在控制台中有此消息:
Set operation on key "texteEnvoye" failed: target is readonly.
我真的不知道为什么会收到此消息,因为我将 prop 传递给了 ref。 这是我的组件: “发电机”
<template>
<div>
<h1>Génération d'une carte de voeux</h1>
<div class="board">
<Visionneuse :texteEnvoye="texte" :taille="0.5"/>
</div>
<textarea
:style="'width: 60%; resize:none;height: 100px;'"
v-model="texte"
placeholder="Écrivez votre texte ici">
</textarea>
</div>
<div>
<button
v-if="lien.length == 0"
id="boutonObtenirLien"
v-bind:class=" enCours: lienEnCours "
class="btn first"
@click="obtenirLien">Obtenir le lien</button>
<p
v-if="lien.length > 0">
Votre carte de voeux est accessible au lien suivant:<br/>
<a :href="lien"> lien </a>
</p>
</div>
</template>
<script>
import Visionneuse from '@/components/Visionneuse.vue';
import axios from 'axios';
import
defineComponent, ref,
from 'vue';
export default defineComponent(
name: 'Générateur',
components:
Visionneuse,
,
setup()
const texte = ref('');
const lienEnCours = ref(false);
const lien = ref('');
function obtenirLien()
if (lienEnCours.value)
console.log('Je suis déjà en train de chercher!');
return false;
lienEnCours.value = true;
axios.post(`$process.env.VUE_APP_API_URL/textes/creer/`,
texte: texte.value,
,
headers:
'Content-Type': 'application/json',
,
)
.then((response) =>
console.log(response.data);
lien.value = `$process.env.VUE_APP_URL/carte/$response.data`;
)
.catch((error) =>
console.log(error);
)
.then(() =>
lienEnCours.value = false;
);
return true;
return
texte,
obtenirLien,
lienEnCours,
lien,
;
,
);
</script>
还有“幻视者”
<template>
<div class="board">
<canvas
ref='carte'
:
:
tabindex='0'
style="border:1px solid #000000;"
></canvas>
</div>
<div id="texteRemplacement" v-if="petit">
<p v-for="p in texte.split('\n')" v-bind:key="p">
p
</p>
</div>
</template>
<script>
import
defineComponent, onMounted, ref, reactive, nextTick, toRefs, watch,
from 'vue';
export default defineComponent(
name: 'Visionneuse',
props: ['texteEnvoye', 'taille'],
setup(props)
const myCanvas = ref(null);
const carte = ref(null);
const texteEnvoye: texte, taille = toRefs(props);
const rapport = ref(0);
const petit = ref((window.innerWidth < 750));
const size = reactive(
w: window.innerWidth * taille.value,
h: window.innerWidth * taille.value,
);
function drawText()
const fontSize = 0.05 * size.w - 10;
myCanvas.value.font = `$fontSizepx Adrip`;
myCanvas.value.textAlign = 'center';
myCanvas.value.fillStyle = 'lightgrey';
myCanvas.value.strokeStyle = 'black';
myCanvas.value.lineWidth = 0.006 * size.w - 10;
const x = size.w / 2;
const lineHeight = fontSize;
const lines = texte.value.split('\n');
for (let i = 0; i < lines.length; i += 1)
myCanvas.value.fillText(
lines[lines.length - i - 1],
x,
(size.h * 0.98) - (i * lineHeight),
);
myCanvas.value.strokeText(
lines[lines.length - i - 1],
x,
(size.h * 0.98) - (i * lineHeight),
);
function initCarte()
const background = new Image();
background.src = '/img/fond.jpeg';
background.onload = function ()
rapport.value = background.naturalWidth / background.naturalHeight;
size.h = size.w / rapport.value;
nextTick(() =>
try
myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
catch (e)
console.log(`ERREUR DE CHARGEMENT D'IMAGE: $e`);
if (!petit.value)
drawText();
);
;
function handleResize()
size.w = window.innerWidth * taille.value;
size.h = size.w / rapport.value;
petit.value = window.innerWidth < 750;
initCarte();
window.addEventListener('resize', handleResize);
watch(texte, (_, y) =>
texte.value = y;
initCarte();
);
onMounted(() =>
const c = carte.value;
const ctx = c.getContext('2d');
myCanvas.value = ctx;
initCarte();
);
return
myCanvas,
size,
texte,
petit,
carte,
;
,
);
</script>
【问题讨论】:
【参考方案1】:好的,我找到了解决方案。我将“texteEnvoye”和“texte”分开,一切正常。我不知道这是否是在组合 API 中编写代码的好方法,但它成功了:
<template>
<div class="board">
<canvas
ref='carte'
:
:
tabindex='0'
style="border:1px solid #000000;"
></canvas>
</div>
<div id="texteRemplacement" v-if="petit">
<p v-for="p in texte.split('\n')" v-bind:key="p">
p
</p>
</div>
</template>
<script>
import
defineComponent, onMounted, ref, reactive, nextTick, toRefs, watch,
from 'vue';
export default defineComponent(
name: 'Visionneuse',
props: ['texteEnvoye', 'taille'],
setup(props)
const myCanvas = ref(null);
const carte = ref(null);
const texteEnvoye, taille = toRefs(props);
const texte = ref('');
const rapport = ref(0);
const petit = ref((window.innerWidth < 750));
const size = reactive(
w: window.innerWidth * taille.value,
h: window.innerWidth * taille.value,
);
function drawText()
const fontSize = 0.05 * size.w - 10;
myCanvas.value.font = `$fontSizepx Adrip`;
myCanvas.value.textAlign = 'center';
myCanvas.value.fillStyle = 'lightgrey';
myCanvas.value.strokeStyle = 'black';
myCanvas.value.lineWidth = 0.006 * size.w - 10;
const x = size.w / 2;
const lineHeight = fontSize;
const lines = texte.value.split('\n');
for (let i = 0; i < lines.length; i += 1)
myCanvas.value.fillText(
lines[lines.length - i - 1],
x,
(size.h * 0.98) - (i * lineHeight),
);
myCanvas.value.strokeText(
lines[lines.length - i - 1],
x,
(size.h * 0.98) - (i * lineHeight),
);
function initCarte()
const background = new Image();
background.src = '/img/fond.jpeg';
background.onload = function ()
rapport.value = background.naturalWidth / background.naturalHeight;
size.h = size.w / rapport.value;
nextTick(() =>
try
myCanvas.value.drawImage(background, 0, 0, size.w, size.h);
catch (e)
console.log(`ERREUR DE CHARGEMENT D'IMAGE: $e`);
if (!petit.value)
drawText();
);
;
function handleResize()
size.w = window.innerWidth * taille.value;
size.h = size.w / rapport.value;
petit.value = window.innerWidth < 750;
initCarte();
window.addEventListener('resize', handleResize);
watch(texteEnvoye, (x) =>
texte.value = x;
initCarte();
);
onMounted(() =>
const c = carte.value;
const ctx = c.getContext('2d');
myCanvas.value = ctx;
initCarte();
);
return
myCanvas,
size,
texte,
petit,
carte,
;
,
);
</script>
【讨论】:
以上是关于Vue 组合 API 中的只读目标的主要内容,如果未能解决你的问题,请参考以下文章
Vue3中 响应式 API ( readonlyshallowReadonlytoRawmarkRaw ) 详解
Vue导入导致无法分配给对象错误的只读属性'exports'
删除文件夹中的只读权限,以便在目标文件夹中上载文件(php)
Vue3中 响应式 API ( readonlyshallowReadonlytoRawmarkRaw ) 详解