surround with emmet

image.png
image.pngimage.png

加入右箭头icon

Icon组件已经封装好,只要传svg文件名就行
衣食住行用span包起来,是经验

  1. <template>
  2. <Layout>
  3. <ul>
  4. <li><span></span> <Icon name="right" /></li>
  5. <li><span></span> <Icon name="right" /></li>
  6. <li><span></span> <Icon name="right" /></li>
  7. <li><span></span> <Icon name="right" /></li>
  8. </ul>
  9. </Layout>
  10. </template>

css

  1. <style lang="scss" scoped>
  2. .tags {
  3. background-color: white;
  4. font-size: 16px;
  5. padding-left: 16px;
  6. > li {
  7. display: flex;
  8. align-items: center;
  9. justify-content: space-between;
  10. border-bottom: 1px solid #e6e6e6;
  11. min-height: 44px;
  12. /* Icon 样式设置, 用.icon选择器也行*/
  13. svg {
  14. width: 18px;
  15. height: 18px;
  16. color: #666;
  17. margin-right: 16px;
  18. }
  19. }
  20. }
  21. .createTag {
  22. border: none;
  23. border-radius: 4px;
  24. background: #767676;
  25. padding: 0 16px;
  26. height: 40px;
  27. color: white;
  28. /* &只是代表外面的选择器,并不代表父子元素 */
  29. &-wrapper {
  30. padding-top: 16px;
  31. margin-top: 44-16px;
  32. text-align: center;
  33. }
  34. }
  35. </style>

新建标签

解决tags存储问题,需要一个tagsModel, 新建一个models文件夹,把recordListModel.ts和tagListModel.ts都放里面
image.png
从本地localStorage获取tags

  1. <template>
  2. <Layout>
  3. <ul class="tags">
  4. <li v-for="tag in tags" :key="tag">
  5. <span>{{tag}}</span>
  6. <Icon name="right" />
  7. </li>
  8. </ul>
  9. -- snip --
  10. </template>
  11. <script lang="ts">
  12. -- snip --
  13. @Component
  14. export default class Labels extends Vue {
  15. tags = tagListModel.fetch()
  16. }
  17. </script>

将create标签函数写进tagListModel.ts
并把数据data也放在tagListModel.ts里

  1. const localStorageItemName = 'tagList';
  2. type TagListModel = {
  3. data: string[],
  4. fetch: () => string[],
  5. create: (name: string) => string,
  6. save: () => void
  7. }
  8. const tagListModel: TagListModel = {
  9. data: [],
  10. fetch() {
  11. this.data = JSON.parse(window.localStorage.getItem(localStorageItemName) || '[]');
  12. return this.data;
  13. },
  14. create(name) {
  15. this.data.push(name);
  16. this.save();
  17. return name;
  18. },
  19. save() {
  20. window.localStorage.setItem(localStorageItemName, JSON.stringify(this.data));
  21. }
  22. };
  23. export default tagListModel;

tags页面不需要管data

  1. <script lang="ts">
  2. -- snip --
  3. tagListModel.fetch();
  4. @Component
  5. export default class Labels extends Vue {
  6. tags = tagListModel.data;
  7. createTag() {
  8. const name = window.prompt('请输入标签名');
  9. if (name) {
  10. tagListModel.create(name);
  11. }
  12. }
  13. }
  14. </script>

错误处理
方法一:throw new Error()和 try…catch捕获错误

  1. create(name) {
  2. if (this.data.indexOf(name) >= 0) {throw new Error('duplicated')}
  3. this.data.push(name);
  4. this.save();
  5. return name;
  6. },
  1. createTag() {
  2. const name = window.prompt('请输入标签名');
  3. if (name) {
  4. try{
  5. tagListModel.create(name);
  6. }catch(error){
  7. console.log(error.message)
  8. if (error.message === 'duplicated') {
  9. window.alert('标签名重复')
  10. }
  11. }
  12. }
  13. }

方法二: 直接返回字符串
ts: 如果函数只返回几个有限的字符串,声明返回类型时,使用联合类型,当返回值不属于列举的字符串时,将报错

  1. const localStorageItemName = 'tagList';
  2. type TagListModel = {
  3. -- snip --
  4. create: (name: string) => 'success' | 'duplicated', // 联合类型
  5. -- snip --
  6. }
  7. const tagListModel: TagListModel = {
  8. -- snip --
  9. create(name) {
  10. if (this.data.indexOf(name) >= 0) {return 'duplicated'}
  11. this.data.push(name);
  12. this.save();
  13. return 'success';
  14. },
  15. -- snip --
  16. };
  1. createTag() {
  2. const name = window.prompt('请输入标签名');
  3. if (name) {
  4. const message = tagListModel.create(name);
  5. if (message === 'duplicated') {
  6. window.alert('标签名已存在');
  7. } else if (message === 'success') {
  8. window.alert('创建成功');
  9. }
  10. }
  11. }