Svelte系列 --- 绑定

915 阅读2分钟

通常,Svelte 中的数据流是 自上而下,父组件可以在子组件上设置 props, 子组件向父组件通信,也是需要借助父组件传递给子组件的方法来完成,但是在某些情况下,需要打破这种规则,尤其是在使用表单元素来接收用户数据的时候

<script>
	let name = 'world';
</script>

<!-- 加上bind指令后 更改name的值时会更新 input 的值,反之亦然 --- 双向绑定 -->
<!-- 
	如果不使用bind指令
	需要其添加对应的事件处理程序(这里是 on:input ),
	在该程序中将 name 的值设置为 event.target.value 
	但是表单元素一般不止一个
	这么写意味着很繁琐,可以认为bind是上述操作的语法糖
-->
<input bind:value={name}>

<h1>Hello {name}!</h1>

表单元素的绑定

文本输入框 input[type=text]

<script>
  let name = 'world';
</script>

<input bind:value={name}>

<h1>Hello {name}!</h1>

数字或范围输入框 input[type=number|range]

<!-- 表单中获取的值都是字符串,一般都需要手动进行转换,但是Svelte不需要, Svelte会帮组我们进行转换 -->
<input type=number value={a} min=0 max=10>
<input type=range bind:value={a} min=0 max=10>

复选框 input[type=checkbox]

<input type=checkbox bind:checked={yes}>

输入框组 radio & checkbox

有多个输入框需要关联到同一个值的时候,则可以将bind:groupvalue属性一起使用。同一组的单选框(Radio)之间是互斥的;而同一组复选框中被选中的值会汇集到一个数组中

<!-- bind:group --- 分组 --- 同一名称为一组 值为value中对应的值 -->
<label><input type=radio bind:group={scoops} value={1}>One scoop</label>
<label><input type=radio bind:group={scoops} value={2}>Two scoops</label>
<label><input type=radio bind:group={scoops} value={3}>Three scoops</label>
<!-- 多选框组 会被绑定成一个数组 -->
<input type=checkbox bind:group={flavours} name="flavours" value="Cookies"> Cookies
<input type=checkbox bind:group={flavours} name="flavours" value="Mint"> Mint
<input type=checkbox bind:group={flavours} name="flavours" value="Raspberry"> Raspberry

多行纯文本 textarea

<textarea bind:value={value}></textarea>

<!-- 属性名和属性值同名可以简写(适用于所有的双向绑定) -->
<textarea bind:value></textarea>

选择框 select(单选)

<script>
  let questions = [
    { id: 1, text: `Where did you go to school?` },
    { id: 2, text: `What is your mother's name?` }
  ];
  
  // 如果绑定的值没有设置初始值,那么默认值就是列表中的第一项,即questions[0]
  let selected;
</script>

<!-- bind:value 是添加在select上的 -->
<select bind:value={selected} on:blur="{() => answer = ''}">
  {#each questions as question}
  <!-- 在svelte中,option上绑定的值可以是一个对象 -->
  <option value={question}>
    {question.text}
  </option>
  {/each}
</select>

<!-- 因为并没有给selected设置初始值,所以selected可能为空,所以此时需要进行判断 -->
<p>selected question {selected ? selected.id : '[waiting...]'}</p>

选择框 select(多选)

<h2>Flavours</h2>

<!-- 此时flavours是一个数组,而非一个普通的值 -->
<select multiple bind:value={flavours}>
  {#each menu as flavour}
    <option value={flavour}>{flavour}</option>
  {/each}
</select>

可编辑属性 contenteditable

<!-- 给元素加上 contenteditalbe 属性,元素即可获得可编辑能力 -->
<!-- 具有contenteditable="true"属性的元素都支持绑定textContent和innerHTML -->
<div
  contenteditable="true"
  bind:innerHTML={html}
></div>

在 each 块中绑定

<!-- 在 Svelte 中,可以在each块中绑定属性 -->
{#each todos as todo}
  <div class:done={todo.done}>
    <input type=checkbox bind:checked={todo.done}>
    <input placeholder="What needs to be done?" bind:value={todo.text}>
  </div>
{/each}

特殊的绑定

尺寸绑定

  1. 每个块级元素都可以绑定到clientWidthclientHeightoffsetWidth以及offsetHeight
  2. 这些绑定都是只读的,修改 wh 的值不会有任何效果
  3. 使用这类测量技术,会涉及到一些额外开销,因此不建议在大量元素上使用。
  4. display: inline 的内联元素是不能测量的,没有子级的元素也不能(例如 <canvas>),这种情况,你需要测量的是包裹它的外层元素。
<div bind:clientWidth={w} bind:clientHeight={h}>
  <span style="font-size: {size}px">{text}</span>
</div>

媒体相关元素 audio & video

<audio><video>元素具有一些可以绑定的属性。具体可以点击参看示例代码

this

  1. 绑定 this 与 Vue 的 ref 功能相似,都是为了取得当前组件的实际 DOM 对象
  2. this绑定适用于任意元素或组件,允许你获取渲染的元素的引用
  3. this绑定获取的值是只读的
  4. 组件 mounted 之前,所有对于DOM的操作都是无效的,对使用this获取的dom元素的操作应放在onMount这个生命周期函数中
<span bind:this={spanElem}>Hello Svelte</span>

<script>
	import { onMount } from 'svelte';
	let spanElem;
	
	onMount(() => console.log(spanElem))
</script>

组件绑定

在Svelte中,组件绑定 类似于 vue中的 .sync操作符

<!-- 父组件 -->
<script>
  let pin = ''
</script>

<!-- 使用bind:xxx 后,在父组件中,pin值一旦发生了改变,子组件的value值也会发生改变 -->
<Keypad bind:value={pin} on:submit={handleSubmit}/>

<!----------------------------------------------------------------->

<!-- 子组件 -->
<script>
	export let value = '';
  
  // 使用bind:xxx 后,在子组件中,修改了value值,父组件中的pin也会相应发生改变
  const select = num => () => value += num;
</script>

<button on:click="{select(1)}">+1</button>

组件绑定需要谨慎小心。如果你的 App 中数据过多,尤其是在没有 “单一数据源” 的情况下,

可能难以跟踪 App 相关的数据流,因此此时在子组件中修改了值,直接影响外部提供的状态

<!-- 父组件 App.svelte -->
<script>
	import Keypad from './Keypad.svelte'
  let pin = ''
	
	$: console.log('pin', pin)
</script>

<Keypad bind:value={pin} />

<!----------------------------------------------------------------->

<!-- 中间组件 Keypad.svelte -->
<script>
	export let value = ''
	import Cpn from './Cpn.svelte'
</script>

<Cpn bind:value />

<!----------------------------------------------------------------->

<!-- 子组件 Cpn.svelte -->
<script>
	export let value = '';
  
  const select = num => () => value += num;
	
	$: console.log('value', value)
</script>

<button on:click="{select(1)}">+1</button>