基于Vue搭建Shiny项目

组学之美 2022年02月18日 2,311次浏览

1. 前言

Shiny在构建UI界面时,默认使用内置的Bootstrap v3.0框架,配合shinyjs R包和 javascript脚本可以满足绝大多数APP项目的构建。但基于这种方式开发的shiny APP, 往往给人一种千篇一律的感觉,UI界面不够引人入胜,不适用构建大型复杂的项目。现如今,ReactVue等前端框架被广泛应用在各种大型APP的开发中。使用这些先进的前端框架有着诸多优势,且目前针对这些前端框架有很多现成可用的成熟组件(比如 element-ui, iView ),方便快速的开发漂亮的we b APP。这篇文章旨在整合前端框架与Shiny 开发,通过简单的案例,管窥更加现代化的Shiny APP的开发过程。

关键词

  • Shiny
  • Vue
  • element-ui
  • packer
  • leprechaun

2. 开发环境

# OS
MacOS Monterey Version 12.2.1

# IDE
Rstudio

# 依赖的软件
最新版Node.js
vue
elememt-ui

# 依赖的R包
shiny
pakcer
leprechaun
...

3. 搭建项目目录

3.1 创建项目

usethis::create_package("shinyApps/vueShiny")
leprechaun::scaffold()
# leprechaun shiny框架更加简洁轻便
# 也可选用golem框架 packer::scaffold_golem(vue = TRUE)
packer::scaffold_leprechaun(vue = TRUE)

3.2 修改根目录package.json

"devDependencies": {
    "@babel/core": "^7.17.4",
    "@babel/preset-env": "^7.16.11",
    "babel-loader": "^8.2.3",
    "css-loader": "^6.6.0",
    //添加style-loader
    "style-loader": "^2.0.0",
    //降低vue版本
    "vue": "^2.6.0",
    //降低vue-loader版本
    "vue-loader": "^15.0.0",
    "vue-template-compiler": "^2.6.14",
    //添加vue-style-loader
    "vue-style-loader": "^4.1.2",
    "webpack": "^5.69.0",
    "webpack-cli": "^4.9.2",
    "webpack-merge": "^5.8.0"
  },

更新软件版本

system("npm install")

3.3修改srcjs/config/loaders.json

[
  {
    "test": "\\.(js|jsx)$",
    "use": [
      "babel-loader"
    ],
    "exclude": "/node_modules/"
  },
  {
    "test": "\\.vue$",
    "use": [
      "vue-loader"
    ],
    "exclude": "/node_modules/"
  },
  {
    "test": "\\.css$",
    "use": [
      "vue-style-loader",
      "style-loader",
      "css-loader"
    ]
  }
]

3.4 运行vue 模版

# packer::bundle()
# 修改R/ui.R

ui <- function(req){
  fluidPage(
    h1("vueShiny Demo"),
    tagList(
      vueCDN(),
      div(id = "app"),
      tags$script(src = "vueShiny-0.0.0.9000/assets/index.js")
    )
  )
}

运行vue模版

leprechaun::build()
devtools::document()
devtools::load_all()
run()

4. 应用element-ui 组建开发shiny APP

4.1 安装element-ui

packer::npm_install("element-ui", scope = "prod")

4.2 使用element-ui开发UI界面

修改srcjs/index.js

// srcjs/index.js
import Vue from 'vue';
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import App from './Home.vue';

Vue.use(ElementUI);

new Vue({
  el: '#app',
  render: h => h(App)
});

修改srcjs/Home.vue

// srcjs/Home.vue

<template>
  <el-form ref="form" :model="form" label-width="120px">
  <el-form-item label="Activity name">
    <el-input v-model="form.name"></el-input>
  </el-form-item>
  <el-form-item label="Activity zone">
    <el-select v-model="form.region" placeholder="please select your zone">
      <el-option label="Zone one" value="shanghai"></el-option>
      <el-option label="Zone two" value="beijing"></el-option>
    </el-select>
  </el-form-item>
  <el-form-item label="Activity time">
    <el-col :span="11">
      <el-date-picker type="date" placeholder="Pick a date" v-model="form.date1" style="width: 100%;"></el-date-picker>
    </el-col>
    <el-col class="line" :span="2">-</el-col>
    <el-col :span="11">
      <el-time-picker placeholder="Pick a time" v-model="form.date2" style="width: 100%;"></el-time-picker>
    </el-col>
  </el-form-item>
  <el-form-item label="Instant delivery">
    <el-switch v-model="form.delivery"></el-switch>
  </el-form-item>
  <el-form-item label="Activity type">
    <el-checkbox-group v-model="form.type">
      <el-checkbox label="Online activities" name="type"></el-checkbox>
      <el-checkbox label="Promotion activities" name="type"></el-checkbox>
      <el-checkbox label="Offline activities" name="type"></el-checkbox>
      <el-checkbox label="Simple brand exposure" name="type"></el-checkbox>
    </el-checkbox-group>
  </el-form-item>
  <el-form-item label="Resources">
    <el-radio-group v-model="form.resource">
      <el-radio label="Sponsor"></el-radio>
      <el-radio label="Venue"></el-radio>
    </el-radio-group>
  </el-form-item>
  <el-form-item label="Activity form">
    <el-input type="textarea" v-model="form.desc"></el-input>
  </el-form-item>
  <el-form-item>
    <el-button type="primary" @click="onSubmit">Create</el-button>
    <el-button>Cancel</el-button>
  </el-form-item>
</el-form>
</template>

<script>
  export default {
    data() {
      return {
        form: {
          name: '',
          region: '',
          date1: '',
          date2: '',
          delivery: false,
          type: [],
          resource: '',
          desc: ''
        }
      }
    },
    methods: {
      onSubmit() {
        console.log('submit!');
      }
    }
  }
</script>


<style scoped>

</style>

运行之后,如下图所示:

到此,在shiny项目中使用element-ui已经有了一个雏形,接下来,还需要整合shiny与vue。

5. 整合Shiny与Vue开发

  •  待实现

https://shiny.rstudio.com/gallery/kmeans-example.html

6. 参考文档