Svelte

# 视频教程

http://noover.leanapp.cn/courses

# 安装(Install)

npm install -g svelte-cli

# 创建一个会说你好世界的组件(HelloWorld Component)

  • 新建一个项目文件夹,新建一个 HelloWrold.html 内容如下。
<!-- HelloWrold 组件 -->
<h1>你好 {{name}}</h1>
  • 使用命令编译 html 文件
svelte compile --format iife HelloWorld.html > HelloWorld.js
  • 创建 index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Svelte Application</title>
</head>
<body>
    
    <application></application>
    
    <script src="./HelloWorld.js"></script>
    <script>
      var app = new HelloWorld({
        target: document.querySelector( 'application' ),
        data: {
          name: '世界'
        }
      });
    </script>
</body>
</html>

# 组件实例方法(Component API)

创建一个组件的实例的方法就是通过 new 调用并传入配置项

  • 要加载到的 DOM 节点上面
target: document.querySelector( 'main' )
  • 组件的初始数据
data: {
    author: {
      name: '近藤麻理惠'
      gender: 'female'
      nationality: 'Japan'
    },
    title: '怦然心动人生整理魔法'
    recommendedReason: '勤俭持家,人人有责。无论男女,统统要干。'
}

# 在我们的 HelloWorld 例子中,在你的Chrome 控制台输入以下内容

以下内容都是实例的方法,每次开始测试之前可以刷新一下,清空之前的变量。

# get

app.get('name')
// "世界"

# set

app.set({ name: '天地' })

# observe

observe 字面上的意思就是观察,在代码中的意思就是观察 name,当值改变的时候就执行回调函数。

可以看到加上观察就立马触发了回调,打印了当前 name 的值

const observer = app.observe( 'name', name => {
  console.log( `当前 name 的值是 ${name}` );
});

app.set({name:'虚空大帝'})

observer.cancel() // 取消观察

app.set({name:'皓月大帝'})

传入{ init: false } 那么第一次就不会触发

app.observe( 'name', ( newValue, oldValue ) => {
  console.log( `长度对比 ${newValue.length > oldValue.length ? 'new > old' : 'new < old'}` );
}, { init: false });

app.set({name:'宵元大帝~'})

默认所有回调会在更新前完成,传入{ defer: true } 会导致回调在组件更新完成之后调用。
这样的操作组要是跟 Dom 有关联,所以我们需要添加一点代码来验证它们。

  • HelloWorld.html
<h1>你好 {{name}}</h1>

<canvas id="canvas-container" width="{{ canvas_width }}" height="{{ canvas_height }}"></canvas>

<style type="text/css">
    #canvas-container{
        background: #7F7BFF;
    }
</style>
  • 重新编译一下
svelte compile --format iife HelloWorld.html > HelloWorld.js
  • index.html
  var app = new HelloWorld({
    target: document.querySelector( 'application' ),
    data: {
      name: '世界',
      canvas_width: '350',
      canvas_height: '150'
    }
  });

  function redraw(newValue, oldValue) {
    const canvas = document.querySelector('#canvas-container')
    console.log("Dom height " + canvas.height);
    console.log("Dom width " + canvas.width);
    console.log(newValue + "  -> " + oldValue);
  }

  app.observe('canvas_width', redraw, { init: false})
  app.observe('canvas_height', redraw, { defer : true, init: false })
  • 在控制台里面输入
app.set({ canvas_height: 20 })
app.set({ canvas_width: 20 })

# on

on 在 js 语言中通常监听某一事件,这很符合惯例

const listener = app.on( 'eat', event => {
  console.log( `${event.name} 超龄儿童,你老婆叫你回家吃晚饭了` );
});

# fire

触发某一事件

app.fire( 'eat', {
  name: 'Alex'
});
  • teardown

删除 DOM 会触发这个事件

app.on( 'teardown', () => {
  alert( '滚蛋吧 组件君!' ); 
});

app.teardown()

# HelloWorld 组件源码分析

  • NeedTodo

# 组件模板语法(Template syntax)

# 变量

使用小胡子Mustaches语法输出变量

<p>{{a}} + {{b}} = {{a + b}}</p>
<h1 style='color: {{color}};'>{{color}}</h1>

# 条件

{{#if user }}
    <div>{{ user.name }} is beautful girl!</div>
{{/if}}
{{#if x > 10}}
  <p>{{x}} 大于 10</p>
{{elseif 5 > x}}
  <p>{{x}} 小于 5</p>
{{else}}
  <p>{{x}} 在 5 与 10 之间</p>
{{/if}}

# 循环

<h1>水果大家庭</h1>

<ul>
  {{#each fruits as fruit}}
    <li>{{fruit}}</li>
  {{/each}}
</ul>
fruits: ['苹果','梨','香蕉','葡萄','橘子','菩提','火龙果','荔枝']

# 指令

<p>Count: {{count}}</p>
<button on:click='set({ count: count + 1 })'>+1</button>

# 组件样式(Style)

<canvas id="canvas-container" width="{{ canvas_width }}" height="{{ canvas_height }}"></canvas>


<style type="text/css">
    #canvas-container{
        background: #7F7BFF;
    }
</style>

# 组件行为(Script)

# 组件属性

<p>Count: {{count}}</p>
<button on:click='set({ count: count + 1 })'>+1</button>

<script>
  export default {
    data () {
      return {
        count: 0
      };
    }
  };
</script>

# 计算属性

<p>
  The time is
  <strong>{{hours}}:{{minutes}}:{{seconds}}</strong>
</p>

<script>
  export default {
    data () {
      return {
        time: new Date()
      };
    },

    computed: {
      hours: time => time.getHours(),
      minutes: time => time.getMinutes(),
      seconds: time => time.getSeconds()
    }
  };
</script>

# 生命周期

<script>
  export default {
    onrender () {
      this.interval = setInterval( () => {
        this.set({ time: new Date() });
      }, 1000 );
    },

    onteardown () {
      clearInterval( this.interval );
    },

    data () {
      return {
        time: new Date()
      };
    },

    computed: {
      hours: time => time.getHours(),
      minutes: time => time.getMinutes(),
      seconds: time => time.getSeconds()
    }
  };
</script>

# 帮助函数

把你需要的函数放到 helpers 里面那就可以在模板中使用了,但是必须是纯函数。

<p>
  The time is
  <strong>{{hours}}:{{leftPad(minutes, 2, '0')}}:{{leftPad(seconds, 2, '0')}}</strong>
</p>

<script>

  function leftPad(str, len, ch) {
      str = str + '';

      len = len - str.length;
      if (len <= 0) return str;

      if (!ch && ch !== 0) ch = ' ';
      ch = ch + '';

      return ch.repeat(len) + str;
  };
    
  export default {
    helpers: {
      leftPad
    },

    onrender () {
      this.interval = setInterval( () => {
        this.set({ time: new Date() });
      }, 1000 );
    },

    onteardown () {
      clearInterval( this.interval );
    },

    data () {
      return {
        time: new Date()
      };
    },

    computed: {
      hours: time => time.getHours(),
      minutes: time => time.getMinutes(),
      seconds: time => time.getSeconds()
    }
  };
</script>

# 组件方法

<button on:click='say("hello")'>say hello!</button>

<script>
  export default {
    methods: {
      say ( message ) {
        alert( message ); 
      }
    }
  };
</script>

# 组件事件

记得在你的 data 上添加 done 变量
node 就是当前的 dom 节点,callback 就是我要执行的代码,自行打印一下就很清楚了。

<button on:longpress='set({ done: true })'>click and hold</button>

{{#if done}}
  <p>clicked and held</p>
{{/if}}

<script>
  export default {
    events: {
      longpress ( node, callback ) {
        function onmousedown ( event ) {
          const timeout = setTimeout( () => callback( event ), 1000 );

          function cancel () {
            clearTimeout( timeout );
            node.removeEventListener( 'mouseup', cancel, false );
          }

          node.addEventListener( 'mouseup', cancel, false );
        }

        node.addEventListener( 'mousedown', onmousedown, false );

        return {
          teardown () {
            node.removeEventListener( 'mousedown', onmousedown, false );
          }
        };
      }
    }
  };
</script>

# 子组件

此小节注意大小写,组件用大写,别弄错了。

  • 创建一个新的文件 Widget.html
<div class="widget-container">
    <h1>hei! Widget</h1>
</div>
  • 编译一下
svelte compile -f iife -i Widget.html -o Widget.js
  • 给 HelloWrold 添加一下代码
import Widget from './Widget.html';

export default {
    components: {
        Widget
    },
    ......
}
  • 编译一下 HelloWorld.html
svelte compile -f iife HelloWorld.html > HelloWorld.js
  • 在给 index.html 修改一下代码
    Widget 由于被 HelloWorld 依赖所以需要先加载
    <script src="./Widget.js"></script>
    <script src="./HelloWorld.js"></script>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容