完全可以。
1、另一方面,Vue 完全有能力驱动采用单文件组件和 Vue 生态系统支持的库开发的复杂单页应用,实现PC端单页式的前端开发。
2、PC端网站在不需要优先考虑SEO和首屏渲染时间时,单页式在用户体验和开发体验(开发效率)上是完胜多页式的。
3、vue.js作为主流框架之一,同样支持SSR,vue.js的PC端网站开发时服务端渲染编译比较慢,使用用单页式效率更高。
扩展资料:
主流框架Vue.js与angularjs的开发区别:
一、相同点:
都支持指令:内置指令和自定义指令。
都支持过滤器:内置过滤器和自定义过滤器。
都支持双向数据绑定。
都不支持低端浏览器。
二、不同点:
1、AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。
2、在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
3、Vue.js使用基于依赖追踪的观察并且使用异步队列更新。所有的数据都是独立触发的。对于庞大的应用来说,这个优化差异还是比较明显的。
参考资料:vue.js官网-介绍-Vue.js
按照上面我们列出来的功能模块,我们在 Vuex/ 下面建立一个 store.js 文件import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 需要维护的状态
const state = {
notes: [],
activeNote: {},
show: ''
}
const mutations = {
// 初始化 state
INIT_STORE(state, data) {
state.notes = data.notes,
state.show = data.show
state.activeNote = data.activeNote
},
// 新增笔记
NEW_NOTE(state) {
var newNote = {
id: +new Date(),
title: '',
content: '',
favorite: false
}
state.notes.push(newNote)
state.activeNote = newNote
},
// 修改笔记
EDIT_NOTE(state, note) {
state.activeNote = note
// 修改原始数据
for (var i = 0i <state.notes.lengthi++) {
if(state.notes[i].id === note.id){
state.notes[i] = note
break
}
}
},
// 删除笔记
DELETE_NOTE(state) {
state.notes.$remove(state.activeNote)
state.activeNote = state.notes[0] || {}
},
// 切换笔记的收藏与取消收藏
TOGGLE_FAVORITE(state) {
state.activeNote.favorite = !state.activeNote.favorite
},
// 切换显示数据列表类型:全部 or 收藏
SET_SHOW_ALL(state, show){
state.show = show
// 切换数据展示,需要同步更新 activeNote
if(show === 'favorite'){
state.activeNote = state.notes.filter(note =>note.favorite)[0] || {}
}else{
state.activeNote = state.notes[0] || {}
}
},
// 设置当前激活的笔记
SET_ACTIVE_NOTE(state, note) {
state.activeNote = note
}
}
export default new Vuex.Store({
state,
mutations
})
创建 Vuex Actions
在 Vuex/ 下面建立一个 action.js,用来给组件使用的函数
function makeAction(type) {
return ({ dispatch }, ...args) =>dispatch(type, ...args)
}
const initNote = {
id: +new Date(),
title: '我的笔记',
content: '第一篇笔记内容',
favorite: false
}
// 模拟初始化数据
const initData = {
show: 'all',
notes: [initNote],
activeNote: initNote
}
export const initStore = ({ dispatch }) =>{
dispatch('INIT_STORE', initData)
}
// 更新当前activeNote对象
export const updateActiveNote = makeAction('SET_ACTIVE_NOTE')
// 添加一个note对象
export const newNote = makeAction('NEW_NOTE')
// 删除一个note对象
export const deleteNote = makeAction('DELETE_NOTE')
export const toggleFavorite = makeAction('TOGGLE_FAVORITE')
export const editNote = makeAction('EDIT_NOTE')
// 更新列表展示
export const updateShow = makeAction('SET_SHOW_ALL')
创建 Vuex Getters
在 vuex/ 下面建立一个 getter.js 文件,用来从 store 获取数据
// 获取 noteList,这里将会根据 state.show 的状态做数据过滤
export const filteredNotes = (state) =>{
if(state.show === 'all'){
return state.notes || {}
}else if(state.show === 'favorite'){
return state.notes.filter(note =>note.favorite) || {}
}
}
// 获取列表展示状态 : all or favorite
export const show = (state) =>{
return state.show
}
// 获取当前激活 note
export const activeNote = (state) =>{
return state.activeNote
}
以上就是我们 Vuex 的所有逻辑了,在定下了我们需要完成的功能之后,接下来就是只需要在组件中去调用 action 来实现对应的功能了。
路由配置
在这里我们将使用 vue-router 来做路由,引用 bootstrap 样式。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>vuex-notes-app</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
所有的入口逻辑我们都将在 main.js 中编写
main.js
import Vue from 'vue'
import App from './App'
import VueRouter from 'vue-router'
import VueResource from 'vue-resource'
// 路由模块和HTTP模块
Vue.use(VueResource)
Vue.use(VueRouter)
const router = new VueRouter()
router.map({
'/index': {
component: App
}
})
router.redirect({
'*': '/index'
})
router.start(App, '#app')
根组件 App.vue
<template>
<div id="app" class="app">
<toolbar></toolbar>
<notes-list></notes-list>
<editor></editor>
</div>
</template>
<style>
html, #app {
height: 100%
}
body {
margin: 0
padding: 0
border: 0
height: 100%
max-height: 100%
position: relative
}
</style>
<script>
import Toolbar from './components/Toolbar'
import NotesList from './components/NotesList'
import Editor from './components/Editor'
import store from './vuex/store'
import { initStore } from './vuex/actions'
export default {
components: {
Toolbar,
NotesList,
Editor
},
store,
vuex: {
actions: {
initStore
}
},
ready() {
this.initStore()
}
}
</script>
在根组件中引用了三个子组件:Toolbar.vue, NotesList.vue, Editor.vue。
注意:我们在配置里面加入了 vuex 这么一个选项,这里用来将我们 action 里面定义的方法给暴露出来,我们在根组件中只做了一件事情,那就是初始化模拟数据,因此我们在组件生命周期的 ready 阶段调用了 actions 里面的 initStore 来初始化我们的 store 里面的 state
Toolbar.vue
<template>
<div id="toolbar">
<i class="glyphicon logo"><img src="../assets/logo.png" width="30" height="30"></i>
<i @click="newNote" class="glyphicon glyphicon-plus"></i>
<i @click="toggleFavorite" class="glyphicon glyphicon-star" :class="{starred: activeNote.favorite}"></i>
<i @click="deleteNote" class="glyphicon glyphicon-remove"></i>
</div>
</template>
<script>
import { newNote, deleteNote, toggleFavorite } from '../vuex/actions'
import { activeNote } from '../vuex/getters'
export default {
vuex: {
getters: {
activeNote
},
actions: {
newNote,
deleteNote,
toggleFavorite
}
}
}
</script>
<style lang="scss" scoped>
#toolbar{
float: left
width: 80px
height: 100%
background-color: #30414D
color: #767676
padding: 35px 25px 25px 25px
.starred {
color: #F7AE4F
}
i{
font-size: 30px
margin-bottom: 35px
cursor: pointer
opacity: 0.8
transition: opacity 0.5s ease
&:hover{
opacity: 1
}
}
}
</style>
在这里,我们用到了 Vuex 的一个案例就是我们需要知道当前的激活的笔记是否是收藏类别的,如果是,我们需要高亮收藏按钮,那么如何知道呢?那就是通过 vuex 里面的 getters 获取当前激活的笔记对象,判断它的 favorite 是否为 true。
始终牢记一个概念,vuex 中数据是单向的,只能从 store 获取,而我们这个例子中的 activeNote 也是始终都在 store.js 中维护的,这样子就可以给其他组件公用了
// 需要维护的状态
const state = {
notes: [],
activeNote: {},
show: ''
}
NotesList.vue
<template>
<div id="notes-list">
<div id="list-header">
<h2>Notes | heavenru.com</h2>
<div class="btn-group btn-group-justified" role="group">
<!-- all -->
<div class="btn-group" role="group">
<button type="button" class="btn btn-default"
@click="toggleShow('all')"
:class="{active: show === 'all'}">All Notes</button>
</div>
<!-- favorites -->
<div class="btn-group" role="group">
<button type="button" class="btn btn-default"
@click="toggleShow('favorite')"
:class="{active: show === 'favorite'}">Favorites</button>
</div>
</div>
</div>
<!-- 渲染笔记列表 -->
<div class="container">
<div class="list-group">
<a v-for="note in filteredNotes"
class="list-group-item" href="#"
:class="{active: activeNote === note}"
@click="updateActiveNote(note)">
<h4 class="list-group-item-heading">
{{note.title.trim().substring(0,30)}}
</h4>
</a>
</div>
</div>
</div>
</template>
<script>
import { updateActiveNote, updateShow } from '../vuex/actions'
import { show, filteredNotes, activeNote } from '../vuex/getters'
export default {
vuex: {
getters: {
show,
filteredNotes,
activeNote
},
actions: {
updateActiveNote,
updateShow
}
},
methods: {
toggleShow(show) {
this.updateShow(show)
}
}
}
</script>
笔记列表组件,主要有三个操作
渲染笔记
切换渲染笔记
点击列表 title,切换 activeNote
我们通过 getters 中的 filteredNotes 方法获取笔记列表
// 获取 noteList,这里将会根据 state.show 的状态做数据过滤
export const filteredNotes = (state) =>{
if(state.show === 'all'){
return state.notes || {}
}else if(state.show === 'favorite'){
return state.notes.filter(note =>note.favorite) || {}
}
}
可以看到,我们获取的列表是依赖于 state.show 这个状态的。而我们的切换列表操作恰好就是调用 actions 里面的方法来更新 state.show ,这样一来,实现了数据列表的动态刷新,而且我们对树的操作都是通过调用 actions 的方法来实现的。
我们再看,在切换列表的时候,我们还需要动态的更新 activeNote 。 看看我们在 store.js 中是如何做的:
// 切换显示数据列表类型:全部 or 收藏
SET_SHOW_ALL(state, show){
state.show = show
// 切换数据展示,需要同步更新 activeNote
if(show === 'favorite'){
state.activeNote = state.notes.filter(note =>note.favorite)[0] || {}
}else{
state.activeNote = state.notes[0] || {}
}
}
触发这些操作的是我们给两个按钮分别绑定了我们自定义的函数,通过给函数传入不同的参数,然后调用 actions 里面的方法,来实现对数据的过滤,更新。
Editor.vue
<template>
<div id="note-editor">
<div class="form-group">
<input type="text" name="title"
class="title form-control"
placeholder="请输入标题"
@input="updateNote"
v-model="currentNote.title">
<textarea
v-model="currentNote.content" name="content"
class="form-control" row="3" placeholder="请输入正文"
@input="updateNote"></textarea>
</div>
</div>
</template>
<script>
import { editNote } from '../vuex/actions'
import { activeNote } from '../vuex/getters'
export default {
vuex: {
getters: {
activeNote
},
actions: {
editNote
}
},
computed: {
// 通过计算属性得到的一个对象,这样子我们就能愉快的使用 v-model 了
currentNote: activeNote
},
methods: {
// 为什么这么做? 因为在严格模式中不允许直接在模板层面去修改 state 中的值
updateNote() {
this.editNote(this.currentNote)
}
}
}
</script>
在 Editor.vue 组件中,我们需要能够实时的更新当前的 activeNote 组件和列表中对应的我们正在修改的笔记对象的内容。
由于我们前面提到过,在组件中是不允许直接修改 store.js在里面的状态值的,所以在这里的时候,我们通过一个计算属性,将 store 里面的状态值赋值给一个对象,然后在自定义的 updateNotes() 方法中,去调用 action,同时传入 currentNote 对象。
在 store.js 中,我们是这么做的,找到对应的 id 的对象,重新赋值,因为前面提到过,我们的数据是响应式的,在这里进行了改变,对应的视图也将刷新改变,这样一来就实现了实时编辑,实时渲染的功能了。
// 修改笔记
EDIT_NOTE(state, note) {
state.activeNote = note
// 修改原始数据
for (var i = 0i <state.notes.lengthi++) {
if(state.notes[i].id === note.id){
state.notes[i] = note
break
}
}
},