使用Svelte响应性实现的计算器功能

huangapple go评论55阅读模式
英文:

Calculator functionality using svelte reactivity

问题

It seems like you're having trouble with your Svelte project involving a calculator functionality. You've shared your Svelte components and code snippets, but it's not entirely clear what specific issue you're facing. If you have a specific question or problem you'd like assistance with, please provide more details or clarify the issue you're encountering, and I'll do my best to help you.

英文:

I'm trying to implement calculator functionality using mathjs library and Svelte. But i cant seem to make the buttons show their value on the display. Im using the input element so that physical and phone keyboards can work. For the result I used the output element.

This works:
Simple example REPL

This does not:

App.svelte


    <script>
  import Display from "./components/Display.svelte"
  
  
</script>

<main class="container">
  <Display />
</main>

<style>
</style>

Display.svelte

<!-- Svelte -->
<script>
import { evaluate } from 'mathjs'
import Button from "./Button.svelte"
let total = 0
let numberInput = ''
// private function
function addToInput(value) {
numberInput += value
}
const clear = () => {
total = 0
numberInput = ""
}
function calculate() {
if (numberInput !== "") {
numberInput = result().toString()
}
}
function replaceAll(string, search, replace) {
return string.split(search).join(replace);
}
function formatString(value) {
return replaceAll(replaceAll(value, "*", "x"), "/", "÷");
}
// computed
let result = () => {
if (!isNaN(numberInput.slice(-1))) {
return evaluate(numberInput)
}
return evaluate(numberInput.slice(0, -1))
}
// function addToInput(value){
//   prompt(value)
//   console.log(value)
//   numberInput += value
// }
$: if (
numberInput !== "" &&
!isNaN(numberInput.slice(-1)) &&
numberInput != result()
) {
total = result().toString();
}
</script>
<div class="wrapper">
<div class="screen-display">
<!-- type="number"
class=""
placeholder={numberInput}
value={numberInput} -->
<input id="arithmetic" bind:value={numberInput} />
<output name="result" for="arithmetic" placeholder="Results">{total}</output>
</div>
</div>
<div class="container numpad">
<Button setting><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3" />
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" />
</svg></Button>
<Button gray="true">FACT</Button>
<Button gray="true" on:click={()=> addToInput('^')}>a<sup style="margin-inline-start: .2em">b</sup></Button>
<Button on:click={()=> addToInput('7')}>7</Button>
<Button on:click={()=> addToInput('8')}>8</Button>
<Button on:click={()=> addToInput('9')}>9</Button>
<Button on:click={()=> addToInput('/')} >÷</Button>
<Button orange="true">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 4H8l-7 8 7 8h13a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2z" />
<line x1="18" y1="9" x2="12" y2="15" />
<line x1="12" y1="9" x2="18" y2="15" />
</svg>
</Button>
<Button dark="false" orange="true">AC</Button>
<Button gray="true">M+</Button>
<Button gray="true">M−</Button>
<Button gray="true"><svg id="ei4kL3yKbWI1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 300 300" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" style="background-color:transparent; transform: translateY(-8px);">
<rect width="30" height="30" rx="0" ry="0" transform="translate(136.15 105)" fill="#fff" stroke-width="0" />
<rect width="30" height="30" rx="0" ry="0" transform="translate(136.149972 154.448797)" fill="#fff" stroke-width="0" />
<line x1="-15" y1="0" x2="35" y2="0" transform="translate(141 144)" fill="#fff" stroke="#fff" stroke-width="3" />
</svg></Button>
<Button on:click={()=> addToInput('4')}>4</Button>
<Button on:click={()=> addToInput('5')}>5</Button>
<Button on:click={()=> addToInput('6')}>6</Button>
<Button on:click={()=> addToInput('*')}>×</Button>
<Button gray="true">←</Button>
<Button gray="true">→</Button>
<Button gray="true">MR</Button>
<Button gray="true">MC</Button>
<Button gray="true" on:click={()=> addToInput('√')}>√</Button>
<Button on:click={()=> addToInput('1')}>1</Button>
<Button on:click={()=> addToInput('2')}>2</Button>
<Button on:click={()=> addToInput('3')}>3</Button>
<Button on:click={()=> addToInput('4')}>−</Button>
<Button gray="true">Exp</Button>
<Button gray="true">Ans</Button>
<Button gray="true">S⇋D</Button>
<Button gray="true" on:click={()=> addToInput('(')}>(</Button>
<Button gray="true" on:click={()=> addToInput(')')}>)</Button>
<Button on:click={()=> addToInput('%')}>%</Button>
<Button on:click={()=> addToInput('0')}>0</Button>
<Button on:click={()=> addToInput('.')}>⋅</Button>
<Button on:click={()=> addToInput('+')}>+</Button>
<Button gray="true" largeBtn="true">=</Button>
</div>
<style>
.numpad {
display: grid;
grid-template-columns: repeat(9, var(--width));
grid-template-rows: repeat(4, var(--height));
gap: 1.3rem 1rem;
margin: 0;
max-width: 100%;
}
.wrapper {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
font-size: 2.7rem;
margin-block-end: 1.8rem;
}
::selection {
color: lch(89.4 5.7 194);
background-color: #000000;
}
.screen-display {
width: 100%;
min-height: 40vh;
outline: none;
border: none;
border-radius: 12px;
background-color: lch(89.4 5.7 194);
display: flex;
flex-direction: column;
/* align-items: center; */
justify-content: space-between;
gap: 1.2rem;
}
.wrapper {}
#arithmetic {
font-size: 3.2rem;
background: transparent;
border: 0;
outline: 0;
align-self: flex-start;
margin-inline-start: 1.8em;
margin-block-start: 0.8em;
}
output {
all: unset;
justify-self: flex-end;
align-self: flex-end;
margin-inline-end: 1.8em;
margn-block-end: 0.8em;
}
</style>

Button.svelte

    <script>
import Button from './Button.svelte'
export let isdisabled = false
export let dark = true
export let orange = false
export let gray = false
export let setting = false
export let largeBtn = false
</script>
<button type="button" disabled={isdisabled} aria-label="button" class:dark class:orange class:setting class:gray class:largeBtn value>
<slot />
</button>
<style lang="scss">
button {
all: unset;
--dropshadow: lch(3.5 1.2 302);
cursor: pointer;
font-size: 2.2rem;
font-weight: 500;
border-radius: var(--border-radius);
filter: drop-shadow(1px 1px 2px var(--dropshadow));
width: var(--width);
height: var(--height);
text-align: center;
color: var(--btn-clr);
background-color: var(--btn-bg);
border-top: 1.5px solid var(--btn-top);
margin-block-end: 2rem;
margin-inline-end: 1.8rem;
transition: all;
&:hover,
&:focus {
transform: translateY(3px);
}
}
.dark {
background-color: var(--btn-dark-bg);
color: var(--btn-dark-clr);
border-top: 1.5px solid var(--btn-dark-top);
&:hover,
&:focus {
background-color: var(--btn-dark-bg-hov);
}
}
.orange {
background-color: var(--btn-orange-bg);
color: var(--btn-orange-clr);
border-top: 1px solid var(--btn-orange-top);
/* filter: drop-shadow(1px 1px 3px lch(28.9 25.4 47)); */
&:hover,
&:focus {
background-color: var(--btn-orange-bg-hov);
}
}
.gray {
background-color: var(--btn-gray-bg);
color: var(--btn-gray-clr);
border-top: 1px solid var(--btn-gray-top);
&:hover,
&:focus {
background-color: var(--btn-gray-bg-hov);
}
}
.setting {
background-color: var(--btn-setting-bg);
color: var(--btn-setting-clr);
border-top: 1px solid var(--btn-setting-top);
&:hover,
&:focus {
background-color: var(--btn-setting-bg-hov);
}
}
.largeBtn {
width: var(--large);
grid-column: span 2;
margin-inline: auto;
}
</style>

I would be grateful for any input (pun intended).:svelte:
Here is the Live Website

I expected the button values to appear ont the input and the output reactively gives the expression evaluation. At first i had the numpad and display in different components and used createEventDispatcher to set up a custom event to keep track of the input in the screen display. I tried appending with += but it made no difference. ChatGPT was not hepful.

答案1

得分: 0

The <button> element inside the component needs an on:click without handler

Button.svelte
<button type="button" disabled={isdisabled} aria-label="button" ... on:click >
  <slot />
</button>

so that listening on the component works

<Button on:click={()=> addToInput('4')}>4</Button>
英文:

The <button> element inside the component needs an on:click without handler

Button.svelte
<button type="button" disabled={isdisabled} aria-label="button" ... on:click >
<slot />
</button>

so that listening on the component works

<Button on:click={()=> addToInput('4')}>4</Button>

huangapple
  • 本文由 发表于 2023年6月8日 23:03:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76433219.html
  • svelte
  • svelte-component
  • sveltekit

我可以将 “ :?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定