大前端 -vue - vue3.0 - Composition API

Composition API

  • createApp:创建一个vue对象。
  • setup: composition api的入口。
  • reactive: 把一个对象变成响应式对象,并且把该对象的嵌套属性也变成响应式对象。

vue3.0 响应式对象不能解构

案例:获取鼠标位置

import { createApp, reactive } from 'vue'
  // setup:第一个参数:props
  // 第二个参数:context,attrs,emit,slots
  createApp({
    setup() {
      // 此时声明的变量不是响应式的。加了reactive之后把对象变成响应式对象。
      const position = reactive({
        x: 0,
        y: 0,
      })
      return {
        position
      }
    },
    mounted() {
      // 在生命周期的钩子函数中使用position:this.position
      this.position.x = 100
    }
})
生命周期钩子函数
  • 如何在setup中使用生命周期钩子函数?
    on + 生命周期第一个字母大写:
    请添加图片描述
<div id="app"></div>
  <script type="module">
    import { createApp, reactive, onMounted,unonMounted } from 'vue'

    function useMousePosition() {
      const position = reactive({
          x: 0,
          y: 0,
        })
      // 封装的函数,用来更新x,y的值
      const update = (e) => {
        position.x = e.pageX
        position.y = e.pageY
      }
      onMounted(() => {
        window.addEventListener('mousemove', update)
      })
      unonMounted(() => {
        window.addEventListener('mousemove', update)
      })
      return position
    }
    createApp({
      setup() {
        const position = useMousePosition()
        return {
          position
        }
      },
    })
    app.mount('#app')
  </script>

reactive, toRefs, ref 创建响应式数据

toRefs:传入的是代理的对象。 把传入的代理的对象的所有属性都变成响应式对象。toRefs返回的对象解构的变量是响应式的。

function useMousePosition() {
      const position = reactive({
          x: 0,
          y: 0,
        })
      // 封装的函数,用来更新x,y的值
      const update = (e) => {
        position.x = e.pageX
        position.y = e.pageY
      }
      onMounted(() => {
        window.addEventListener('mousemove', update)
      })
      unonMounted(() => {
        window.addEventListener('mousemove', update)
      })
      return toRefs(position)
    }

ref:把普通数据转成响应式数据对象。
ref内部做了什么?传入的参数如果是对象,那么内部调用的就是reactive,如果是基本类型的值,那么内部会创建一个具有value属性的对象,该对象的value属性具有gutter和setter,在gutter搜集依赖,在setter中触发更新。

 function useCount() {
      // ref:基本数据转成响应式对象,它的值是value
      const count = ref(0)
      return {
        count,
        increase: () => {
          count.value ++
        }
      }
    }
    createApp({
      setup() {
        return {
          ...useCount()
        }
      }
    })

computed(计算属性)

可以缓存计算的结果,当属性发生变化时再重新计算。
第一种用法:

computed(()=>count.value + 1)

第2种用法:

const count = ref(1)
const plusOne = computed({
	get: () => count.value + 1,
	set: () => {
		count.value = val - 1
	}
})

案例:

import {computed} from 'vue'
{{activeCount}}
<div @click="plus">+ </div>

const data = [
	{ text: '看书', computed: false },
	{ text: '敲代码', computed: true },
	{ text: '约会', computed: false },
]

createApp({
	setup() {
		const todos = reactive(data)
		const activeCount = computed(() => {
			return todos.filter(item => !item.computed).length
		})
		return { 
			activeCount,
			plus: () => {
				todos.push({text: '开会', computed: false})
			}
		}
	}
})

watch

创建监听器:监听响应式数据的变化,然后执行相应的回调函数。
watch的三个参数:
请添加图片描述

deep:深入监听。
immediate:立即执行。

案例:

createApp() {
	setup() {
		const question = ref('')
		const answer = ref('')
		watch(question, async(newValue, oldValue) {
			const response = await fetch('https://www.yesno.wtf/api')
			const data = await response.json()
			answer.value = data.value
		})
	return {question, answer}	
	}
}

watchEffect

watchEffect:是watch函数的简化版本,也用来监听数据的变化。
接收一个函数作为参数,监听函数内响应式数据的变化。
watchEffect:返回值是:取消函数的监听。

案例:

createApp() {
	setup() {
		const count = ref(0)
		const stop = watchEffect(() => {
			console.log(count.value)
		})
	return {count, stop, increate:() => {count.value++}}	
	}
}

todolist案例:(待办事项清单)

添加待办事项

vue-cli:4.5版本以上
vue:v3.0以上

<input
   class="new-todo"
    placeholder="What needs to be done?"
    autocomplete="off"
    autofocus
    v-model="input"
    @keyup.enter="addTodo"
    >

<ul class="todo-list">
   <li
     v-for="todo in todos"
     :key="todo"
    
   >
     <div class="view">
     	 <!-- 完成代办事情 -->
       <input class="toggle" type="checkbox" v-model="todo.completed"> 
       <label>{{ todo.text }}</label>
       <!-- 删除 -->
       <button class="destroy" @click=""></button>
     </div>
     <!-- 编辑 -->
     <input
       class="edit"
       type="text"
       v-model="todo.text"
       >
   </li>
 </ul>

<script>
import './essets/index.css'
import { ref } from 'vue'
 
// 拆分代码,方便后续维护

// 1。添加代办事项
const useAdd = todos => {
  const input = ref('')

  const addTodo = (todos) => {
    const text = input.value && input.value.trim() //input.value: 获取input的值
    if (text.length === 0) return
    todos.value.unshift({ text, complated: false })
    // 添加完成,清空文本框
    input.value = ''
  }

  return {
    input,
    addTodo,
  }
}


export default {
  name: 'App',
  setup() {
    const todos = ref([])

    return {
      todos,
      ...useAdd(todos),
    }
  }
}

</script>
删除待办事项
<input
   class="new-todo"
    placeholder="What needs to be done?"
    autocomplete="off"
    autofocus
    v-model="input"
    @keyup.enter="addTodo"
    >

<ul class="todo-list">
   <li
     v-for="todo in todos"
     :key="todo"
    
   >
     <div class="view">
     	 <!-- 完成代办事情 -->
       <input class="toggle" type="checkbox" v-model="todo.completed"> 
       <label>{{ todo.text }}</label>
       <!-- 删除 -->
 +      <button class="destroy" @click="remove(todo)"></button>
     </div>
     <!-- 编辑 -->
     <input
       class="edit"
       type="text"
       v-model="todo.text"
       >
   </li>
 </ul>


<script>
// 2.删除代办事项: 注意传递的参数,
const  useRemove = (todos) => {
  const remove = (todo) => {
    const index = todos.value.indexOf(todo)
    todos.value.splice(index, 1)
  }
  return {
    remove
  }
}

export default {
  name: 'App',
  setup() {
    const todos = ref([])


    return {
      todos,
      ...useRemove(todos),
    }
  }
}
</script>
编辑待办事项
<section class="main" v-show="count">
      <input id="toggle-all" class="toggle-all"  type="checkbox">
      <label for="toggle-all">Mark all as complete</label>
      <ul class="todo-list">
        <!-- editing:是否是编辑状态  -->
        <li
          v-for="todo in filteredTodos"
          :key="todo"
          :class="{ editing: todo === editingTodo, completed: todo.completed }"
        >
          <div class="view">
            <!-- 完成代办事情 -->
            <input class="toggle" type="checkbox">
            <!-- dblclick 双击事件 -->
            <label @dblclick="editTodo(todo)">{{ todo.text }}</label>
            <!-- 删除 -->
            <button class="destroy" @click="remove(todo)"></button> 
          </div>
          <!--
            @keyup.enter:按下回车,修改数据
            @blur:失去焦点,完成编辑
            @keyup.esc:取消编辑
            v-editing-focus="todo === editingTodo":获取焦点
            -->
          <input
            class="edit"
            type="text"
            v-editing-focus="todo === editingTodo"
            v-model="todo.text"
            @keyup.enter="doneEdit(todo)"
            @blur="doneEdit(todo)"
            @keyup.esc="cancelEdit(todo)"
            >
        </li>
      </ul>
    </section>


<script>

// 3.编辑代办事项  1.双击显示文本框(input) 2.按enter/input失去焦点,修改数据   3.按esc可以取消编辑   4.清空文本框的内容,按enter,删除  5.显示input的时候获取焦点

+ const useEdit = (remove) => {

  // 1.双击显示文本框(input)
  let beforeEditingText = '' // 编辑之前的文本
  const editingTodo = ref(null) // 编辑的数据
  const editingTodo = todo => {
    beforeEditingText = todo.text
    editingTodo.value = todo
  }

  // 2.按enter/input失去焦点,修改数据 
  const doneEdit = (todo) => {
    if (!editingTodo.value) return

    todo.text = todo.text.trim()

    todo.text || remove(todo)
    editingTodo.value = ''
  }

  // 按esc可以取消编辑
  const calcelEdit = (todo) => {
    editingTodo.value = null
    todo.text = beforeEditingText
  }

  return {
    editingTodo,
    editingTodo,
    doneEdit, 
    calcelEdit
  }

}

export default {
  name: 'App',
  setup() {
    const todos = ref([])

+    const remove = useRemove(todos)

    return {
      todos,
+      ...useEdit(remove)
    }
  }
}

</script>
编辑待办事项-编辑文本框获取焦点

自定义指令:编辑文本框获取焦点(v-editing-focus)
参数:boolean:true,正在编辑的文本框
请添加图片描述
请添加图片描述

<script>

export default {
  name: 'App',
+  directives: {
    editingFocus: (el, binding) => {
      binding.value && el.focus()
    }
  }
}
</script>

使用:

<input
   class="edit"
   type="text"
+   v-editing-focus="todo === editingTodo"
   v-model="todo.text"
   >
改变待办事项完成状态

```javascript
<section class="main" v-show="count">
 +     <input id="toggle-all" class="toggle-all" v-model="allDone" type="checkbox">
      <label for="toggle-all">Mark all as complete</label>
      <ul class="todo-list">
        <!-- editing:是否是编辑状态, completed:当前代办事项是否完成  -->
        <li
          v-for="todo in filteredTodos"
          :key="todo"
          :class="{ editing: todo === editingTodo, completed: todo.completed }"
        >
          <div class="view">
            <!-- 完成代办事情 -->
  +          <input class="toggle" type="checkbox" v-model="todo.completed">
            <!-- dblclick 双击事件 -->
            <label @dblclick="editTodo(todo)">{{ todo.text }}</label>
            <!-- 删除 -->
            <button class="destroy" @click="remove(todo)"></button> 
          </div>
          <!--
            @keyup.enter:按下回车,修改数据
            @blur:失去焦点,完成编辑
            @keyup.esc:取消编辑
            v-editing-focus="todo === editingTodo":获取焦点
            -->
          <input
            class="edit"
            type="text"
            v-editing-focus="todo === editingTodo"
            v-model="todo.text"
            @keyup.enter="doneEdit(todo)"
            @blur="doneEdit(todo)"
            @keyup.esc="cancelEdit(todo)"
            >
        </li>
      </ul>
    </section>

<script>
	
// 4.切换代办项完成状态
const useFilter = todos => {
  const allDone = computed({
    get() {
      return !todos.value.filter((todo) => todo.completed).length
    },
    set(value) {
      todos.value.forEach(todo => {
        todo.complated = value
      });
    }
  })
  return {
    allDone
  }
}
</script>


export default {
  name: 'App',
  setup() {
    const todos = ref([])


    return {
      todos,
      ...useFilter(todos)
    }
  }
}
切换代办事项状态
<footer class="footer" v-show="count">  
<span class="todo-count">
   <strong>1</strong> item left
 </span>
 <ul class="filters">
    <li><a href="#/all">All</a></li>
    <li><a href="#/active">Active</a></li>
    <li><a href="#/completed">Completed</a></li>
  </ul>
  <button class="clear-completed" >
    Clear completed
  </button>
</footer>


// 4. 切换待办项完成状态
const useFilter = todos => {
  const allDone = computed({
    get () {
      return !todos.value.filter(todo => !todo.completed).length
    },
    set (value) {
      todos.value.forEach(todo => {
        todo.completed = value
      })
    }
  })

+  const filter = {
    all: list => list, // 所有的数据
    active: list => list.filter(todo => !todo.completed), // 未完成事项
    completed: list => list.filter(todo => todo.completed) // 已经过完成的代办事项
  }
  // 事项类型,初始值为all,
+  const type = ref('all')
+  const filteredTodos = computed(() => filter[type.value](todos.value)) // 过滤之后的数据
+  const count = computed(() => todos.value.length)

  const onHashChange = () => {
    // 获取路径中#之后的字符
    const hash = window.location.hash.replace('#/', '')
    if (filter[hash]) {
      type.value = hash
    } else {
      // 加载所有的数据
      type.value = 'all'
      // 地址为空
      window.location.hash = ''
    }
  }
  // 注册 hashchange事件
+  onMounted(() => {
    window.addEventListener('hashchange', onHashChange)
    // 调用onHashChange事件加载数据
    onHashChange()
  })
  // 移除 hashchange事件
+  onUnmounted(() => {
    window.removeEventListener('hashchange', onHashChange)
  })

  return {
    allDone,
    count,
    filteredTodos,
  }
}
其它
<footer class="footer" v-show="count">
 <span class="todo-count">
+   <strong>{{ remainingCount }}</strong> {{ remainingCount > 1 ? 'items' : 'item' }} left
  </span>
  <ul class="filters">
    <li><a href="#/all">All</a></li>
    <li><a href="#/active">Active</a></li>
    <li><a href="#/completed">Completed</a></li>
  </ul>
+    <button class="clear-completed" @click="removeCompleted" v-show="count > remainingCount">
    	Clear completed
 	 </button>
</footer>




// 2. 删除待办事项
const useRemove = todos => {
  const remove = todo => {
    const index = todos.value.indexOf(todo)
    todos.value.splice(index, 1)
  }

  // 删除已完成的代办事项
+  const removeCompleted = () => {
    todos.value = todos.value.filter(todo => !todo.completed)
  }
  return {
    remove,
    removeCompleted
  }
}


// 4. 切换待办项完成状态
const useFilter = todos => {
  const allDone = computed({
    get () {
      return !todos.value.filter(todo => !todo.completed).length
    },
    set (value) {
      todos.value.forEach(todo => {
        todo.completed = value
      })
    }
  })

  const filter = {
    all: list => list, // 所有的数据
    active: list => list.filter(todo => !todo.completed), // 未完成事项
    completed: list => list.filter(todo => todo.completed) // 已经过完成的代办事项
  }
  // 事项类型,初始值为all,
  const type = ref('all')
  const filteredTodos = computed(() => filter[type.value](todos.value)) // 过滤之后的数据
+  const remainingCount = computed(() => filter.active(todos.value).length) // 显示未完成代办事项的的个数
  const count = computed(() => todos.value.length)

  const onHashChange = () => {
    // 获取路径中#之后的字符
    const hash = window.location.hash.replace('#/', '')
    if (filter[hash]) {
      type.value = hash
    } else {
      // 加载所有的数据
      type.value = 'all'
      // 地址为空
      window.location.hash = ''
    }
  }
  // 注册 hashchange事件
  onMounted(() => {
    window.addEventListener('hashchange', onHashChange)
    // 调用onHashChange事件加载数据
    onHashChange()
  })
  // 移除 hashchange事件
  onUnmounted(() => {
    window.removeEventListener('hashchange', onHashChange)
  })

  return {
    allDone,
    count,
    filteredTodos,
+    remainingCount
  }
}

存储代办事项

数据存储到localStorage中

utils/useLocalStorage.js

// 字符串转换成对象
function parse (str) {
  let value // value转换之后的结果
  try {
    value = JSON.parse(str)
  } catch {
    value = null
  }
  return value
}
// 对象转为字符串
function stringify (obj) {
  let value // value转换之后的结果
  try {
    value = JSON.stringify(obj)
  } catch {
    value = null
  }
  return value
}

export default function useLocalStorage () {
  function setItem (key, value) {
    value = stringify(value)
    window.localStorage.setItem(key, value)
  }

  function getItem (key) {
    let value = window.localStorage.getItem(key)
    if (value) {
      value = parse(value)
    }
    return value
  }

  return {
    setItem,
    getItem
  }
}
import useLocalStorage from './utils/useLocalStorage'

const storage = useLocalStorage()
<script>
// 5. 存储待办事项
const useStorage = () => {
  const KEY = 'TODOKEYS'
  const todos = ref(storage.getItem(KEY) || [])
  //watchEffect: 可以监听到数据的变化
  watchEffect(() => {
    storage.setItem(KEY, todos.value)
  })
  return todos
}
export default {
  name: 'App',
  setup () {
  	const todos = useStorage()
  }
}
</script>
### 回答1: vue-element-admin 是基于 Vue.js 和 Element UI 的开源后台管理系统,它主要面向企业级应用,提供了完善的组件、插件和网站模板,能够快速搭建一个可靠、稳定、易用的后台管理系统。 而 Vue.js 3.0 是 Vue.js 的下一个重要版本,它将带来很多新特性和改进,包括提高性能、优化开发体验和支持更多场景。Vue 3.0 的核心是使用 Proxy 对象重建了响应式系统,提高了性能;另外还加强了其类型检查、静态渲染和模板编译等方面。 对于 vue-element-admin 和 Vue.js 3.0 的关系,可以看到 vue-element-admin 还没有直接升级到 Vue.js 3.0,但是作为一个基于 Vue.js 的项目,vue-element-admin 可以逐渐使用 Vue.js 3.0 的优化和新特性,使其更加强大、高效、易用。同时,一些开源社区也在积极地为 vue-element-admin 编写适配 Vue.js 3.0 的插件和组件,为后台管理系统的开发提供更多的选择和便利。 ### 回答2: vue-element-admin是一个基于Vue.js和ElementUI的后台管理系统模板。它提供了丰富的功能和组件,可用于快速开发各种类型的后台管理系统。 vue3.0Vue.js的最新版本,其性能和体验相比之前的版本都有很大的提升。它引入了Composition API,使得开发者可以更好地组织和复用代码。此外,Vue3.0还提供了更好的TypeScript支持和更快的渲染速度。 结合使用vue-element-admin和vue3.0可以使得后台管理系统的开发更加高效和愉悦。vue-element-admin提供了大量的组件和功能,以及良好的UI设计,使得开发者可以将精力更多地放在业务逻辑的实现上。使用vue3.0Composition API可以使得代码更加清晰明了,容易维护和扩展。 综上所述,vue-element-admin和vue3.0是非常有价值的前端开发工具,它们可以使得开发者快速搭建后台管理系统并提高开发效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值