onMount 生命周期
引用一段官方的话:
Solid 中只有少量的生命周期,因为一切的存活销毁都由响应系统控制。响应系统是同步创建和更新的,因此唯一的调度就是将逻辑写到更新结束的 Effect 中。
举个🌰
import { render } from "solid-js/web"; import { createSignal, onMount, For } from "solid-js"; function App() { const [photos, setPhotos] = createSignal([]); onMount(async () => { const res = await fetch( `https://jsonplaceholder.typicode.com/photos?_limit=20` ); setPhotos(await res.json()); }); return ( <> <h1>photos</h1> <div class="photos"> <For each={photos()} fallback={<p>Loading</p>}> {(photo, i) => ( <figure> <img src={photo.thumbnailUrl} alt={photo.title} /> <figcaption>{photo.title}</figcaption> </figure> )} </For> </div> </> ); } render(() => <App />, document.getElementById("app")); 复制代码
onCleanup
onCleanup
函数可以执行一些销毁操作,举个栗子
import { render } from "solid-js/web"; import { createSignal, onCleanup } from "solid-js"; function Counter() { const [count, setCount] = createSignal(0); const timer = setInterval(() => setCount(count() + 1), 1000); onCleanup(() => clearInterval(timer)); return <div>Count: {count()}</div>; } render(() => <Counter />, document.getElementById("app")); 复制代码
事件
在SolidJs中,事件均以on
为前缀,举个🌰
import { render } from "solid-js/web"; import { createSignal } from "solid-js"; import "./style.css"; function App() { const [pos, setPos] = createSignal({ x: 0, y: 0 }); function handleMouseMove(event) { setPos({ x: event.clientX, y: event.clientY, }); } return ( <div onmousemove={handleMouseMove}> The mouse position is {pos().x} x {pos().y} </div> ); } render(() => <App />, document.getElementById("app")); 复制代码
动态样式 Style
SolidJs中的style
属性接受样式字符串和对象,但需要注意一点,官话:
对象形式不同于
Element.prototype.style
,Solid 通过调用style.setProperty
的封装来进行样式设置。
意味着样式的键需要采用中划线的方式,例如background-color
而不是backgroundColor
,但是这意味着可以设置CSS变量:
<div style={{'--my-custom-color': themeColor()}}></div> 复制代码
举个🌰
import { render } from "solid-js/web"; import { createSignal } from "solid-js"; function App() { const [num, setNum] = createSignal(0); setInterval(() => setNum((num() + 1) % 255), 30) return <div style={{ color: `rgb(${num()}, 180, ${num()})`, 'font-size': `${num()}px` }}>Some Text</div>; } render(() => <App />, document.getElementById('app')); 复制代码
动态类名 ClassList
SolidJs支持使用 class
和className
设置元素的classname属性,classList
用来设置多个class名,key是类名,value是一个boolean,举个🌰
function App() { const [current, setCurrent] = createSignal('foo') return <> <button class={current() === 'foo' ? 'selected' : ''} onClick={setCurrent('foo')}>foo</button> <button class={current() === 'bar' ? 'selected' : ''} onClick={setCurrent('bar')}>bar</button> <button class={current() === 'baz' ? 'selected' : ''} onClick={setCurrent('bar')}>baz</button> </> } 复制代码
当然上面的代码也可以用classList
,🌰:
<button classList={{'selected': current() === 'foo'}} onClick={setCurrent('foo')}>foo</button> 复制代码
Ref
SolidJs中,可以通过ref
属性获取元素的引用,官话:
赋值行为是在元素创建时,在 DOM 被追加前发生的。 只需声明一个变量,元素引用就会赋值给该变量。
举个🌰
let myDiv; <div ref={myDiv}>my Div</div> 复制代码
就可以了...
属性绑定/扩展
利用...
扩展运算符,可以直接把属性传进子组件,举个🌰
main.tsx
import { render } from "solid-js/web"; import Info from "./info"; const pkg = { name: "dog", age: 3, gender: 0, }; function App() { return <Info name={pkg.name} age={pkg.age} gender={pkg.gender}></Info>; } render(() => <App />, document.getElementById("app")); 复制代码
info.tsx
export default function Info(props) { console.log(props) return ( <div> <p>name: {props.name}</p> <p>age: {props.age}</p> <p>gender: {props.gender === 0 ? "girl" : "boy"}</p> </div> ); } 复制代码
上面的main.tsx
可以这样改造一下:
function App() { return <Info {...pkg}></Info>; } 复制代码
是不是省了很多事儿!
指令
SolidJs可以通过use
自定义指令,自定义指令仅仅只是一个形式为(element, valueAccesor)
的函数,其中valueAccesor
是一个获取绑定值的函数,只要函数是在作用域中导入的,就可以通过use:
使用。
重要提示:
use:
需要被编译器检测并进行转换,并且函数需要在作用域内,因此不能作为传值的一部分或在组件上使用。
举一个modal的🌰:
main.tsx
import { render } from "solid-js/web"; import { createSignal, Show } from "solid-js"; import clickOutside from './click-outside' function App() { const [show, setShow] = createSignal(false) return ( <Show when={show()} fallback={<button onClick={setShow(true)}>show Modal</button>}> <div class="modal" use:clickOutside={show(false)}>modal box</modal> </Show> ) } render(() => <App />, document.getElementById("app")); 复制代码
click-outside.tsx
import { onCleanup } from 'solid-js'; export default function clickOutside(el, accessor) { const onClick = (e) => !el.contains(e.target) && accessor()?.(); document.body.addEventListener('click', onClick) onCleanup(() => document.removeEventListener('click', onClick)) } 复制代码
props
SolidJs中的props传值上面已经有🌰了,很简单,再举个🌰
main.tsx
import WelcomeWord from './welcomeWord' function App() { reutrn ( <> <WelcomeWord gretting="Hi" name="Bob"></WelcomeWord> </> ) } 复制代码
welcomeWord.tsx
export default function welcomeWord(props) { return <h1>{props.gretting || 'hello'} {props.name || 'Alice'}</h1> } 复制代码
props赋值默认值通过mergeProps
操作,上面的🌰就可以改成这样
welcomeWord.tsx
import { mergeProps } from 'solid-js' export default function welcomeWord(props) { const merged = mergeProps({ greeting: 'hello', name: 'Alice' }, props) return <h1>{merged.greeting} {merged.name} </h1> } 复制代码
就很完美,官话:
Solid 有一些工具函数可以帮助我们处理 props。 第一个
mergeProps
函数听起来很像它名字描述得那样合并 props。mergeProps
将潜在的响应式对象合并而不会失去响应式性。最常见的情况就是是为组件设置默认 props。
props分离
在SolidJs中解构一个props会失去数据的响应性,可以通过splitProps
来分离一个props,举个🌰
main.tsx
import { render } from "solid-js/web"; import { createSignal } from "solid-js"; import Greeting from "./greeting"; function app() { const [name, setName] = createSignal("Jack") return <> <Greeting greeting="Yo" name={name()} style="color: teal;" /> <button onClick={setName("Alice")}>set name</button> </> } render(() => <App />, document.getElementById('app')); 复制代码
greeting.tsx
export default function Greeting(props) { let { greeting, name, ...others } = props return <h3 {...others}>{greeting} {name}</h3> } 复制代码
这种方式修改name
的时候,发现子组件并没有修改,所以需要使用splitProps
import { splitProps } from "solid-js"; export default function Greeting(props) { const [local, others] = splitProps(props, ["greeting", "name", "age"]); console.log(local, others) return ( <h3 {...others}> {local.greeting} {local.name} {local.age} </h3> ); } 复制代码
就很完美!