# 视频教程
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>