尝一尝美味的svelte

759 阅读4分钟

Svelte来历

Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。 与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。

相对于目前主流框架而言,这是一种新奇的思路:用编译代替Runtime实现同样的效果,有种前端框架界的LLVM的感觉。

作者Rich Harris 明说,Svelte速度上吊打目前所有前端框架,快出几个数量级。 祭出 Svelte全家桶。

行胜于言,下面将三步入手Svelte

目标:用Svelte写一个聊天页

第一步,安装 Svelte 并让它跑起来

npx degit sveltejs/template svelte-app
cd svelte-app
npm install
npm run dev

第二步,编写组件

编写组件之前康一康项目架构。

依旧是熟悉的组件拆分。

APP组件(首页)

App.svelte

  • import进组件进行使用,通过props进行传值与函数给子组件
  • 值得注意的是,Svelte是观测不了数组变化的,所以绑定不了数组。每次更新组件上的数组值可以通过解构的方式实现。
  • 直接使用npm 引入 axios进行http请求,与其他框架做法无差别
  • HTML无需标签包裹,脚本和样式需要包裹
<script>
  import http from "axios";
  import Header from "./Header.svelte";
  import InputBottom from "./InputBottom.svelte";
  import List from "./List.svelte";

  let listData = [];

  const answer = value => {
    http
      .get(`//127.0.0.1:9000?question=${value}`)
      .then(function(response) {
        console.log(response);
        const data = {
          class: "message1",
          info: response.data.msg
        };
        listData = [...listData, data];
        const scroll = setInterval(() => {
		  window.scrollTo(0, document.body.scrollHeight);
		  clearInterval(scroll)
		}, 100);
      })
      .catch(function(error) {
        console.log(error);
      });
  };

  const getValue = value => {
    const data = {
      class: "message2",
      info: value
    };
    listData = [...listData, data];
    answer(value);
    console.log(listData);
    window.scrollTo(0, document.body.scrollHeight);
  };
</script>

<style>
  main {
    text-align: center;
    /* width: 100vw; */
  }
</style>

<main>
  <Header title={'AI'} />
  <List bind:data={listData} />
  <InputBottom {getValue} />
</main>

子组件1输入框InputBottom.svelte

  • props 定义,直接在变量前面加export即可定义为props
  • 通过双向绑定输入值,通过绑定父组件的点击事件将子组件的值回传到父组件
<script>
  export let getValue;
  let text = '';
</script>

<style>
  .input {
    display: flex;
    align-content: space-around;
    justify-items: center;
    padding: 4px;
    width: 100%;
    position: fixed;
    bottom: 0px;
    height: 6vh;
    background: rgb(226, 214, 214);
  }
  input {
    border: 1px white solid;
    border-radius: 3px;
    outline: none;
    width: 80%;
    height: 85%;
    margin-right: 5px;
    font-size: 20px;
  }
  span {
    height: 6vh;
    margin-right: 5px;
    width: 20%;
    padding: 8px;
    color: #ffffff;
    background-color: #1aad19;
    box-sizing: border-box;
    text-align: center;
    text-decoration: none;
    border-radius: 5px;
    -webkit-tap-highlight-color: transparent;
    overflow: hidden;
    line-height: 4vh;
  }
</style>

<div class="input">
  <input bind:value={text} />
  <span
    on:click={() => {
      text !== '' && getValue(text), (text = '');
    }}>
    发送
  </span>
</div>

组件2Header.svelte

<script>
	export let title;
</script>

<div class="header">
{title}
</div>

<style>
.header{
    position: fixed;
    top: 0px;
    z-index: 1;
    font-size: 30px;
    height: 5vh;
    width: 100%;
    line-height: 5vh;
    background:#eeeeee;
}
</style>

组件3 List.svelte

  • Svelte的循环是用使用闭合模型,写起来与PHP非常类似
<!-- open each block -->
{#each data as item}
需要循环的部分
{/each}
<!-- close each block -->
<script>
    export let data = [];
</script>

<div class="list">
   <div class="bottom-black-top"></div>
<!-- open each block -->
	{#each data as item}
        <div class="box">
            <div class="{item.class}">
                {item.info}
            </div>
        </div>
	{/each}
	<!-- close each block -->
    <div class="bottom-black-bottom"></div>
</div>

<style>

.bottom-black-top{
    width: 200px;
    height: 5vh;
    margin: 10px 50px;
}
.bottom-black-bottom{
    width: 200px;
    height: 7vh;
    margin: 10px 50px;
}

.box{
    overflow: auto
}

.message1 {
    float:left;
    width: auto;
    height: auto;
    margin: 3px 30px;
    background-color: skyblue;
    border-bottom-color: skyblue;
    /*为了给after伪元素自动继承*/
    color: #fff;
    font-size: 12px;
    line-height: 18px;
    padding: 5px 12px 5px 12px;
    box-sizing: border-box;
    border-radius: 6px;
    position: relative;
    word-break: break-all;
}

/** 通过对小正方形旋转45度解决 **/
.message1::before {
    content: '';
    position: absolute;
    top: 60%;
    left: -5px;
    width: 10px;
    height: 10px;
    margin-top: -10px;
    background: inherit;
    /*自动继承父元素的背景*/
    transform: rotate(45deg);
}

.message2 {
    display: flex;
    align-items: center;
    justify-content: space-around;
    float: right;
    width: auto;
    height: auto;
    margin: 10px 30px;
    background-color: #9EEA6A;
    border-bottom-color: #9EEA6A;
    /*为了给after伪元素自动继承*/
    color: #fff;
    font-size: 12px;
    line-height: 18px;
    padding: 5px 12px 5px 12px;
    box-sizing: border-box;
    border-radius: 6px;
    position: relative;
    word-break: break-all;
}


/** 通过对小正方形旋转45度解决 **/
.message2::before {
    content: '';
    position: absolute;
    top: 60%;
    right: -5px;
    width: 10px;
    height: 10px;
    margin-top: -10px;
    background: inherit;
    /*自动继承父元素的背景*/
    transform: rotate(45deg);
}
</style>

结果

框架bug

public的global.css在dev模式是不生效的。。所以只能把全局css放在index.html里面

编译结果

将所有资源编译成bundle(无runtime),体积小,速度快~